tina4-python 3.13.91__tar.gz → 3.13.92__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.91 → tina4_python-3.13.92}/PKG-INFO +1 -1
- {tina4_python-3.13.91 → tina4_python-3.13.92}/pyproject.toml +1 -1
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/auth/__init__.py +68 -10
- {tina4_python-3.13.91 → tina4_python-3.13.92}/.gitignore +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/README.md +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/CLAUDE.md +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/Testing.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/cli/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/context/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/context/chunker.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/core/events.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/core/rate_limiter.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/core/request.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/core/response.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/core/router.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/core/server.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/database/connection.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/database/mongodb.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/dev_admin/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/dev_admin/metrics_engine.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/dev_admin/plan.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/dev_admin/project_index.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/docs.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/docstore/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/env.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/frond/compiler.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/frond/parser.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/mqtt/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/mqtt/message.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/orm/model.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/public/__feedback/widget.js +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/public/js/frond.js +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/queue/job.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/queue/kafka_backend.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/queue/lite_backend.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/queue/mongo_backend.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/queue/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/realtime/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/realtime/models/Attachment.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/realtime/models/Channel.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/realtime/models/ChannelMember.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/realtime/models/Message.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/realtime/models/Workspace.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/realtime/models/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/realtime/storage.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/_pagination.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/session/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/test/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -196,19 +196,51 @@ def _resolve_secret(secret: str = None) -> str:
|
|
|
196
196
|
return env_secret
|
|
197
197
|
|
|
198
198
|
|
|
199
|
+
# Supported JWT algorithms. HMAC only — the whole family is in hashlib, so this
|
|
200
|
+
# stays zero-dependency. The header's "alg" is now always the one we actually sign
|
|
201
|
+
# with (python#105): the digest is looked up here rather than hardcoded.
|
|
202
|
+
_HMAC_ALGORITHMS = {
|
|
203
|
+
"HS256": hashlib.sha256,
|
|
204
|
+
"HS384": hashlib.sha384,
|
|
205
|
+
"HS512": hashlib.sha512,
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
# Seconds of clock skew tolerated on the "nbf" (not-before) claim. Without this a
|
|
209
|
+
# token minted on one host and validated on another a second behind is rejected
|
|
210
|
+
# for no real reason; RFC 7519 explicitly allows "a small leeway".
|
|
211
|
+
_JWT_LEEWAY_SECONDS = 60
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _resolve_algorithm(algorithm: str = None) -> str:
|
|
215
|
+
"""Pick the JWT algorithm: explicit arg, else TINA4_JWT_ALGORITHM, else HS256.
|
|
216
|
+
|
|
217
|
+
Raises ValueError naming the supported set when asked for one we cannot sign
|
|
218
|
+
(python#106 — the env var was registered in the CLI's known_vars and then
|
|
219
|
+
silently ignored, so a user could set HS512 and still get HS256 tokens).
|
|
220
|
+
"""
|
|
221
|
+
chosen = (algorithm or os.environ.get("TINA4_JWT_ALGORITHM") or "HS256").strip()
|
|
222
|
+
if chosen not in _HMAC_ALGORITHMS:
|
|
223
|
+
raise ValueError(
|
|
224
|
+
f"Unsupported JWT algorithm {chosen!r}. Tina4 signs with "
|
|
225
|
+
f"{', '.join(sorted(_HMAC_ALGORITHMS))} (HMAC only, zero-dependency). "
|
|
226
|
+
f"Set TINA4_JWT_ALGORITHM to one of those."
|
|
227
|
+
)
|
|
228
|
+
return chosen
|
|
229
|
+
|
|
230
|
+
|
|
199
231
|
class Auth:
|
|
200
232
|
"""JWT authentication and password hashing — zero dependencies."""
|
|
201
233
|
|
|
202
|
-
def __init__(self, secret: str = None, algorithm: str =
|
|
234
|
+
def __init__(self, secret: str = None, algorithm: str = None,
|
|
203
235
|
expires_in: int = None):
|
|
204
236
|
"""
|
|
205
237
|
Args:
|
|
206
238
|
secret: Signing secret (falls back to the TINA4_SECRET env var).
|
|
207
|
-
algorithm: JWT algorithm (
|
|
239
|
+
algorithm: JWT algorithm (falls back to TINA4_JWT_ALGORITHM, then HS256).
|
|
208
240
|
expires_in: Token lifetime in seconds (default 3600).
|
|
209
241
|
"""
|
|
210
242
|
self.secret = secret if secret is not None else _resolve_secret()
|
|
211
|
-
self.algorithm = algorithm
|
|
243
|
+
self.algorithm = _resolve_algorithm(algorithm)
|
|
212
244
|
# JWT expiry env var:
|
|
213
245
|
# - TINA4_TOKEN_EXPIRES_IN (preferred — matches docs and the
|
|
214
246
|
# form-token expiry env var used by Frond)
|
|
@@ -275,13 +307,29 @@ class Auth:
|
|
|
275
307
|
return None
|
|
276
308
|
|
|
277
309
|
h, p, sig = parts
|
|
310
|
+
|
|
311
|
+
# Pin the algorithm to OUR configured one instead of trusting the
|
|
312
|
+
# token's header. A token asking to be verified as anything else --
|
|
313
|
+
# "none", a weaker HMAC, or an RSA alg we do not implement -- is
|
|
314
|
+
# rejected before any signature work. Matches the Ruby check.
|
|
315
|
+
header = json.loads(_b64url_decode(h))
|
|
316
|
+
if header.get("alg") != self.algorithm:
|
|
317
|
+
return None
|
|
318
|
+
|
|
278
319
|
expected = self._sign(f"{h}.{p}")
|
|
279
320
|
if not hmac.compare_digest(sig, expected):
|
|
280
321
|
return None
|
|
281
322
|
|
|
282
323
|
payload = json.loads(_b64url_decode(p))
|
|
283
324
|
|
|
284
|
-
|
|
325
|
+
now = time.time()
|
|
326
|
+
if "exp" in payload and now > payload["exp"]:
|
|
327
|
+
return None
|
|
328
|
+
|
|
329
|
+
# "nbf" (not-before): a post-dated token is not valid yet. Was
|
|
330
|
+
# honoured only by Ruby, so Python/PHP/Node accepted tokens their
|
|
331
|
+
# issuer had explicitly marked as not-yet-usable (python#107).
|
|
332
|
+
if "nbf" in payload and now + _JWT_LEEWAY_SECONDS < payload["nbf"]:
|
|
285
333
|
return None
|
|
286
334
|
|
|
287
335
|
return payload
|
|
@@ -314,8 +362,10 @@ class Auth:
|
|
|
314
362
|
return self.get_token(payload, expires_in=expires_in)
|
|
315
363
|
|
|
316
364
|
def _sign(self, message: str) -> str:
|
|
365
|
+
# Digest comes from the configured algorithm, so the "alg" we advertise in
|
|
366
|
+
# the header is the one that actually produced this signature.
|
|
317
367
|
sig = hmac.new(
|
|
318
|
-
self.secret.encode(), message.encode(),
|
|
368
|
+
self.secret.encode(), message.encode(), _HMAC_ALGORITHMS[self.algorithm]
|
|
319
369
|
).digest()
|
|
320
370
|
return _b64url_encode(sig)
|
|
321
371
|
|
|
@@ -424,16 +474,24 @@ class Auth:
|
|
|
424
474
|
# ── Request Auth Helper ───────────────────────────────────────
|
|
425
475
|
|
|
426
476
|
@_DualMethod
|
|
427
|
-
def authenticate_request(self, headers: dict, secret: str = None, algorithm: str =
|
|
477
|
+
def authenticate_request(self, headers: dict, secret: str = None, algorithm: str = None) -> dict | None:
|
|
428
478
|
"""Extract and validate auth from request headers.
|
|
429
479
|
|
|
430
480
|
Args:
|
|
431
481
|
secret: Override signing secret (default: self.secret / TINA4_SECRET env var).
|
|
432
|
-
algorithm: JWT algorithm override (default:
|
|
482
|
+
algorithm: JWT algorithm override (default: self.algorithm / TINA4_JWT_ALGORITHM).
|
|
433
483
|
|
|
434
484
|
Checks: Bearer JWT, Bearer API key, Basic auth.
|
|
435
485
|
Returns payload dict on success, None on failure.
|
|
436
486
|
"""
|
|
487
|
+
# Both overrides used to be accepted and then dropped on the floor: the
|
|
488
|
+
# body called self.valid_token(), so a caller passing secret= or
|
|
489
|
+
# algorithm= silently got this instance's values instead. Honour them.
|
|
490
|
+
if secret is not None or algorithm is not None:
|
|
491
|
+
return Auth(secret=secret if secret is not None else self.secret,
|
|
492
|
+
algorithm=algorithm or self.algorithm,
|
|
493
|
+
expires_in=self.expires_in).authenticate_request(headers)
|
|
494
|
+
|
|
437
495
|
auth_header = headers.get("authorization", "")
|
|
438
496
|
|
|
439
497
|
if auth_header.startswith("Bearer "):
|
|
@@ -497,10 +555,10 @@ def refresh_token(token: str, expires_in: int = 60) -> str | None:
|
|
|
497
555
|
return Auth.refresh_token_static(token, expires_in=expires_in)
|
|
498
556
|
|
|
499
557
|
|
|
500
|
-
def authenticate_request(headers: dict, secret: str = None, algorithm: str =
|
|
558
|
+
def authenticate_request(headers: dict, secret: str = None, algorithm: str = None) -> dict | None:
|
|
501
559
|
"""Validate auth from request headers — reads TINA4_SECRET from env."""
|
|
502
|
-
if secret is not None:
|
|
503
|
-
return Auth(secret=secret
|
|
560
|
+
if secret is not None or algorithm is not None:
|
|
561
|
+
return Auth(secret=secret, algorithm=algorithm).authenticate_request(headers)
|
|
504
562
|
return Auth.authenticate_request_static(headers)
|
|
505
563
|
|
|
506
564
|
|
|
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
|
|
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.91 → tina4_python-3.13.92}/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
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/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.91 → tina4_python-3.13.92}/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
|
|
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.91 → tina4_python-3.13.92}/tina4_python/session_handlers/mongodb_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/session_handlers/redis_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/session_handlers/valkey_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/docker/distroless/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/templates/docker/poetry/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/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.91 → tina4_python-3.13.92}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.91 → tina4_python-3.13.92}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|