flask-ishuman


Nameflask-ishuman JSON
Version 2.1.0 PyPI version JSON
download
home_pagehttps://ari-web.xyz/gh/flask-ishuman
Summarysimple flask captcha validation
upload_time2023-11-04 15:36:44
maintainer
docs_urlNone
authorAri Archer
requires_python
licenseGPLv3+
keywords flask captcha recaptcha audio captcha image captcha human validation
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # flask-ishuman

> simple flask captcha validation

# usage

a good example of usage can be found in [/tests/main.py](/tests/main.py), although heres a basic example

```py
import flask
import flask_ishuman

app = flask.Flask(__name__)
h = flask_ishuman.IsHuman()

@app.get("/")
def index():
    c = h.new()
    return ...  # now render it, like c.image() maybe or c.rawpng() or something

@app.post("/")
def validate():
    code = flask.request.form.get("code")  # this if u have a <form> that has name=code in it, but ur free to get the `code` in any way u want

    # if code is None then itll return false regardless

    if h.verify(code):
        pass  # captcha valid
    else:
        pass  # captcha invalid

app.config["SECRET_KEY"] = h.rand.randbytes(2048)

# firefox throws warnings if these are not set
app.config["SESSION_COOKIE_SAMESITE"] = "None"
app.config["SESSION_COOKIE_SECURE"] = True

h.init_app(app)
app.run("127.0.0.1", 8080)
```

heres the functions and classes we have :

-   `IsHuman` -- captcha wrapper
    -   `__init__(image_args: dict, audio_args: dict) -> None` -- constructor, passes `image_args` to captcha.image.ImageCaptcha and same with `audio_args`, just for audio ( [underlying captcha library](https://pypi.org/project/captcha/), although [i forked it](https://pypi.org/project/more-captcha/) )
        -   `cimage` attr is an instance of `captcha.image.ImageCaptcha`
        -   `caudio` attr is an instance of `captcha.audio.AudioCaptcha`
        -   `rand` is a cryptographically secure randomness source, or `secrets.SystemRandom()`
        -   `skey` is the unique captcha key in the session
        -   `app` is the flask app ( can be `None` if `init_app()` was not called )
        -   `pepper` is the pepper of captchas ( also can b `None` if `init_app()` was not called )
    -   `init_app(app: flask.Flask) -> Self` -- initialize flask app, set up variables, configuration, generate keys
    -   `random(length: int | None) -> str` -- returns a random code of `length` length, uses a random number in `CAPTCHA_RANGE` length by default
    -   `digest(code: str, salt: bytes | None) -> (bytes, bytes, float)` -- returns a salted and peppered sha3-512 digest of a code, returns `(digest, salt, timestamp)`
    -   `set_code(code: str) -> Self` -- sets the captcha to a code
    -   `get_digest() -> (bytes, bytes, float) | None` -- returns the current captcha digest if available, returns `(digest, salt, timestamp)`, returns `None` if unavailable or expired
    -   `verify(code: str | None, expire: bool = True) -> bool` -- returns if a code is a valid hash, if `code` is `None` will always return `False`, which helps to work with flask apis like `flask.request.from.get`, will also call `expire()` if `expire=True` ( default ) is passed
    -   `new(code: str | None, length: str | None, set_c: bool = True)` -- returns a new `CaptchaGenerator`, passes code as the code and uses `random(length)` by default, `set_code()` is called if `set_c` is `True`, which is the default
    -   `expire() -> Self` -- expire the current captcha
    -   `expired_dt(ts: float) -> bool` -- check if the current captcha is expired according to its `ts` ( timestamp )
    -   `auto_expire(ts: float) -> bool` -- runs `expire()` if `expired_dt()` is `True`, returns the result of `expired_dt()`
-   `CaptchaGenerator` -- generate captchas
    -   `__init__(code: str, cimage: captcha.image.ImageCaptcha, caudio: captcha.audio.AudioCaptcha) -> None` -- constructor, takes in the captcha code and captcha helpers
        -   `code` is the captcha code
        -   `cimage` is an instance of `captcha.image.ImageCaptcha`
        -   `caudio` is an instance of `captcha.audio.AudioCaptcha`
    -   `rawpng() -> bytes` -- returns raw png data used in `png()`
    -   `rawwav() -> bytes` -- returns raw wav data used in `wav()`
    -   `png() -> str` -- returns base64 encoded png of the image captcha
    -   `wav() -> str` -- returns base64 encoded wav of the audio captcha
    -   `image(alt: str = "Image CAPTCHA") -> str` -- returns html to embed for the captcha, `alt` attr is set as `alt`, note tht `alt` is not escaped
    -   `audio(alt: str = "Audio CAPTCHA", controls: bool = True) -> str` -- returns the audio captcha embedding html, `alt` attr is not set, but embded in the `audio` element as `alt`, and `controls` is added too if `controls` is set to `True`, note tht `alt` is not escaped

what u have to do is basically :

-   create `IsHuman`
-   call `init_app` on it
-   call `new` on it
-   use functions provided in` CaptchaGenerator` to display captcha
    -   for example embed it in html using `.png()` or have a route like `/captcha.png` to return the actual png although do whatever u want

# configuration

-   `SECRET_KEY` -- this is default in flask, set this to a secure random value, this is used for session storage and protection, will throw a warning if unset
-   `CAPTCHA_SALT_LEN` -- the salt length to use for salting of hashes, by default `32`
-   `CAPTCHA_CHARSET` -- the charset to use in captchas, by default all ascii letters, digits and characters `@#%?`
-   `CAPTCHA_RANGE` -- a 2 value tuple storing `(from, to)` arguments, used to generation of random captcha lengths, by default from 4 to 8 ( `(4, 8)` )
-   `CAPTCHA_EXPIRY` -- a float, which defines the lifetime of a single captcha in seconds, by default it is `None` which means the lifetime is infinite
-   `CAPTCHA_PEPPER_SIZE` -- the size of the pepper value, by default `2048`
-   `CAPTCHA_PEPPER_FILE` -- the pepper file to use, which is like a constant salt not stored in the session, by default `captcha_pepper`

these should be a part of `app.config`, although optional -- will use default values if unspecified

## best configuration practices

-   large, cryptographically secure, random secret key
-   a salt length that is anywhere from 16 to 64 bytes, dont go overboard though as that will increase the size of the session
-   charset of readable characters when messed with in a captcha sense
-   a sensible range, so it isnt too large like 100 characters or too small like 1 characters
-   a short expiry time, but not so sort that users cant figure it out in time, maybe like 5 to 10 mins, keep in mind audio captchas if ur using them, audio captchas tend to take longer
-   a big pepper size, maybe like from 512 to 4096 bytes

## styling and selection

-   image captchas get the `image-captcha` id ( `<img id=... />` )
-   audio captchas get the `audio-captcha` id ( `<audio id=...><source /><audio>` )

## logging

all logging of flask-ishuman is done through `logging.DEBUG`

            

Raw data

            {
    "_id": null,
    "home_page": "https://ari-web.xyz/gh/flask-ishuman",
    "name": "flask-ishuman",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "flask,captcha,recaptcha,audio captcha,image captcha,human validation",
    "author": "Ari Archer",
    "author_email": "ari.web.xyz@gmail.com",
    "download_url": "",
    "platform": null,
    "description": "# flask-ishuman\n\n> simple flask captcha validation\n\n# usage\n\na good example of usage can be found in [/tests/main.py](/tests/main.py), although heres a basic example\n\n```py\nimport flask\nimport flask_ishuman\n\napp = flask.Flask(__name__)\nh = flask_ishuman.IsHuman()\n\n@app.get(\"/\")\ndef index():\n    c = h.new()\n    return ...  # now render it, like c.image() maybe or c.rawpng() or something\n\n@app.post(\"/\")\ndef validate():\n    code = flask.request.form.get(\"code\")  # this if u have a <form> that has name=code in it, but ur free to get the `code` in any way u want\n\n    # if code is None then itll return false regardless\n\n    if h.verify(code):\n        pass  # captcha valid\n    else:\n        pass  # captcha invalid\n\napp.config[\"SECRET_KEY\"] = h.rand.randbytes(2048)\n\n# firefox throws warnings if these are not set\napp.config[\"SESSION_COOKIE_SAMESITE\"] = \"None\"\napp.config[\"SESSION_COOKIE_SECURE\"] = True\n\nh.init_app(app)\napp.run(\"127.0.0.1\", 8080)\n```\n\nheres the functions and classes we have :\n\n-   `IsHuman` -- captcha wrapper\n    -   `__init__(image_args: dict, audio_args: dict) -> None` -- constructor, passes `image_args` to captcha.image.ImageCaptcha and same with `audio_args`, just for audio ( [underlying captcha library](https://pypi.org/project/captcha/), although [i forked it](https://pypi.org/project/more-captcha/) )\n        -   `cimage` attr is an instance of `captcha.image.ImageCaptcha`\n        -   `caudio` attr is an instance of `captcha.audio.AudioCaptcha`\n        -   `rand` is a cryptographically secure randomness source, or `secrets.SystemRandom()`\n        -   `skey` is the unique captcha key in the session\n        -   `app` is the flask app ( can be `None` if `init_app()` was not called )\n        -   `pepper` is the pepper of captchas ( also can b `None` if `init_app()` was not called )\n    -   `init_app(app: flask.Flask) -> Self` -- initialize flask app, set up variables, configuration, generate keys\n    -   `random(length: int | None) -> str` -- returns a random code of `length` length, uses a random number in `CAPTCHA_RANGE` length by default\n    -   `digest(code: str, salt: bytes | None) -> (bytes, bytes, float)` -- returns a salted and peppered sha3-512 digest of a code, returns `(digest, salt, timestamp)`\n    -   `set_code(code: str) -> Self` -- sets the captcha to a code\n    -   `get_digest() -> (bytes, bytes, float) | None` -- returns the current captcha digest if available, returns `(digest, salt, timestamp)`, returns `None` if unavailable or expired\n    -   `verify(code: str | None, expire: bool = True) -> bool` -- returns if a code is a valid hash, if `code` is `None` will always return `False`, which helps to work with flask apis like `flask.request.from.get`, will also call `expire()` if `expire=True` ( default ) is passed\n    -   `new(code: str | None, length: str | None, set_c: bool = True)` -- returns a new `CaptchaGenerator`, passes code as the code and uses `random(length)` by default, `set_code()` is called if `set_c` is `True`, which is the default\n    -   `expire() -> Self` -- expire the current captcha\n    -   `expired_dt(ts: float) -> bool` -- check if the current captcha is expired according to its `ts` ( timestamp )\n    -   `auto_expire(ts: float) -> bool` -- runs `expire()` if `expired_dt()` is `True`, returns the result of `expired_dt()`\n-   `CaptchaGenerator` -- generate captchas\n    -   `__init__(code: str, cimage: captcha.image.ImageCaptcha, caudio: captcha.audio.AudioCaptcha) -> None` -- constructor, takes in the captcha code and captcha helpers\n        -   `code` is the captcha code\n        -   `cimage` is an instance of `captcha.image.ImageCaptcha`\n        -   `caudio` is an instance of `captcha.audio.AudioCaptcha`\n    -   `rawpng() -> bytes` -- returns raw png data used in `png()`\n    -   `rawwav() -> bytes` -- returns raw wav data used in `wav()`\n    -   `png() -> str` -- returns base64 encoded png of the image captcha\n    -   `wav() -> str` -- returns base64 encoded wav of the audio captcha\n    -   `image(alt: str = \"Image CAPTCHA\") -> str` -- returns html to embed for the captcha, `alt` attr is set as `alt`, note tht `alt` is not escaped\n    -   `audio(alt: str = \"Audio CAPTCHA\", controls: bool = True) -> str` -- returns the audio captcha embedding html, `alt` attr is not set, but embded in the `audio` element as `alt`, and `controls` is added too if `controls` is set to `True`, note tht `alt` is not escaped\n\nwhat u have to do is basically :\n\n-   create `IsHuman`\n-   call `init_app` on it\n-   call `new` on it\n-   use functions provided in` CaptchaGenerator` to display captcha\n    -   for example embed it in html using `.png()` or have a route like `/captcha.png` to return the actual png although do whatever u want\n\n# configuration\n\n-   `SECRET_KEY` -- this is default in flask, set this to a secure random value, this is used for session storage and protection, will throw a warning if unset\n-   `CAPTCHA_SALT_LEN` -- the salt length to use for salting of hashes, by default `32`\n-   `CAPTCHA_CHARSET` -- the charset to use in captchas, by default all ascii letters, digits and characters `@#%?`\n-   `CAPTCHA_RANGE` -- a 2 value tuple storing `(from, to)` arguments, used to generation of random captcha lengths, by default from 4 to 8 ( `(4, 8)` )\n-   `CAPTCHA_EXPIRY` -- a float, which defines the lifetime of a single captcha in seconds, by default it is `None` which means the lifetime is infinite\n-   `CAPTCHA_PEPPER_SIZE` -- the size of the pepper value, by default `2048`\n-   `CAPTCHA_PEPPER_FILE` -- the pepper file to use, which is like a constant salt not stored in the session, by default `captcha_pepper`\n\nthese should be a part of `app.config`, although optional -- will use default values if unspecified\n\n## best configuration practices\n\n-   large, cryptographically secure, random secret key\n-   a salt length that is anywhere from 16 to 64 bytes, dont go overboard though as that will increase the size of the session\n-   charset of readable characters when messed with in a captcha sense\n-   a sensible range, so it isnt too large like 100 characters or too small like 1 characters\n-   a short expiry time, but not so sort that users cant figure it out in time, maybe like 5 to 10 mins, keep in mind audio captchas if ur using them, audio captchas tend to take longer\n-   a big pepper size, maybe like from 512 to 4096 bytes\n\n## styling and selection\n\n-   image captchas get the `image-captcha` id ( `<img id=... />` )\n-   audio captchas get the `audio-captcha` id ( `<audio id=...><source /><audio>` )\n\n## logging\n\nall logging of flask-ishuman is done through `logging.DEBUG`\n",
    "bugtrack_url": null,
    "license": "GPLv3+",
    "summary": "simple flask captcha validation",
    "version": "2.1.0",
    "project_urls": {
        "Homepage": "https://ari-web.xyz/gh/flask-ishuman"
    },
    "split_keywords": [
        "flask",
        "captcha",
        "recaptcha",
        "audio captcha",
        "image captcha",
        "human validation"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "fa51548325a133de0b4c71a0513caa4aef9078a076a36d294ec6415154680291",
                "md5": "15b265154a88c1ef1cdd761515944aa4",
                "sha256": "8bc877fd8ddd8961c839d470ad88f37f958143355cf5e35b4ea491a65c8edb6f"
            },
            "downloads": -1,
            "filename": "flask_ishuman-2.1.0-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "15b265154a88c1ef1cdd761515944aa4",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": null,
            "size": 19310,
            "upload_time": "2023-11-04T15:36:44",
            "upload_time_iso_8601": "2023-11-04T15:36:44.460252Z",
            "url": "https://files.pythonhosted.org/packages/fa/51/548325a133de0b4c71a0513caa4aef9078a076a36d294ec6415154680291/flask_ishuman-2.1.0-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-11-04 15:36:44",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "flask-ishuman"
}
        
Elapsed time: 3.44001s