generateApiKey 0.4.7__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- generateapikey-0.5.0/AGENTS.md +47 -0
- generateapikey-0.5.0/CHANGELOG.md +102 -0
- generateapikey-0.5.0/CONTRIBUTING.md +34 -0
- generateapikey-0.5.0/MANIFEST.in +6 -0
- generateapikey-0.5.0/PKG-INFO +774 -0
- generateapikey-0.5.0/README.md +693 -0
- generateapikey-0.5.0/SECURITY.md +19 -0
- generateapikey-0.5.0/benchmarks/bench.py +41 -0
- generateapikey-0.5.0/examples/__init__.py +0 -0
- generateapikey-0.5.0/examples/django_quickstart.md +67 -0
- generateapikey-0.5.0/examples/fastapi_app.py +109 -0
- generateapikey-0.5.0/generateApiKey.py +23 -0
- generateapikey-0.5.0/generateapikey/__init__.py +350 -0
- generateapikey-0.5.0/generateapikey/__main__.py +249 -0
- generateapikey-0.5.0/generateapikey/crypto.py +131 -0
- generateapikey-0.5.0/generateapikey/integrations/__init__.py +329 -0
- generateapikey-0.5.0/generateapikey/integrations/aiohttp.py +81 -0
- generateapikey-0.5.0/generateapikey/integrations/django.py +276 -0
- generateapikey-0.5.0/generateapikey/integrations/drf.py +101 -0
- generateapikey-0.5.0/generateapikey/integrations/falcon.py +108 -0
- generateapikey-0.5.0/generateapikey/integrations/fastapi.py +86 -0
- generateapikey-0.5.0/generateapikey/integrations/flask.py +93 -0
- generateapikey-0.5.0/generateapikey/integrations/litestar.py +65 -0
- generateapikey-0.5.0/generateapikey/integrations/quart.py +56 -0
- generateapikey-0.5.0/generateapikey/integrations/sanic.py +52 -0
- generateapikey-0.5.0/generateapikey/integrations/starlette.py +101 -0
- generateapikey-0.5.0/generateapikey/limiters.py +109 -0
- generateapikey-0.5.0/generateapikey/llms-full.txt +222 -0
- generateapikey-0.5.0/generateapikey/mfa.py +481 -0
- generateapikey-0.5.0/generateapikey/py.typed +0 -0
- generateapikey-0.5.0/generateapikey/qr.py +51 -0
- generateapikey-0.5.0/generateapikey/tokens.py +123 -0
- generateapikey-0.5.0/generateapikey/utils.py +319 -0
- generateapikey-0.5.0/generateapikey.egg-info/PKG-INFO +774 -0
- generateapikey-0.5.0/generateapikey.egg-info/SOURCES.txt +55 -0
- generateapikey-0.5.0/generateapikey.egg-info/entry_points.txt +3 -0
- generateapikey-0.5.0/generateapikey.egg-info/requires.txt +57 -0
- {generateApiKey-0.4.7/generateApiKey.egg-info → generateapikey-0.5.0/generateapikey.egg-info}/top_level.txt +1 -0
- generateapikey-0.5.0/llms.txt +27 -0
- generateapikey-0.5.0/pyproject.toml +128 -0
- generateapikey-0.5.0/skills/generateapikey/SKILL.md +31 -0
- generateapikey-0.5.0/tests/conftest.py +82 -0
- generateapikey-0.5.0/tests/test_compat.py +53 -0
- generateapikey-0.5.0/tests/test_docs.py +51 -0
- generateapikey-0.5.0/tests/test_examples.py +53 -0
- generateapikey-0.5.0/tests/test_extras.py +164 -0
- generateapikey-0.5.0/tests/test_generate.py +395 -0
- generateapikey-0.5.0/tests/test_integrations_asgi.py +159 -0
- generateapikey-0.5.0/tests/test_integrations_core.py +150 -0
- generateapikey-0.5.0/tests/test_integrations_django.py +187 -0
- generateapikey-0.5.0/tests/test_integrations_flask.py +51 -0
- generateapikey-0.5.0/tests/test_integrations_more.py +293 -0
- generateapikey-0.5.0/tests/test_mfa.py +421 -0
- generateapikey-0.5.0/tests/test_security.py +291 -0
- generateApiKey-0.4.7/MANIFEST.in +0 -1
- generateApiKey-0.4.7/PKG-INFO +0 -163
- generateApiKey-0.4.7/README.md +0 -141
- generateApiKey-0.4.7/generateApiKey/__init__.py +0 -83
- generateApiKey-0.4.7/generateApiKey.egg-info/PKG-INFO +0 -163
- generateApiKey-0.4.7/generateApiKey.egg-info/SOURCES.txt +0 -10
- generateApiKey-0.4.7/generateApiKey.egg-info/requires.txt +0 -1
- generateApiKey-0.4.7/setup.py +0 -35
- {generateApiKey-0.4.7 → generateapikey-0.5.0}/LICENSE +0 -0
- {generateApiKey-0.4.7/generateApiKey.egg-info → generateapikey-0.5.0/generateapikey.egg-info}/dependency_links.txt +0 -0
- {generateApiKey-0.4.7 → generateapikey-0.5.0}/setup.cfg +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Guidance for AI coding agents working **on** this repository. To *use* the library, read [generateapikey/llms-full.txt](generateapikey/llms-full.txt).
|
|
4
|
+
|
|
5
|
+
## Project
|
|
6
|
+
|
|
7
|
+
`generateapikey` is a zero-dependency Python (>= 3.9) library for API keys and MFA. It is published to PyPI as `generateapikey`.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
generateapikey/
|
|
11
|
+
__init__.py generate_api_key, ApiKey, batch/async, legacy generateApiKey(), re-exports
|
|
12
|
+
utils.py charsets, unbiased rejection sampling, derivation, checksum, hashing
|
|
13
|
+
mfa.py TOTP/HOTP, recovery codes, OTP, AttemptLimiter
|
|
14
|
+
tokens.py signed expiring tokens
|
|
15
|
+
qr.py QR output (optional `qrcode` extra, imported lazily)
|
|
16
|
+
crypto.py SecretBox (AES-GCM) for secrets at rest [crypto extra]
|
|
17
|
+
limiters.py Redis attempt limiters (atomic Lua) [redis extra]
|
|
18
|
+
integrations/ __init__ = framework-agnostic APIKeyAuth core; adapters: fastapi starlette django drf
|
|
19
|
+
flask litestar sanic aiohttp quart falcon
|
|
20
|
+
(each imports its framework at module import -> only loaded when the user imports it)
|
|
21
|
+
__main__.py CLI (`generate-api-key`)
|
|
22
|
+
llms-full.txt LLM usage guide, shipped in the wheel, printed by `--llms`
|
|
23
|
+
generateApiKey.py back-compat alias for the old import name; keep it working
|
|
24
|
+
tests/ pytest; test_compat.py guards the old import name and version sync;
|
|
25
|
+
test_docs.py guards documented imports; test_examples.py runs examples/
|
|
26
|
+
examples/, benchmarks/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Commands
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install -e ".[dev]" # test deps + every extra + ruff/mypy/bandit/pre-commit
|
|
33
|
+
pytest -q # passes on 3.9-3.14
|
|
34
|
+
ruff check . && ruff format --check . && mypy && bandit -q -r generateapikey generateApiKey.py
|
|
35
|
+
python -m build && twine check dist/*
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Rules
|
|
39
|
+
|
|
40
|
+
- **No runtime dependencies.** Use the standard library only. Anything else goes behind an optional extra and a lazy import, like `qr.py`.
|
|
41
|
+
- **Security primitives:** use `secrets` for randomness, `utils.safe_equals` (bytes `hmac.compare_digest`, never raises) for every secret comparison, and rejection sampling for alphabet mapping (never `byte % n`). Verification loops must not exit early on a match.
|
|
42
|
+
- **Public API is stable.** Don't rename or remove exported names or change defaults without a deprecation path and a CHANGELOG entry. The legacy `generateApiKey()` and the `generateApiKey` module alias must keep working.
|
|
43
|
+
- **Version lives in two places:** `pyproject.toml` and `generateapikey/__init__.py`. A test enforces that they match. Don't switch to `attr:` dynamic versioning: on case-insensitive filesystems setuptools resolves it to the `generateApiKey.py` alias.
|
|
44
|
+
- **When adding a public function:** add it to `__all__`, give it a typed signature and docstring, write tests, and update README.md, `generateapikey/llms-full.txt` and CHANGELOG.md.
|
|
45
|
+
- **Framework adapters stay thin.** All auth logic lives in `integrations/__init__.py` so every framework behaves the same. Adapters only map request -> `extract`/`authenticate` and `AuthError` -> response. Test each adapter against the real framework (`pytest.importorskip`).
|
|
46
|
+
- **MFA code must match the RFCs.** Keep the RFC 4226/6238 test vectors in `tests/test_mfa.py` passing.
|
|
47
|
+
- Supported Python is 3.9+. Use `from __future__ import annotations` and `typing.Optional`/`Union` rather than runtime `X | Y`.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Renamed
|
|
6
|
+
- The package is now **`generateapikey`** (lowercase), both on PyPI and as the import name. PyPI treats names case-insensitively, so `pip install generateApiKey` still works. `import generateApiKey` (including submodules) keeps working through an alias module that emits a `DeprecationWarning`.
|
|
7
|
+
|
|
8
|
+
### Security
|
|
9
|
+
Fixes from an internal review. The issues below were found in this release's code before it was published:
|
|
10
|
+
- **Attacker input could crash verification.** `verify_totp`, `verify_hotp`, `verify_checksum` and `verify_signed_token` raised `TypeError` on non-ASCII input (e.g. `١٢٣٤٥٦`), which surfaced as an HTTP 500. All verifiers now return False/None on any input.
|
|
11
|
+
- **`AttemptLimiter` could be bypassed with parallel requests.** The new atomic `hit()` counts an attempt before verification, and the docs now use it.
|
|
12
|
+
- **`AttemptLimiter` memory and CPU DoS.** It was O(n) per call after 100k keys and unbounded. It is now capped by `max_keys` with O(1) amortized eviction (expired entries first).
|
|
13
|
+
- **Short codes were stored with fast unsalted SHA-256.** OTPs reversed instantly from a leaked hash. OTPs and recovery codes now use salted PBKDF2-SHA256 (100k iterations, format `pbkdf2-sha256$...`).
|
|
14
|
+
- **Domain separation.** Tokens, hash peppers and derived keys use independent subkeys, so reusing one server secret can't forge across features.
|
|
15
|
+
- **Stricter inputs:**
|
|
16
|
+
- Empty peppers are rejected (they silently disabled the pepper before).
|
|
17
|
+
- TOTP secrets under 80 bits are rejected.
|
|
18
|
+
- Token secrets must be at least 16 characters.
|
|
19
|
+
- TOTP/HOTP `digits` is capped at 8, per the RFC.
|
|
20
|
+
- `:` is rejected in otpauth issuer/account.
|
|
21
|
+
- `inf`/`NaN` expiry is rejected.
|
|
22
|
+
- OTP `charset` is validated.
|
|
23
|
+
- Integer codes keep their leading zeros.
|
|
24
|
+
- Recovery codes must be at least 8 characters.
|
|
25
|
+
- **`repr(ApiKey)` is redacted** so keys don't leak into logs and tracebacks.
|
|
26
|
+
- **CLI secrets** can be passed via stdin (`-`) or `GENERATEAPIKEY_SECRET`, `GENERATEAPIKEY_PEPPER` and `GENERATEAPIKEY_TOTP_SECRET`, instead of argv.
|
|
27
|
+
- **CI hardening:**
|
|
28
|
+
- Read-only default permissions.
|
|
29
|
+
- Publishing moved to PyPI Trusted Publishing in a separate job, triggered on `release: published`.
|
|
30
|
+
- A bandit scan runs on every push.
|
|
31
|
+
- Dependabot is enabled.
|
|
32
|
+
- `SECURITY.md` has been added.
|
|
33
|
+
|
|
34
|
+
### Added: production extras
|
|
35
|
+
- **More frameworks:** Sanic, aiohttp, Quart and Falcon (WSGI and ASGI), each tested against the real framework.
|
|
36
|
+
- **Rotation:**
|
|
37
|
+
- Django `AbstractAPIKey.rotate(grace=...)` keeps the old key valid during a grace period.
|
|
38
|
+
- Pepper rotation via `APIKeyAuth(previous_peppers=..., on_rehash=...)`, plus the Django `rehash_model()` hook.
|
|
39
|
+
- **Session-bound tokens:** `generate_signed_token(..., context=session_id)` and the matching `verify_signed_token(..., context=...)`. A leaked link fails outside the session that requested it.
|
|
40
|
+
- **`generateapikey.crypto`** (`[crypto]`): `SecretBox` encrypts TOTP and other secrets at rest. AES-256-GCM, associated data, key rotation.
|
|
41
|
+
- **`generateapikey.limiters`** (`[redis]`): `RedisAttemptLimiter` and `AsyncRedisAttemptLimiter` share atomic counters across processes. `APIKeyAuth` accepts sync or async limiters.
|
|
42
|
+
- **Segment-aware `exclude` matching:** `/health` no longer also excludes `/healthz`.
|
|
43
|
+
- **Tooling:**
|
|
44
|
+
- Strict mypy across the core and ruff lint and format.
|
|
45
|
+
- pre-commit config, plus a `dev` extra.
|
|
46
|
+
- CI tests Python 3.9–3.14 on Linux, macOS and Windows, adds a zero-dependency job, and runs ruff, mypy and bandit.
|
|
47
|
+
- **Repo:** `examples/` (a full FastAPI app run in CI, and a Django quickstart), `benchmarks/bench.py`, CONTRIBUTING.md, and issue/PR templates.
|
|
48
|
+
|
|
49
|
+
### Added: framework integrations
|
|
50
|
+
- `generateapikey.integrations` holds the framework-agnostic core:
|
|
51
|
+
- `APIKeyAuth` handles header/Bearer extraction, prefix and checksum pre-checks, hash-only lookup, revoked/expired checks, optional rate limiting and an `on_success` hook. Lookups can be sync or async.
|
|
52
|
+
- `issue_api_key()` returns the key, its hash and a display hint.
|
|
53
|
+
- Adapters, each as an optional extra:
|
|
54
|
+
- **FastAPI**: `APIKeyDependency`, with an OpenAPI security scheme.
|
|
55
|
+
- **Starlette**: `APIKeyBackend`.
|
|
56
|
+
- **Django**: `AbstractAPIKey` model with `create_key`, `api_key_required` for sync and async views, `APIKeyMiddleware`, `model_lookup` and `touch_last_used`.
|
|
57
|
+
- **Django REST Framework**: `APIKeyAuthentication` and `HasAPIKey`.
|
|
58
|
+
- **Flask**: `require_api_key` and `FlaskAPIKey`.
|
|
59
|
+
- **Litestar**: `api_key_middleware`.
|
|
60
|
+
- Each adapter is tested against the real framework.
|
|
61
|
+
|
|
62
|
+
### Added: MFA
|
|
63
|
+
- **TOTP / HOTP** (RFC 6238 / 4226) in `generateapikey.mfa`: `generate_totp_secret`, `totp`, `totp_now`, `verify_totp`, `find_totp_step` (replay protection), `hotp`, `verify_hotp`, `totp_uri` and `hotp_uri` (`otpauth://` URIs for QR setup). Supports SHA-1/256/512, 6–10 digits and custom periods. Tested against the official RFC test vectors.
|
|
64
|
+
- **Recovery codes**: `generate_recovery_codes`, `hash_recovery_code`, `verify_recovery_code`. Crockford base32, single use, tolerant of case, dashes and look-alike characters.
|
|
65
|
+
- **Email/SMS one-time codes**: `generate_otp`, `hash_otp`, `verify_otp`.
|
|
66
|
+
- **Signed tokens** for magic links, email verification and password resets, in `generateapikey.tokens`: `generate_signed_token`, `verify_signed_token`. HMAC-SHA256, with expiry, purpose binding and a unique `jti`.
|
|
67
|
+
- **`AttemptLimiter`**: thread-safe, in-memory brute-force guard.
|
|
68
|
+
- **QR codes** (`pip install "generateapikey[qr]"`): `qr_svg`, `qr_png`, `qr_ascii` in `generateapikey.qr`.
|
|
69
|
+
- CLI subcommands: `totp` (with `--qr`), `code`, `recovery`, `otp`, `token`. A `generateapikey` command alias is also installed.
|
|
70
|
+
|
|
71
|
+
### Added: AI coding agent support
|
|
72
|
+
- `llms.txt` index and a full `llms-full.txt` guide. The guide ships in the wheel and is printed by `generate-api-key --llms`.
|
|
73
|
+
- A drop-in Agent Skill (`skills/generateapikey/SKILL.md`), `AGENTS.md` for contributors, and `context7.json`.
|
|
74
|
+
- Tests that fail if the documented imports drift from the real API.
|
|
75
|
+
|
|
76
|
+
### Added: API keys
|
|
77
|
+
- `checksum=True`: appends a 6-char CRC32 (base62) to the key. Check it offline with `verify_checksum()`.
|
|
78
|
+
- `hash_api_key()` / `verify_api_key()`: SHA-256 storage hashing, with optional HMAC pepper and constant-time verification. `ApiKey.hash()` is a shortcut.
|
|
79
|
+
- `generate_api_keys(count, ...)` for batches.
|
|
80
|
+
- `entropy_bits()`, the `min_entropy=` option, and `WeakKeyWarning` for random keys below 128 bits.
|
|
81
|
+
- `expiry` accepts a `timedelta` or fractional minutes.
|
|
82
|
+
- `ApiKey.expires_in` and `ApiKey.expires_at_datetime`. `ApiKey` now pickles with its expiry and has an informative `repr`.
|
|
83
|
+
- `dash_char=` option.
|
|
84
|
+
- New charsets: `base32`, `crockford`, `unambiguous`.
|
|
85
|
+
- `generate-api-key` command-line tool (also `python -m generateApiKey`).
|
|
86
|
+
- `__version__`, `py.typed`, a test CI matrix (3.9–3.13, Linux/macOS/Windows), and `pyproject.toml`.
|
|
87
|
+
|
|
88
|
+
### Changed
|
|
89
|
+
- **Derived keys (`secret` + `seed`) are now deterministic**: the same inputs give the same key. Previously a random salt and a timestamp made every call different, so the secret had no effect on the result. The legacy `generateApiKey()` keeps its old one-key-per-call behaviour.
|
|
90
|
+
- Character sampling uses rejection sampling, so it is unbiased. It is also about 20× faster.
|
|
91
|
+
- Removed the unused `cryptography` dependency. The package now has zero dependencies.
|
|
92
|
+
|
|
93
|
+
### Fixed
|
|
94
|
+
- Modulo bias in derived keys: some characters were about 25% more likely.
|
|
95
|
+
- Duplicate characters in a custom charset skewed the output.
|
|
96
|
+
- `expiry=0` was silently ignored, and negative expiry was accepted.
|
|
97
|
+
- Empty `secret`/`seed` strings silently fell back to random keys.
|
|
98
|
+
- `include` without `secret`/`seed` was silently ignored.
|
|
99
|
+
- `case="lower"`/`"upper"` on `base58` re-introduced look-alike characters.
|
|
100
|
+
|
|
101
|
+
### Deprecated
|
|
102
|
+
- `is_token_valid()`: no API ever produced the token format it checks. Use `ApiKey.is_expired` instead.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for helping! Bug reports, docs fixes, new framework adapters and features are all welcome.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/nuhmanpk/generate-api-key
|
|
9
|
+
cd generate-api-key
|
|
10
|
+
python -m venv .venv && source .venv/bin/activate
|
|
11
|
+
pip install -e ".[dev]"
|
|
12
|
+
pre-commit install
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Checks (CI runs the same)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pytest -q # all tests, all frameworks
|
|
19
|
+
ruff check . && ruff format --check .
|
|
20
|
+
mypy # strict
|
|
21
|
+
bandit -q -r generateapikey generateApiKey.py
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Guidelines
|
|
25
|
+
|
|
26
|
+
- **No runtime dependencies.** Anything third-party goes behind an optional extra and a lazy import.
|
|
27
|
+
- **Security first.** Use `secrets` for randomness and `utils.safe_equals` for comparisons. Verifiers must return False/None on bad input, never raise. Add a test with hostile input.
|
|
28
|
+
- **Framework adapters stay thin.** Logic belongs in `generateapikey/integrations/__init__.py`. Test each adapter against the real framework, guarded by `pytest.importorskip`.
|
|
29
|
+
- **Docs:** when you change the public API, update `README.md`, `generateapikey/llms-full.txt` (the guide AI agents read) and `CHANGELOG.md`. `tests/test_docs.py` fails if a documented import doesn't exist.
|
|
30
|
+
- Supports Python 3.9+.
|
|
31
|
+
|
|
32
|
+
## Security issues
|
|
33
|
+
|
|
34
|
+
Please report them privately. See [SECURITY.md](SECURITY.md).
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
include README.md LICENSE CHANGELOG.md llms.txt AGENTS.md CONTRIBUTING.md SECURITY.md
|
|
2
|
+
include generateapikey/py.typed generateapikey/llms-full.txt
|
|
3
|
+
recursive-include tests *.py
|
|
4
|
+
recursive-include examples *.py *.md
|
|
5
|
+
recursive-include benchmarks *.py
|
|
6
|
+
recursive-include skills *.md
|