tina4-python 3.13.19__tar.gz → 3.13.21__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.
- {tina4_python-3.13.19 → tina4_python-3.13.21}/PKG-INFO +1 -1
- {tina4_python-3.13.19 → tina4_python-3.13.21}/pyproject.toml +1 -1
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/CLAUDE.md +2 -2
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/__init__.py +1 -1
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/auth/__init__.py +42 -20
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/core/middleware.py +4 -4
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/frond/engine.py +2 -2
- {tina4_python-3.13.19 → tina4_python-3.13.21}/.gitignore +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/README.md +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/Testing.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/cli/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/core/events.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/core/rate_limiter.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/core/request.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/core/response.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/core/router.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/core/server.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/database/connection.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/database/mongodb.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/dev_admin/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/dev_admin/plan.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/dev_admin/project_index.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/docs.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/env.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/orm/model.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/__feedback/widget.js +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/js/frond.js +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/js/tina4-dev-admin.js +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/queue/job.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/queue/kafka_backend.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/queue/lite_backend.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/queue/mongo_backend.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/queue/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/test/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -1590,7 +1590,7 @@ Key `.env` settings:
|
|
|
1590
1590
|
|
|
1591
1591
|
```bash
|
|
1592
1592
|
# Authentication
|
|
1593
|
-
|
|
1593
|
+
TINA4_SECRET=your-jwt-secret # JWT signing (warns + uses a blank, insecure secret if unset)
|
|
1594
1594
|
TINA4_API_KEY=your-api-key # Static bearer token for API auth (API_KEY fallback supported)
|
|
1595
1595
|
TINA4_TOKEN_LIMIT=60 # Token lifetime in minutes (default: 60)
|
|
1596
1596
|
|
|
@@ -1836,7 +1836,7 @@ async def dashboard(request, response):
|
|
|
1836
1836
|
## v3 Features Summary
|
|
1837
1837
|
|
|
1838
1838
|
- **55 built-in features**, zero third-party dependencies
|
|
1839
|
-
- **2,
|
|
1839
|
+
- **2,857 tests** passing across all modules
|
|
1840
1840
|
- **Production server auto-detect**: `tina4python serve --production` auto-installs uvicorn
|
|
1841
1841
|
- **`tina4python generate`**: model, route, migration, middleware scaffolding
|
|
1842
1842
|
- **Database**: 5 engines (SQLite, PostgreSQL, MySQL, MSSQL, Firebird), query caching (`TINA4_DB_CACHE=true`, `cache_stats()`, `cache_clear()`)
|
|
@@ -29,7 +29,7 @@ import functools
|
|
|
29
29
|
class _DualMethod:
|
|
30
30
|
"""Descriptor that makes a method callable on both the class and an instance.
|
|
31
31
|
|
|
32
|
-
- ``Auth.get_token(payload)`` — creates a temporary Auth() using env
|
|
32
|
+
- ``Auth.get_token(payload)`` — creates a temporary Auth() using env TINA4_SECRET
|
|
33
33
|
- ``auth.get_token(payload)`` — uses the instance's own secret / settings
|
|
34
34
|
"""
|
|
35
35
|
|
|
@@ -42,13 +42,35 @@ class _DualMethod:
|
|
|
42
42
|
# Called on the class: Auth.get_token(payload, ...)
|
|
43
43
|
@functools.wraps(self._func)
|
|
44
44
|
def _class_call(*args, **kwargs):
|
|
45
|
-
inst = cls() # Auth() reads
|
|
45
|
+
inst = cls() # Auth() reads TINA4_SECRET from env
|
|
46
46
|
return self._func(inst, *args, **kwargs)
|
|
47
47
|
return _class_call
|
|
48
48
|
# Called on an instance: auth_instance.get_token(payload, ...)
|
|
49
49
|
return functools.partial(self._func, obj)
|
|
50
50
|
|
|
51
51
|
|
|
52
|
+
def _resolve_secret(secret: str = None) -> str:
|
|
53
|
+
"""Resolve the JWT signing secret.
|
|
54
|
+
|
|
55
|
+
Reads ``TINA4_SECRET`` from the environment. When neither an explicit
|
|
56
|
+
secret nor ``TINA4_SECRET`` is set, warns loudly and returns a blank
|
|
57
|
+
secret — parity with the PHP/Node frameworks. Tina4 never silently signs
|
|
58
|
+
with a guessable built-in default, which would make tokens forgeable.
|
|
59
|
+
"""
|
|
60
|
+
if secret:
|
|
61
|
+
return secret
|
|
62
|
+
env_secret = os.environ.get("TINA4_SECRET", "")
|
|
63
|
+
if not env_secret:
|
|
64
|
+
try:
|
|
65
|
+
from tina4_python.debug import Log
|
|
66
|
+
Log.warning("Auth: TINA4_SECRET not set in .env — using blank secret (insecure)")
|
|
67
|
+
except Exception:
|
|
68
|
+
import sys
|
|
69
|
+
print("Auth: TINA4_SECRET not set in .env — using blank secret (insecure)", file=sys.stderr)
|
|
70
|
+
return ""
|
|
71
|
+
return env_secret
|
|
72
|
+
|
|
73
|
+
|
|
52
74
|
class Auth:
|
|
53
75
|
"""JWT authentication and password hashing — zero dependencies."""
|
|
54
76
|
|
|
@@ -56,11 +78,11 @@ class Auth:
|
|
|
56
78
|
expires_in: int = None):
|
|
57
79
|
"""
|
|
58
80
|
Args:
|
|
59
|
-
secret: Signing secret (falls back to
|
|
81
|
+
secret: Signing secret (falls back to the TINA4_SECRET env var).
|
|
60
82
|
algorithm: JWT algorithm (default HS256).
|
|
61
83
|
expires_in: Token lifetime in seconds (default 3600).
|
|
62
84
|
"""
|
|
63
|
-
self.secret = secret
|
|
85
|
+
self.secret = secret if secret is not None else _resolve_secret()
|
|
64
86
|
self.algorithm = algorithm
|
|
65
87
|
# JWT expiry env var:
|
|
66
88
|
# - TINA4_TOKEN_EXPIRES_IN (preferred — matches docs and the
|
|
@@ -80,7 +102,7 @@ class Auth:
|
|
|
80
102
|
|
|
81
103
|
Args:
|
|
82
104
|
expires_in: Lifetime in minutes (default: self.expires_in).
|
|
83
|
-
secret: Override signing secret (default: self.secret /
|
|
105
|
+
secret: Override signing secret (default: self.secret / TINA4_SECRET env var).
|
|
84
106
|
|
|
85
107
|
Returns: header.payload.signature
|
|
86
108
|
"""
|
|
@@ -176,36 +198,36 @@ class Auth:
|
|
|
176
198
|
|
|
177
199
|
# get_token and valid_token are the primary names
|
|
178
200
|
|
|
179
|
-
# ── Class-level convenience methods (read
|
|
201
|
+
# ── Class-level convenience methods (read TINA4_SECRET from env) ────
|
|
180
202
|
|
|
181
203
|
@classmethod
|
|
182
204
|
def get_token_static(cls, payload: dict, expires_in: int = 60) -> str:
|
|
183
|
-
"""Create a JWT without instantiating Auth — reads
|
|
184
|
-
secret =
|
|
205
|
+
"""Create a JWT without instantiating Auth — reads TINA4_SECRET from env."""
|
|
206
|
+
secret = _resolve_secret()
|
|
185
207
|
auth = cls(secret=secret, expires_in=expires_in)
|
|
186
208
|
return auth.get_token(payload)
|
|
187
209
|
|
|
188
210
|
@classmethod
|
|
189
211
|
def valid_token_static(cls, token: str) -> "dict | None":
|
|
190
|
-
"""Validate a JWT without instantiating Auth — reads
|
|
212
|
+
"""Validate a JWT without instantiating Auth — reads TINA4_SECRET from env.
|
|
191
213
|
|
|
192
214
|
Returns the decoded payload on success, ``None`` on failure.
|
|
193
215
|
"""
|
|
194
|
-
secret =
|
|
216
|
+
secret = _resolve_secret()
|
|
195
217
|
auth = cls(secret=secret)
|
|
196
218
|
return auth.valid_token(token)
|
|
197
219
|
|
|
198
220
|
@classmethod
|
|
199
221
|
def get_payload_static(cls, token: str) -> dict | None:
|
|
200
222
|
"""Decode payload (no validation) without instantiating Auth."""
|
|
201
|
-
secret =
|
|
223
|
+
secret = _resolve_secret()
|
|
202
224
|
auth = cls(secret=secret)
|
|
203
225
|
return auth.get_payload(token)
|
|
204
226
|
|
|
205
227
|
@classmethod
|
|
206
228
|
def refresh_token_static(cls, token: str, expires_in: int = 60) -> str | None:
|
|
207
|
-
"""Refresh a JWT without instantiating Auth — reads
|
|
208
|
-
secret =
|
|
229
|
+
"""Refresh a JWT without instantiating Auth — reads TINA4_SECRET from env."""
|
|
230
|
+
secret = _resolve_secret()
|
|
209
231
|
auth = cls(secret=secret, expires_in=expires_in)
|
|
210
232
|
return auth.refresh_token(token)
|
|
211
233
|
|
|
@@ -213,10 +235,10 @@ class Auth:
|
|
|
213
235
|
def authenticate_request_static(cls, headers: dict) -> dict | None:
|
|
214
236
|
"""Extract and validate auth from request headers without instantiating Auth.
|
|
215
237
|
|
|
216
|
-
Reads
|
|
238
|
+
Reads TINA4_SECRET from env. Checks: Bearer JWT, Bearer API key, Basic auth.
|
|
217
239
|
Returns payload dict on success, None on failure.
|
|
218
240
|
"""
|
|
219
|
-
secret =
|
|
241
|
+
secret = _resolve_secret()
|
|
220
242
|
auth = cls(secret=secret)
|
|
221
243
|
return auth.authenticate_request(headers)
|
|
222
244
|
|
|
@@ -281,7 +303,7 @@ class Auth:
|
|
|
281
303
|
"""Extract and validate auth from request headers.
|
|
282
304
|
|
|
283
305
|
Args:
|
|
284
|
-
secret: Override signing secret (default: self.secret /
|
|
306
|
+
secret: Override signing secret (default: self.secret / TINA4_SECRET env var).
|
|
285
307
|
algorithm: JWT algorithm override (default: "HS256").
|
|
286
308
|
|
|
287
309
|
Checks: Bearer JWT, Bearer API key, Basic auth.
|
|
@@ -324,14 +346,14 @@ def _b64url_decode(s: str) -> bytes:
|
|
|
324
346
|
# ── Module-level convenience functions (use static methods) ────
|
|
325
347
|
|
|
326
348
|
def get_token(payload: dict, expires_in: int = 60, secret: str = None) -> str:
|
|
327
|
-
"""Create a JWT — reads
|
|
349
|
+
"""Create a JWT — reads TINA4_SECRET from env. Shortcut for Auth.get_token_static()."""
|
|
328
350
|
if secret is not None:
|
|
329
351
|
return Auth(secret=secret).get_token(payload, expires_in=expires_in)
|
|
330
352
|
return Auth.get_token_static(payload, expires_in=expires_in)
|
|
331
353
|
|
|
332
354
|
|
|
333
355
|
def valid_token(token: str) -> "dict | None":
|
|
334
|
-
"""Validate a JWT signature and expiry — reads
|
|
356
|
+
"""Validate a JWT signature and expiry — reads TINA4_SECRET from env.
|
|
335
357
|
|
|
336
358
|
Returns the decoded payload dict on success, ``None`` on failure.
|
|
337
359
|
The truthy/falsy split keeps legacy ``if valid_token(t):`` code working
|
|
@@ -346,12 +368,12 @@ def get_payload(token: str) -> dict | None:
|
|
|
346
368
|
|
|
347
369
|
|
|
348
370
|
def refresh_token(token: str, expires_in: int = 60) -> str | None:
|
|
349
|
-
"""Refresh a JWT — reads
|
|
371
|
+
"""Refresh a JWT — reads TINA4_SECRET from env. Shortcut for Auth.refresh_token_static()."""
|
|
350
372
|
return Auth.refresh_token_static(token, expires_in=expires_in)
|
|
351
373
|
|
|
352
374
|
|
|
353
375
|
def authenticate_request(headers: dict, secret: str = None, algorithm: str = "HS256") -> dict | None:
|
|
354
|
-
"""Validate auth from request headers — reads
|
|
376
|
+
"""Validate auth from request headers — reads TINA4_SECRET from env."""
|
|
355
377
|
if secret is not None:
|
|
356
378
|
return Auth(secret=secret).authenticate_request(headers, algorithm=algorithm)
|
|
357
379
|
return Auth.authenticate_request_static(headers)
|
|
@@ -286,8 +286,8 @@ class CsrfMiddleware:
|
|
|
286
286
|
if auth_header.startswith("Bearer "):
|
|
287
287
|
bearer_token = auth_header[7:].strip()
|
|
288
288
|
if bearer_token:
|
|
289
|
-
from tina4_python.auth import Auth as _CsrfAuth
|
|
290
|
-
secret =
|
|
289
|
+
from tina4_python.auth import Auth as _CsrfAuth, _resolve_secret
|
|
290
|
+
secret = _resolve_secret()
|
|
291
291
|
auth = _CsrfAuth(secret=secret)
|
|
292
292
|
if auth.valid_token(bearer_token):
|
|
293
293
|
return request, response
|
|
@@ -325,8 +325,8 @@ class CsrfMiddleware:
|
|
|
325
325
|
)
|
|
326
326
|
|
|
327
327
|
# Validate the token
|
|
328
|
-
from tina4_python.auth import Auth as _CsrfAuth
|
|
329
|
-
secret =
|
|
328
|
+
from tina4_python.auth import Auth as _CsrfAuth, _resolve_secret
|
|
329
|
+
secret = _resolve_secret()
|
|
330
330
|
auth = _CsrfAuth(secret=secret)
|
|
331
331
|
if not auth.valid_token(token):
|
|
332
332
|
return request, response.error(
|
|
@@ -15,7 +15,7 @@ from functools import lru_cache
|
|
|
15
15
|
from pathlib import Path
|
|
16
16
|
from datetime import datetime
|
|
17
17
|
|
|
18
|
-
from tina4_python.auth import Auth as _FrondAuth
|
|
18
|
+
from tina4_python.auth import Auth as _FrondAuth, _resolve_secret
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class SafeString(str):
|
|
@@ -1173,7 +1173,7 @@ def _generate_form_jwt(descriptor: str = "", session_id: str = "") -> str:
|
|
|
1173
1173
|
if sid:
|
|
1174
1174
|
payload["session_id"] = sid
|
|
1175
1175
|
|
|
1176
|
-
secret =
|
|
1176
|
+
secret = _resolve_secret()
|
|
1177
1177
|
ttl = int(os.environ.get("TINA4_TOKEN_EXPIRES_IN", "60"))
|
|
1178
1178
|
auth = _FrondAuth(secret=secret, expires_in=ttl)
|
|
1179
1179
|
return auth.get_token(payload)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/images/tina4-logo-icon.webp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/public/swagger/oauth2-redirect.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/queue_backends/rabbitmq_backend.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/session_handlers/mongodb_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/session_handlers/redis_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/session_handlers/valkey_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/docker/distroless/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/docker/poetry/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/templates/docker/python/Dockerfile
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.19 → tina4_python-3.13.21}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|