{"id":20126695,"url":"https://github.com/cc-d/flask-simple-captcha","last_synced_at":"2026-03-10T13:32:38.405Z","repository":{"id":36755086,"uuid":"230030388","full_name":"cc-d/flask-simple-captcha","owner":"cc-d","description":"lightweight captcha. doesn't require server side sessions packages","archived":false,"fork":false,"pushed_at":"2024-09-03T22:06:10.000Z","size":12869,"stargazers_count":30,"open_issues_count":6,"forks_count":12,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-27T22:38:16.135Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cc-d.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-25T02:42:27.000Z","updated_at":"2025-01-18T12:59:27.000Z","dependencies_parsed_at":"2023-12-06T01:33:51.288Z","dependency_job_id":"9d01afd7-3a19-4449-8f41-7140850c88fc","html_url":"https://github.com/cc-d/flask-simple-captcha","commit_stats":{"total_commits":13,"total_committers":4,"mean_commits":3.25,"dds":"0.23076923076923073","last_synced_commit":"6a85762d79996aa22dc5dfda5b77c6edb902a976"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cc-d%2Fflask-simple-captcha","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cc-d%2Fflask-simple-captcha/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cc-d%2Fflask-simple-captcha/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cc-d%2Fflask-simple-captcha/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cc-d","download_url":"https://codeload.github.com/cc-d/flask-simple-captcha/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242259935,"owners_count":20098429,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-13T20:17:18.408Z","updated_at":"2026-03-10T13:32:33.377Z","avatar_url":"https://github.com/cc-d.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# flask-simple-captcha\n\n### CURRENT VERSION: **v5.5.4**\n\n**v5.0.0+ added an encryption mechanism to the stored text in the jwts. Previous versions are insecure!**\n\n**v5.5.4 removed the upper limit on werkzeug/pillow dependency versions**\n\n`flask-simple-captcha` is a CAPTCHA generator class for generating and validating CAPTCHAs. It allows for easy integration into Flask applications.\n\nSee the encryption / decryption breakdown below for more information on the verification mechanism.\n\n## Features\n\n- Generates CAPTCHAs with customizable length and characters\n- Easy integration with Flask applications\n- Built-in image rendering and line drawing for added complexity\n- Base64 image encoding for easy embedding into HTML\n- Uses JWTs and Werkzeug password hashing for secure CAPTCHA verification\n- Successfully submitted CAPTCHAs are stored in-memory to prevent resubmission\n- Backwards compatible with 1.0 versions of this package\n- Avoids visually similar characters by default\n- Supports custom character set provided by user\n- Casing of submitted captcha is ignored by default\n- Minor random font variation in regards to size/family/etc\n- PNG/JPEG image format support\n- Customizable text|noise/background colors\n\n## Prerequisites\n\n- Python 3.7 or higher\n- Werkzeug \u003e=0.16.0, \u003c3\n- Pillow \u003e4, \u003c10\n\n## Installation\n\nImport this package directly into your Flask project and make sure to install all dependencies.\n\n## How to Use\n\n### Configuration\n\n```python\nDEFAULT_CONFIG = {\n    'SECRET_CAPTCHA_KEY': 'LONGKEY',  # use for JWT encoding/decoding\n\n    # CAPTCHA GENERATION SETTINGS\n    'EXPIRE_SECONDS': 60 * 10,  # takes precedence over EXPIRE_MINUTES\n    'CAPTCHA_IMG_FORMAT': 'JPEG',  # 'PNG' or 'JPEG' (JPEG is 3X faster)\n\n    # CAPTCHA TEXT SETTINGS\n    'CAPTCHA_LENGTH': 6,  # Length of the generated CAPTCHA text\n    'CAPTCHA_DIGITS': False,  # Should digits be added to the character pool?\n    'EXCLUDE_VISUALLY_SIMILAR': True,  # Exclude visually similar characters\n    'BACKGROUND_COLOR': (0, 0, 0),  # RGB(A?) background color (default black)\n    'TEXT_COLOR': (255, 255, 255),  # RGB(A?) text color (default white)\n\n    # Optional settings\n    #'ONLY_UPPERCASE': True, # Only use uppercase characters\n    #'CHARACTER_POOL': 'AaBb',  # Use a custom character pool\n}\n\n```\n\n### Initialization\n\nAdd this code snippet at the top of your application:\n\n```python\nfrom flask_simple_captcha import CAPTCHA\nYOUR_CONFIG = {\n    'SECRET_CAPTCHA_KEY': 'LONG_KEY',\n    'CAPTCHA_LENGTH': 6,\n    'CAPTCHA_DIGITS': False,\n    'EXPIRE_SECONDS': 600,\n}\nSIMPLE_CAPTCHA = CAPTCHA(config=YOUR_CONFIG)\napp = SIMPLE_CAPTCHA.init_app(app)\n```\n\n### Protecting a Route\n\nTo add CAPTCHA protection to a route, you can use the following code:\n\n```python\n@app.route('/example', methods=['GET','POST'])\ndef example():\n    if request.method == 'GET':\n        new_captcha_dict = SIMPLE_CAPTCHA.create()\n        return render_template('your_template.html', captcha=new_captcha_dict)\n    if request.method == 'POST':\n        c_hash = request.form.get('captcha-hash')\n        c_text = request.form.get('captcha-text')\n        if SIMPLE_CAPTCHA.verify(c_text, c_hash):\n            return 'success'\n        else:\n            return 'failed captcha'\n```\n\nIn your HTML template, you need to wrap the CAPTCHA inputs within a form element. The package will only generate the CAPTCHA inputs but not the surrounding form or the submit button.\n\n```html\n\u003c!-- your_template.html --\u003e\n\u003cform action=\"/example\" method=\"post\"\u003e\n  {{ captcha_html(captcha)|safe }}\n  \u003cinput type=\"submit\" value=\"Submit\" /\u003e\n\u003c/form\u003e\n```\n\n## Example Captcha Images\n\nHere is an example of what the generated CAPTCHA images look like, this is a screen shot from the `/images` route of the debug server.\n\n![Example CAPTCHA Image](/captcha-example.PNG)\n\n[link to image url if the above does not load](https://github.com/cc-d/flask-simple-captcha/blob/master/captcha-example.PNG)\n\n## Encryption and Decryption Breakdown\n\nUses a combination of JWTs and Werkzeug's password hashing to encrypt and decrypt CAPTCHA text.\n\n### Encryption\n\n1. **Salting the Text**: The CAPTCHA text is salted by appending the secret key at the beginning.\n   ```python\n   salted_text = secret_key + text\n   ```\n2. **Hashing**: Werkzeug's `generate_password_hash` function is then used to hash the salted CAPTCHA text.\n   ```python\n   hashed_text = generate_password_hash(salted_text)\n   ```\n3. **Creating JWT Token**: A JWT token is generated using the hashed CAPTCHA text and an optional expiration time.\n   ```python\n   payload = {\n       'hashed_text': hashed_text,\n       'exp': datetime.utcnow() + timedelta(seconds=expire_seconds),\n   }\n   return jwt.encode(payload, secret_key, algorithm='HS256')\n   ```\n\n### Decryption\n\n1. **Decode JWT Token**: The JWT token is decoded using the secret key. If the token is invalid or expired, the decryption process will fail.\n   ```python\n   decoded = jwt.decode(token, secret_key, algorithms=['HS256'])\n   ```\n2. **Extract Hashed Text**: The hashed CAPTCHA text is extracted from the decoded JWT payload.\n   ```python\n   hashed_text = decoded['hashed_text']\n   ```\n3. **Verifying the Hash**: Werkzeug's `check_password_hash` function is used to verify that the hashed CAPTCHA text matches the original salted CAPTCHA text.\n   ```python\n   salted_original_text = secret_key + original_text\n   if check_password_hash(hashed_text, salted_original_text):\n       return original_text\n   ```\n\n# Development\n\n### Setting Up Your Development Environment Without VS Code\n\n1. **Create a Virtual Environment:**\n\n   - Navigate to the project directory where you've cloned the repository and create a virtual environment named `venv` within the project directory:\n\n     ```bash\n     python -m venv venv/\n     ```\n\n2. **Activate the Virtual Environment:**\n\n   - Activate the virtual environment to isolate the project dependencies:\n     - On macOS/Linux:\n       ```bash\n       source venv/bin/activate\n       ```\n     - On Windows (using Command Prompt):\n       ```cmd\n       .\\venv\\Scripts\\activate\n       ```\n     - On Windows (using PowerShell):\n       ```powershell\n       .\\venv\\Scripts\\Activate.ps1\n       ```\n\n3. **Install Dependencies:**\n\n   Install the required dependencies for development:\n\n   ```bash\n   pip install -r requirements_dev.txt\n   ```\n\n   Install the local flask-simple-captcha package:\n\n   ```bash\n   pip install .\n   ```\n\n## Running Tests\n\n#### ENSURE YOU HAVE A VENV NAMED `venv` IN THE PROJECT DIRECTORY AND THAT IT IS ACTIVATED AND BOTH THE DEPENDENCIES AND THE LOCAL FLASK-SIMPLE-CAPTCHA PACKAGE ARE INSTALLED IN THE VENV\n\nAs of the time of me writing this README (2023-11-15), pytest reports 97% test coverage of the logic in the `flask_simple_captcha` package. Should be kept as close to 100% as possible.\n\n### Run Tests Without VS Code\n\n- Run the tests using the following command (make sure your venv is activated and you are in the project directory)\n  ```bash\n  python -m pytest tests.py -s -vv --cov=flask_simple_captcha/ --cov-report term-missing\n  ```\n- The command runs pytest with flags for verbose output, standard output capture, coverage report, and displaying missing lines in the coverage.\n\n### Running Tests With VS Code\n\nSimply hit command + shift + p and type \"Select And Start Debugging\" and select `Python: Run tests`. You will want to make sure your venv is installed and activated.\n\n### Example Test Output\n\n```bash\n... previous output omitted for brevity ...\n\ntests.py::TestCaptchaUtils::test_jwtencrypt PASSED\ntests.py::TestCaptchaUtils::test_no_hashed_text PASSED\n\n\n---------- coverage: platform darwin, python 3.8.18-final-0 ----------\nName                                         Stmts   Miss  Cover   Missing\n----------------------------------\nflask_simple_captcha/__init__.py                 3      0   100%\nflask_simple_captcha/captcha_generation.py      78      0   100%\nflask_simple_captcha/config.py                  10      0   100%\nflask_simple_captcha/img.py                     56      0   100%\nflask_simple_captcha/text.py                    25      0   100%\nflask_simple_captcha/utils.py                   51      0   100%\n----------------------------\nTOTAL                                          223      0   100%\n\n\n==================================== 41 passed in 5.53s\n```\n\n## Debug Server\n\n#### **Start the debug server without VS Code**\n\n1. **Set Environment Variables:**\n   - Before running the debug Flask server, set the required environment variables:\n   - On macOS/Linux:\n     ```bash\n     export FLASK_APP=debug_flask_server\n     export FLASK_DEBUG=1\n     ```\n   - On Windows (using Command Prompt):\n     ```cmd\n     set FLASK_APP=debug_flask_server\n     set FLASK_DEBUG=1\n     ```\n   - On Windows (using PowerShell):\n     ```powershell\n     $env:FLASK_APP=\"debug_flask_server\"\n     $env:FLASK_DEBUG=\"1\"\n     ```\n2. **Start the debug Flask server:**\n   - Run the following command to start the debug Flask server:\n     ```bash\n     flask run --no-debugger\n     ```\n   - This will start the debug Flask server with the automatic reloader. See the navigation section below on how to access the debug server.\n\n#### **Start the debug server with VS Code**\n\n- Hit command + shift + p and type \"Select And Start Debugging\" and select `Python: Flask`\n- This will start the debug Flask server with debugging features enabled, including the interactive debugger and automatic reloader.\n\n### Accessing the Debug Server\n\nNavigate to `localhost:5000` in your browser to view the debug server. You can also navigate to `localhost:5000/images` to view 50 CAPTCHA images at once, or `localhost:5000/images/\u003c$NUMBER_OF_IMAGES\u003e` to view an arbritrary amount of generated captchas.\n\n## Code Examples\n\nFor usage and integration examples, including how to use `flask-simple-captcha` with WTForms and Flask-Security, check out the [Code Examples](code_examples.md) document.\n\n## Contributing\n\nFeel free to open a PR. The project has undergone a recent overhaul to improve the code quality.\n\nIf you make changes in the logic, please follow the steps laid out in this document for testing and debugging. Make sure the coverage % stays \u003e= 100% and that you verify manually at least once that things look okay by submitting a real CAPTCHA in the debug server.\n\nThe `pyproject.toml` has the required configuration for `black` and `isort`. There is also a vscode settings file equivalent to the `pyproject.toml` file in `.vscode/settings.json`.\n\n## License\n\nMIT\n\nContact: ccarterdev@gmail.com\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcc-d%2Fflask-simple-captcha","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcc-d%2Fflask-simple-captcha","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcc-d%2Fflask-simple-captcha/lists"}