Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
167 commits
Select commit Hold shift + click to select a range
a83880d
Initial commit
i-am-unknown-81514525 Aug 5, 2025
e75c2b2
Test webhook
i-am-unknown-81514525 Aug 5, 2025
ec0bd8f
Update pyproject.toml
i-am-unknown-81514525 Aug 5, 2025
fdcf733
Set author in pyproject.toml
i-am-unknown-81514525 Aug 5, 2025
fc723fe
Update uv.lock and add pylock.toml
i-am-unknown-81514525 Aug 7, 2025
6b5a8a9
Add cmd.md for common command used for development
i-am-unknown-81514525 Aug 7, 2025
90f7b27
Remove samples folder for other package manager
i-am-unknown-81514525 Aug 7, 2025
4901b85
Add new author for new code jam member
i-am-unknown-81514525 Aug 7, 2025
1a22bd6
Add basic setup to include directory to seperate frontend and backend
i-am-unknown-81514525 Aug 8, 2025
2ca59e6
Add pyscript as dependency
i-am-unknown-81514525 Aug 8, 2025
f8d27fc
Add default groups for uv
i-am-unknown-81514525 Aug 8, 2025
5d49a6e
Merge pull request #1 from i-am-unknown-81514525/setup
i-am-unknown-81514525 Aug 8, 2025
6944cee
Update dependency and add crypto module
i-am-unknown-81514525 Aug 8, 2025
20d0caa
Add Ed25519 key generation
i-am-unknown-81514525 Aug 8, 2025
fa2a0ec
Add cryptography itself to also be required dependency
i-am-unknown-81514525 Aug 8, 2025
6f4b885
Optimize the logic
i-am-unknown-81514525 Aug 8, 2025
92bbd83
Fix linting
i-am-unknown-81514525 Aug 8, 2025
f74587f
chore: update doc strings
Harshal6927 Aug 8, 2025
be7857a
Add JWT token generation base on private key
i-am-unknown-81514525 Aug 9, 2025
0ec0509
Reformat and add docstring
i-am-unknown-81514525 Aug 9, 2025
7f922f1
More ruff reformat
i-am-unknown-81514525 Aug 9, 2025
b7c0b8a
Add listening for cookie change from website and redirect
i-am-unknown-81514525 Aug 9, 2025
4c39080
Complete untested captcha_handler
i-am-unknown-81514525 Aug 9, 2025
bb0cf6c
Set require auth cookie to false and delete it after auth
i-am-unknown-81514525 Aug 9, 2025
1d220a5
feat: initial ui
Harshal6927 Aug 9, 2025
e951691
Add captcha script to get challenge
i-am-unknown-81514525 Aug 10, 2025
3356aea
Add create_proxy for get_challenge
i-am-unknown-81514525 Aug 11, 2025
ebc13a5
backend
Harshal6927 Aug 11, 2025
b83e8a4
get endpoint
Harshal6927 Aug 11, 2025
5d8e322
tayvona's error message ui changes
Harshal6927 Aug 11, 2025
4030e51
add submit-challeng endpoint
Harshal6927 Aug 11, 2025
27e495f
connect FE and BE
Harshal6927 Aug 12, 2025
3da4ca2
fix import bug
Harshal6927 Aug 12, 2025
2c280de
update jwt token generation
Harshal6927 Aug 12, 2025
153a407
Update README.md
Harshal6927 Aug 12, 2025
1dab1ae
Merge pull request #13 from i-am-unknown-81514525/harshal-main
Harshal6927 Aug 12, 2025
fa6ab6d
Change .venv script for mac/linux
DragonSenseiGuy Aug 12, 2025
0b5a9d8
Add linter
DragonSenseiGuy Aug 12, 2025
f4071fd
Add . and source to README
DragonSenseiGuy Aug 12, 2025
a7f37bf
Remove Linter
DragonSenseiGuy Aug 12, 2025
f6705c3
Make venv activate runnable by itself
DragonSenseiGuy Aug 12, 2025
0dfd771
Merge pull request #14 from i-am-unknown-81514525/dragon-edits
DragonSenseiGuy Aug 12, 2025
e76ff4a
Add function for js part to submit results
i-am-unknown-81514525 Aug 11, 2025
bc3414a
Fix endpoint name on script
i-am-unknown-81514525 Aug 11, 2025
8d79a9b
Add runner.js to run the user python code
i-am-unknown-81514525 Aug 11, 2025
38ee9e1
Add code to handle the execution in python
i-am-unknown-81514525 Aug 11, 2025
1ef5aaa
Add panel
i-am-unknown-81514525 Aug 12, 2025
3599596
Attempt to add UI with panel
i-am-unknown-81514525 Aug 12, 2025
d96ab48
Basic functional?
i-am-unknown-81514525 Aug 12, 2025
5bb8e36
Add script integrity check
i-am-unknown-81514525 Aug 13, 2025
03ea81d
Update redirect location
i-am-unknown-81514525 Aug 13, 2025
f591ca5
Fix linting
i-am-unknown-81514525 Aug 13, 2025
8222b65
Fix missing on_click handler for submit button
i-am-unknown-81514525 Aug 13, 2025
273ed01
Add fix
i-am-unknown-81514525 Aug 13, 2025
a4ef228
chore: fix captcha.py
Harshal6927 Aug 13, 2025
bf4b87d
Fox GetChallengeResponse schema
i-am-unknown-81514525 Aug 13, 2025
c9cbe61
Folder restructure
i-am-unknown-81514525 Aug 13, 2025
73c7f16
Revert server.backend -> server.demo change as requested
i-am-unknown-81514525 Aug 13, 2025
ff06ed2
Merge pull request #18 from i-am-unknown-81514525/restructure
Harshal6927 Aug 13, 2025
768e7cb
Add
DragonSenseiGuy Aug 13, 2025
7abcdd0
Put it in static path
i-am-unknown-81514525 Aug 13, 2025
93008f1
Update README.md
i-am-unknown-81514525 Aug 13, 2025
c67408c
Fix worker using absolute path causing error
i-am-unknown-81514525 Aug 13, 2025
ee13da6
Use consistent port between litestar and uvicorn
i-am-unknown-81514525 Aug 13, 2025
873e4b3
Remove requirement of API base url
i-am-unknown-81514525 Aug 13, 2025
2bc26d2
Merge pull request #19 from i-am-unknown-81514525/dragon
DragonSenseiGuy Aug 14, 2025
ad298df
Add captcha_handler alternative in js for fast loading
i-am-unknown-81514525 Aug 13, 2025
cd8de15
Basic docker setup
i-am-unknown-81514525 Aug 14, 2025
c3096ac
Fix docker building
i-am-unknown-81514525 Aug 14, 2025
1e26642
Add file serving to demo frontend
i-am-unknown-81514525 Aug 14, 2025
8132b69
Add captcha_handler.py to index.html with micropython
i-am-unknown-81514525 Aug 14, 2025
907c386
fix static files
Harshal6927 Aug 14, 2025
9e211bd
Add build step for domain variation
i-am-unknown-81514525 Aug 14, 2025
920f42f
Rewrite demo index.html, app.js and add API route on demo server to g…
i-am-unknown-81514525 Aug 14, 2025
17291a9
Fix linting
i-am-unknown-81514525 Aug 14, 2025
a075895
Fix typo in README.md
i-am-unknown-81514525 Aug 15, 2025
88d065d
Add question set json
i-am-unknown-81514525 Aug 15, 2025
fdfaffa
Add example question set
i-am-unknown-81514525 Aug 15, 2025
e1084d7
Add more example questions
i-am-unknown-81514525 Aug 15, 2025
2d1a7b1
Somemore idea
i-am-unknown-81514525 Aug 15, 2025
060a954
Add more item for sentence constructor
i-am-unknown-81514525 Aug 15, 2025
5d14cbb
Add more sentence structure
i-am-unknown-81514525 Aug 15, 2025
115dd27
Use sympy for prime calculation instead
i-am-unknown-81514525 Aug 15, 2025
cec0bc2
Add question for fib
i-am-unknown-81514525 Aug 15, 2025
54aa1ec
Limit amount of fibonacci number calculate
i-am-unknown-81514525 Aug 15, 2025
df86d8a
added more values to question set
Ununennium817 Aug 15, 2025
40a0169
Rename continue -> cont
i-am-unknown-81514525 Aug 15, 2025
9f6af68
Add schema
i-am-unknown-81514525 Aug 15, 2025
83de618
Minor update on small issue
i-am-unknown-81514525 Aug 15, 2025
8e79fed
added even more values
Ununennium817 Aug 15, 2025
4ff1303
Update question set
i-am-unknown-81514525 Aug 15, 2025
1b51a2f
Increase question range
i-am-unknown-81514525 Aug 15, 2025
8897909
Update question set
i-am-unknown-81514525 Aug 15, 2025
f407954
Add parser
i-am-unknown-81514525 Aug 15, 2025
26b9959
Make sure base is at the start
i-am-unknown-81514525 Aug 15, 2025
1077de3
Add docstring
i-am-unknown-81514525 Aug 15, 2025
c4a3ac7
Rename to in python
i-am-unknown-81514525 Aug 15, 2025
55702df
Update schema and add key and question state in captcha app state
i-am-unknown-81514525 Aug 15, 2025
857d0db
Add question generation
i-am-unknown-81514525 Aug 15, 2025
1116c47
Fix linting
i-am-unknown-81514525 Aug 15, 2025
03f3c00
Add on_startup
i-am-unknown-81514525 Aug 15, 2025
13ff599
small fixes
Harshal6927 Aug 15, 2025
c7e00aa
small fixes
Harshal6927 Aug 15, 2025
9657526
small fixes
Harshal6927 Aug 15, 2025
446dd2f
Add captcha reset js
i-am-unknown-81514525 Aug 15, 2025
0d70829
Add public key endpoint that the server get on login
i-am-unknown-81514525 Aug 15, 2025
b195f78
Add a validator
i-am-unknown-81514525 Aug 16, 2025
36f8849
add login for website
Harshal6927 Aug 16, 2025
ce61e9b
update func names
Harshal6927 Aug 16, 2025
b9a9731
update readme
Harshal6927 Aug 16, 2025
f8b5c5f
update models
Harshal6927 Aug 16, 2025
7233c5b
website login (#23)
i-am-unknown-81514525 Aug 17, 2025
9fd855f
Attempt to update UI
i-am-unknown-81514525 Aug 16, 2025
aee936e
Fix import issue
i-am-unknown-81514525 Aug 16, 2025
d195fe1
Idk why it need this commit but sure
i-am-unknown-81514525 Aug 16, 2025
2c80e7b
Add logging for error
i-am-unknown-81514525 Aug 16, 2025
58554ab
Add health checking
i-am-unknown-81514525 Aug 16, 2025
f391274
Add timeout for question and strip problematic questions
i-am-unknown-81514525 Aug 16, 2025
3a68114
Add back fib with smaller range and test for <4300 digit
i-am-unknown-81514525 Aug 16, 2025
ee3ef68
Fix lintint
i-am-unknown-81514525 Aug 16, 2025
22e0f27
Add curl in container
i-am-unknown-81514525 Aug 16, 2025
70ef366
Fix mobile compatibility
i-am-unknown-81514525 Aug 16, 2025
a0eb8c3
Fix type issue
i-am-unknown-81514525 Aug 17, 2025
f33106d
Change JWT issuer to client-discoverable endpoint instead
i-am-unknown-81514525 Aug 17, 2025
7530af2
Fix linter and typo
i-am-unknown-81514525 Aug 17, 2025
ee7979f
Add gitignore to test.py
i-am-unknown-81514525 Aug 17, 2025
31156e7
Update so challenge_id can only be used once, whether success on not
i-am-unknown-81514525 Aug 17, 2025
58d94b5
Return apporiate status code for invalid JWT
i-am-unknown-81514525 Aug 17, 2025
cb4caff
Add more error handling for runner.js
i-am-unknown-81514525 Aug 17, 2025
b8c5a42
Update .gitignore
i-am-unknown-81514525 Aug 17, 2025
f1885e6
Some fixes
i-am-unknown-81514525 Aug 17, 2025
414fa2c
Apparently just this
i-am-unknown-81514525 Aug 17, 2025
ec09b5c
Improve question phrasing
i-am-unknown-81514525 Aug 17, 2025
980fb1e
Improve progress bar UI
i-am-unknown-81514525 Aug 17, 2025
af5c677
Fix linting
i-am-unknown-81514525 Aug 17, 2025
e79c2e2
Fix local var error
i-am-unknown-81514525 Aug 17, 2025
1fc3405
Add better traceback for the user
i-am-unknown-81514525 Aug 17, 2025
781ccf7
Revert ignore on 2 server data folder
i-am-unknown-81514525 Aug 17, 2025
f65f4ed
Update captcha.py to accomodate images
fiwam Aug 16, 2025
384b0c1
Update challenge.py
fiwam Aug 16, 2025
9b8fd20
Update captcha.py
fiwam Aug 16, 2025
85442b1
Update challenge.py
fiwam Aug 16, 2025
cb29acd
Fix some part
i-am-unknown-81514525 Aug 17, 2025
250750d
Change to use image
i-am-unknown-81514525 Aug 17, 2025
506eb38
Update width and height settings
i-am-unknown-81514525 Aug 17, 2025
59a8b87
Implement and link image together
i-am-unknown-81514525 Aug 17, 2025
a22260f
Add /logout and /me endpoint
Harshal6927 Aug 17, 2025
59ffacf
Fix JWT prevent static resource load and JWT actually work now
i-am-unknown-81514525 Aug 18, 2025
d5d9a75
use proper auth
Harshal6927 Aug 18, 2025
7cd3f1a
Remove timeout execution
i-am-unknown-81514525 Aug 18, 2025
f408b07
Remove unused multiprocessing, os import
i-am-unknown-81514525 Aug 18, 2025
ab21daa
Fix on http context and Host header missing protocol
i-am-unknown-81514525 Aug 18, 2025
6b3007b
Use consistent local IP
i-am-unknown-81514525 Aug 18, 2025
c8e57e1
Fix /api/auth/me endpoint
i-am-unknown-81514525 Aug 18, 2025
39efae5
Fix inconsistent login button color
i-am-unknown-81514525 Aug 18, 2025
e8f5cd9
Improve phrasing for some question
i-am-unknown-81514525 Aug 18, 2025
876301f
Add font and remove the image write
i-am-unknown-81514525 Aug 18, 2025
a1085de
Fix linting
i-am-unknown-81514525 Aug 18, 2025
427d905
Remove debug file
i-am-unknown-81514525 Aug 18, 2025
31416c1
Fix other pre-commit check
i-am-unknown-81514525 Aug 18, 2025
ae0f53e
Fix inconsistent IP on .env.example
i-am-unknown-81514525 Aug 18, 2025
bf26c13
Use consistent IP
i-am-unknown-81514525 Aug 18, 2025
b2f806e
Change Size of iframe
DragonSenseiGuy Aug 18, 2025
e2a825b
Merge pull request #27 from i-am-unknown-81514525/dragon
DragonSenseiGuy Aug 18, 2025
7ae13b2
Add updated README.md with a video demo
i-am-unknown-81514525 Aug 22, 2025
545d1ec
Remove Gemini Key and Change Spelling error
DragonSenseiGuy Aug 22, 2025
9cea873
Add 'peppy-poppies/' from commit '545d1ecbbe51f1df20adf1c1df159ef0e0e…
janine9vn Sep 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions peppy-poppies/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Secret key used for the demo server to generate JWT for login session. CAPTCHA server don't use this
SECRET_KEY=super-secret-key

# Change if needed (if you follow the instructions in the README, you don't need to change this)
KEY_PATH=./captcha_data # You can add your public/private key with `public.pem` and `private.pem` key. They must be pair of Ed25519 key
CODECAPTCHA_DOMAIN=http://127.0.0.1:8001

FONT_PATH=./captcha_data/JetBrainsMono-Regular.ttf # You can edit to a different font and edit this, the provide font use OFL license, included alongside the font
# OFL font is compatible with MIT

# ======================== Docker only ========================
# This is used for without domain as the service might not be discoverable in the same way. Use http://captcha:8001 in docker
CODECAPTCHA_DOMAIN_INTERNAL=
35 changes: 35 additions & 0 deletions peppy-poppies/.github/workflows/lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# GitHub Action workflow enforcing our code style.

name: Lint

# Trigger the workflow on both push (to the main repository, on the main branch)
# and pull requests (against the main repository, but from any repo, from any branch).
on:
push:
branches:
- main
pull_request:

# Brand new concurrency setting! This ensures that not more than one run can be triggered for the same commit.
# It is useful for pull requests coming from the main repository since both triggers will match.
concurrency: lint-${{ github.sha }}

jobs:
lint:
runs-on: ubuntu-latest

env:
# The Python version your project uses. Feel free to change this if required.
PYTHON_VERSION: "3.12"

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}

- name: Run pre-commit hooks
uses: pre-commit/action@v3.0.1
36 changes: 36 additions & 0 deletions peppy-poppies/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Files generated by the interpreter
__pycache__/
*.py[cod]

# Environment specific
.venv
venv
.env
env

# Unittest reports
.coverage*

# Logs
*.log

# PyEnv version selector
.python-version

# Built objects
*.so
dist/
build/

# IDEs
# PyCharm
.idea/
# VSCode
.vscode/
# MacOS
.DS_Store

*.pem
*.sqlite
!captcha_data/question_set.json
test.py
18 changes: 18 additions & 0 deletions peppy-poppies/.pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Pre-commit configuration.
# See https://github.com/python-discord/code-jam-template/tree/main#pre-commit-run-linting-before-committing

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-toml
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
args: [--markdown-linebreak-ext=md]

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.2
hooks:
- id: ruff-check
- id: ruff-format
7 changes: 7 additions & 0 deletions peppy-poppies/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Copyright 2021 Python Discord

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
198 changes: 198 additions & 0 deletions peppy-poppies/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
# CodeCaptcha
A CAPTCHA system where the user writes python code to solve a given question.

A normal example:

![Example question](docs-assets/16768e08d0bf01f942995f0077ef5e6718aba3298c7b609dd98cf3825fa0db0a.png)

<details>
<summary>Chaotic example (Note that it is very long):</summary>

This question has 100 steps and ~~AI has failed to solve this :)~~ (I used the wrong model in the original test with Google Gemini 2.5 Flash, and Gemini 2.5 Pro was able to solve this with 13,857 tokens)

![Example question](docs-assets/de19ebabd51028f36f7ee03dbe4365b54726181300998b3bf1fd3954a17966e1.png)

<details>
<summary>Spoiler: Test input</summary>

```py
[16386, 19874, 48296, 41718, 58488, 42810, 58044]
```

</details>

<details>
<summary>Spoiler: Test output</summary>

```py
[24, 24, 24, 24, 24, 24, 24]
```

Could you have possibly guessed the result looks like this? I certainly didn't

> Side note: The reason I figured out afterward is that each step in the question is deterministic (a given input would always give the same output for the same step), and many steps in the `question_set.json` have a many-to-one relationship, therefore, when there are a lot of steps (in this case: 100), it is very likely that all the inputs produce the exact same result.

</details>

</details>

## How to Run the project with the demo
<details>
<summary>Run with docker (recommended)</summary>

Prerequisites: Have [docker](https://docs.docker.com/engine/install/) installed with `docker compose`

### Step 1: Setup `.env`

In contrast to running without docker, `.env` setup is necessary for running in docker, It would fail if the following environment variables are not set.

- `CODECAPTCHA_DOMAIN` to `http://127.0.0.1:9201`
- It can be changed depending on the configuration in `docker-compose.yml`. This environment variable is the domain in which the **client** accesses the CAPTCHA server
- `CODECAPTCHA_DOMAIN_INTERNAL` to `http://captcha:8001`
- If the CAPTCHA endpoint is from `CODECAPTCHA_DOMAIN` it can be accessible inside the docker container (such as a publicly accessible domain), then this environment variable is not needed

Other configurations can be changed, according to the documentation in `.env.example`. The default values should work for them.

### Step 2: Run the project
```bash
docker compose up -d --build
```
The [demo site](http://127.0.0.1:9200) and the [captcha site](http://127.0.0.1:9201) can be accessed from http://127.0.0.1:9200 and http://127.0.0.1:9201 respectively
</details>
<details>
<summary>Run without docker</summary>

Prerequisites: Have [uv](https://docs.astral.sh/uv/getting-started/installation/) and `python3.12` installed

### Step 1: Setup `.venv`
```bash
uv sync
```

### Step 2: Setup `.env`
By default, the project can be run without creating or setting up `.env`, however, you might want to change some configurations. Check `.env.example` for information to configurate `.env`.

Note: If you changed the `.env` file, or any other files in `frontend/`, you must set the project up from the next step again.

### Step 3: Run the build script
```bash
uv run build.py
```
This configures the frontend code to create a set of files in `dist/` which link the demo assets to the CAPTCHA server endpoint defined in `CODECAPTCHA_DOMAIN`

### Step 4: Run the project
Run in 2 seperate terminals
```bash
# This must be run first
uv run litestar --app server.captcha.main:app run --port 8001 --reload
# Run the following about 5 to 10 seconds later in the other terminal
uv run litestar --app server.backend.main:app run --port 8000 --reload
```
`--host 0.0.0.0` can be added on either command if it need to be accessible from other IP

The [demo site](http://127.0.0.1:8000) and the [captcha site](http://127.0.0.1:8001) can be accessed from http://127.0.0.1:8000 and http://127.0.0.1:8001 respectively
</details>

## Short video demo
![Demo](docs-assets/Presentation.gif)

## Why is it wrong?

Have you ever seen a meme like this?

<img width="446" height="271" alt="image" src="https://github.com/user-attachments/assets/df3c995c-4ced-43de-82a0-16d0de28a628" />

> Mark Rushakoff Sep 19, 2009 from StackOverflow, Answer to "alternative captcha methods", https://stackoverflow.com/a/1448684 CC-BY-SA 2.5. The original source that the author mentioned is no longer available

One that is overcomplicated and no one can solve them? We done something similar, but for coding! You have to write the code to solve very specific problems that have no practical usage, and hopefully it's fun?

### Other reasons it is wrong
- It is written in python - which makes it really slow (This is why it takes 5-6 seconds to load) and in addition to the complex UI framework used on the CAPTCHA UI for features such as the code editor, it would freeze my tab for about 10s and about 30s to load (hopefully that doesn't happen on yours), and it downloads about 50MiB of packages before it can be run.
- Statistically LLMs have higher success rates to solve these problems than a human can, without help from LLMs or other people (considering most of the population in the world cannot write python code by themselves).
- LLMs are not trained to avoid solving these questions, unlike conventional CAPTCHAs, which makes them potentially have a higher chance of success than normal CAPTCHAs.
- The server also needed high computational effort to know and validate the answer, unlike normal CAPTCHA which the question is generated from answers.

## Project structure

- `server/captcha` - The CAPTCHA server, written with Litestar that is responsible for generating images and creating the questions.
- `server/backend` - A basic demo server written with Litestar that handles the theoretical login system that is gated with CAPTCHA.
- `frontend/captcha` - Contains the static assets for the CAPTCHA server.
<details>
<summary>Disclosure</summary>

`frontend/captcha/parse.py` is a patch for micropython as it didn't bundle the `urllib.parse` stdlib. The file contains `urllib.parse` and `ipaddress` standard libraries from [cpython](https://github.com/python/cpython) and a patch for some other feature that isn't available in micropython such as `str.isascii` and "too complex" regex which is used by the original code from the standard library, which replaces with equivialent behaviour.

</details>
- `frontend/demo` - A demo login page for testing
- `crypto` - A module that both CAPTCHA server and demo server use to generate/handle public private key pair, and to generate and validate the JWT(JSON Web Token) using the Ed25519 key.
- `captcha_data` - Contains a font file and the a question set
<details>
<summary>Disclosure</summary>

- `captcha_data/JetBrainsMono-Regular.ttf` is a font created by JetBrains, and licensed under SIL Open Font License, Version 1.1 (OFL). The license text is inclued in `captcha_data/OFL.txt` as required by the license. The font is included for the purpose to run the project with minimal setup, and any other font can be used. The OFL license is compatible with MIT license according to [FOSSA](https://fossa.com/blog/open-source-licenses-101-sil-open-font-license-ofl/)
- `captcha_data/question_set.json` is created with a combination of manual effort and AI generation. Approximately 2 million questions are generated during testing, with only 1 exceeding the execution timeout of 0.5s during testing when calculating a prime number, which likely originated from saturated resource usage from other tasks running on the test device. However, some question descriptions might not match the checking criteria (with 1 known case found after the deadline)

</details>
- `build.py` A build script which puts all the files from `frontend/` to `dist/` and replaces `[domain]` in specific files to the domain defined by the environment variable `CODECAPTCHA_DOMAIN` so the client can connect to the correct CAPTCHA servers specified in the static file. This is only needed for the demo server, but for consistency, the CAPTCHA server will also use it.

## Contribution list
<details>
<summary>harshal6927 (@Harshal6927)</summary>

- Demo server
- CAPTCHA server
- Demo page UI
- Demo login system on the backend
- Setup SQLite database for the servers
</details>
<details>
<summary>deleted.user0 (@i-am-unknown-81514525)</summary>

- CAPTCHA UI
- CAPTCHA frontend
- Adding login system on the demo frontend
- JWT generation and validation, Ed25519 key generation and handling
- Question generator parser
- Writing question set
- Update image generation
- Write the final `README.md`
</details>
<details>
<summary>ununenium817 (@Ununenium817)</summary>

- Help writing the CAPTCHA server that was replaced
- Writing question set
- Construct system prompt and code to generate part of question set
</details>
<details>
<summary>wrybyte (@tayvona)</summary>

- Minor UI improvement on demo page
</details>
<details>
<summary>fiwam (@fiwam)</summary>

- Update CAPTCHA frontend to handle image
- Convert the question generated to send image instead of text to client
</details>
<details>
<summary>dragonsenseiguy (@DragonSenseiGuy)</summary>

- Attempt to write the CAPTCHA server that was replaced
- Minor UI improvement for the CAPTCHA frame for usability
- Wrote JWT Validator but was scrapped(due to issues).
- Attempt to write the login system for demo server that didn't get merged.
- Update various part of `README.md`
</details>

## Framework choice

The project used a combination of Pyscript and Pyodide from the approved frameworks, with some HTML/js/css when necessary in the CAPTCHA files.
- Pyscript is used in `frontend/captcha/captcha.py` and `frontend/captcha/captcha_handler.py` to handle the communication between 2 sites to exchange the JWT token.
- Pyodide is used to run user code in isolation in `frontend/captcha/runner.js`

Other framework:
- [Panel](https://panel.holoviz.org/) is used as a frontend framework with pyscript as a CAPTCHA UI, defined in `frontend/captcha/captcha.py`.
- [Litestar](https://litestar.dev/) is used as backend framework for both the CAPTCHA server and DEMO server in `server/`.
- [pyjwt](https://pyjwt.readthedocs.io/) and [cryptography](https://cryptography.io/) is used for Ed25519 key handling, JWT creation and validation in `crypto/`.
- [Pillow](https://pillow.readthedocs.io/en/stable/) is used to generate image of question that is sent to the client.
35 changes: 35 additions & 0 deletions peppy-poppies/build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from os import getenv
from pathlib import Path
from shutil import copytree, rmtree

try:
from dotenv import load_dotenv

load_dotenv(override=True)
except ImportError:
pass
Comment on lines +5 to +10
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this raise some sort of warning if the .env file isn't able to be loaded? If this is intended to be development only, should there be some sort of flag to read/set?


rmtree(Path("./dist"), ignore_errors=True) # remove the folder whether exist or not
copytree(Path("./frontend"), "./dist/frontend")

index_html_path: Path = Path("./dist") / "frontend" / "demo" / "index.html"

if index_html_path.exists():
with index_html_path.open("r", encoding="utf-8") as fp:
content = fp.read()

content = content.replace("[domain]", getenv("CODECAPTCHA_DOMAIN", "http://127.0.0.1:8001"))

with index_html_path.open("w", encoding="utf-8") as fp:
fp.write(content)

app_js_path: Path = Path("./dist") / "frontend" / "demo" / "app.js"

if app_js_path.exists():
with app_js_path.open("r", encoding="utf-8") as fp:
content = fp.read()

content = content.replace("[domain]", getenv("CODECAPTCHA_DOMAIN", "http://127.0.0.1:8001"))

with app_js_path.open("w", encoding="utf-8") as fp:
fp.write(content)
32 changes: 32 additions & 0 deletions peppy-poppies/captcha.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
FROM python:3.12-slim-bookworm

COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

RUN apt-get update && apt-get -y install curl

# Sync the project into a new environment, asserting the lockfile is up to date
WORKDIR /app
ENV UV_LINK_MODE=copy

RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --locked --only-group backend --only-group math --compile-bytecode --no-install-project

ADD pyproject.toml /app
ADD uv.lock /app
ADD server/captcha /app/server/captcha
ADD frontend/captcha /app/frontend/captcha
ADD crypto /app/crypto

RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --locked --only-group backend --only-group math --compile-bytecode

ADD build.py /app
ARG CODECAPTCHA_DOMAIN
ENV CODECAPTCHA_DOMAIN=$CODECAPTCHA_DOMAIN
RUN ["uv", "run", "--no-sync", "python3", "build.py"]

VOLUME ["/app/captcha_data"]

CMD ["uv", "run", "--no-sync", "litestar", "--app", "server.captcha.main:app", "run", "--port", "8001", "--host", "0.0.0.0"]
Empty file.
Binary file not shown.
Loading