tina4-python 3.13.77__tar.gz → 3.13.79__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.77 → tina4_python-3.13.79}/PKG-INFO +1 -1
- {tina4_python-3.13.77 → tina4_python-3.13.79}/pyproject.toml +1 -1
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/CLAUDE.md +13 -13
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/core/request.py +33 -9
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/core/server.py +18 -6
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/session/__init__.py +40 -4
- {tina4_python-3.13.77 → tina4_python-3.13.79}/.gitignore +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/README.md +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/Testing.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/ai/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/api/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/auth/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/cache/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/cli/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/container/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/context/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/context/chunker.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/core/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/core/cache.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/core/constants.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/core/events.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/core/middleware.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/core/rate_limiter.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/core/response.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/core/router.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/crud/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/database/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/database/adapter.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/database/connection.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/database/firebird.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/database/mongodb.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/database/mssql.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/database/mysql.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/database/odbc.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/database/postgres.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/database/sqlite.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/debug/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/debug/error_overlay.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/dev_admin/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/dev_admin/metrics.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/dev_admin/plan.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/dev_admin/project_index.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/docs.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/docstore/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/dotenv/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/env.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/frond/FROND.md +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/frond/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/frond/engine.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/auth/meta.json +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/auth/src/routes/api/gallery_auth.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/database/meta.json +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/database/src/routes/api/gallery_db.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/error-overlay/meta.json +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/error-overlay/src/routes/api/gallery_crash.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/orm/meta.json +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/orm/src/orm/Product.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/orm/src/routes/api/gallery_products.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/queue/meta.json +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/queue/src/routes/api/gallery_queue.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/rest-api/meta.json +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/rest-api/src/routes/api/gallery_hello.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/templates/meta.json +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/templates/src/routes/gallery_page.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/gallery/templates/src/templates/gallery_page.twig +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/graphql/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/i18n/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/mcp/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/mcp/protocol.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/mcp/tools.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/messenger/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/migration/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/migration/runner.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/orm/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/orm/fields.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/orm/model.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/public/__feedback/widget.js +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/public/css/tina4.css +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/public/css/tina4.min.css +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/public/images/logo.svg +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/public/images/tina4-logo-icon.webp +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/public/js/frond.js +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/public/js/frond.min.js +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/public/js/tina4-dev-admin.js +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/public/js/tina4-dev-admin.min.js +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/public/js/tina4.min.js +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/public/js/tina4js.min.js +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/query_builder/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/queue/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/queue/job.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/queue/kafka_backend.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/queue/lite_backend.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/queue/mongo_backend.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/queue/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/queue_backends/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/queue_backends/kafka_backend.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/queue_backends/mongo_backend.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/queue_backends/rabbitmq_backend.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/realtime/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/realtime/models/Attachment.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/realtime/models/Channel.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/realtime/models/ChannelMember.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/realtime/models/Message.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/realtime/models/Workspace.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/realtime/models/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/realtime/storage.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/_alerts.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/_badges.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/_buttons.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/_cards.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/_forms.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/_grid.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/_modals.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/_nav.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/_reset.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/_tables.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/_typography.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/_utilities.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/_variables.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/base.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/colors.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/scss/tina4css/tina4.scss +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/seeder/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/service/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/session_handlers/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/session_handlers/mongodb_handler.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/session_handlers/redis_handler.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/session_handlers/valkey_handler.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/swagger/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/docker/distroless/Dockerfile +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/docker/poetry/Dockerfile +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/docker/python/Dockerfile +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/docker/uv/Dockerfile +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/errors/302.twig +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/errors/401.twig +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/errors/502.twig +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/errors/503.twig +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/errors/base.twig +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/frontend/README.md +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/readme.md +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/test/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/test_client/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/validator/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/websocket/__init__.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/websocket/backplane.py +0 -0
- {tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/wsdl/__init__.py +0 -0
|
@@ -514,23 +514,23 @@ TINA4_TOKEN_LIMIT is used to set the session time, default 60 minutes
|
|
|
514
514
|
|
|
515
515
|
Set `TINA4_SESSION_BACKEND` to choose a backend:
|
|
516
516
|
|
|
517
|
-
|
|
517
|
+
The value is the backend NAME, not a class name. An unknown value falls back to
|
|
518
|
+
the file backend without raising.
|
|
519
|
+
|
|
520
|
+
| Value | Backend | Required package |
|
|
518
521
|
|---------|---------|-----------------|
|
|
519
|
-
| `
|
|
520
|
-
| `
|
|
521
|
-
| `
|
|
522
|
-
| `
|
|
522
|
+
| `file` (default) | File system | none |
|
|
523
|
+
| `redis` | Redis | `redis` |
|
|
524
|
+
| `valkey` | Valkey | `valkey` |
|
|
525
|
+
| `mongodb` | MongoDB | `pymongo` |
|
|
526
|
+
| `database` | Your ORM DB | none |
|
|
523
527
|
|
|
524
528
|
#### MongoDB session env vars
|
|
525
529
|
|
|
526
530
|
```bash
|
|
527
|
-
TINA4_SESSION_BACKEND=
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
TINA4_SESSION_MONGO_URI= # full URI (overrides host/port)
|
|
531
|
-
TINA4_SESSION_MONGO_USERNAME= # optional
|
|
532
|
-
TINA4_SESSION_MONGO_PASSWORD= # optional
|
|
533
|
-
TINA4_SESSION_MONGO_DB=tina4_sessions # default database
|
|
531
|
+
TINA4_SESSION_BACKEND=mongodb # backend NAME, not a class name
|
|
532
|
+
TINA4_SESSION_MONGO_URI=mongodb://localhost:27017 # connection URI
|
|
533
|
+
TINA4_SESSION_MONGO_DB=tina4_sessions # default database
|
|
534
534
|
TINA4_SESSION_MONGO_COLLECTION=sessions # default collection
|
|
535
535
|
TINA4_SESSION_SAMESITE=Lax # SameSite attribute for session cookies (default: Lax)
|
|
536
536
|
```
|
|
@@ -1644,7 +1644,7 @@ TINA4_OVERRIDE_CLIENT=false # Set to true to allow running without tina4 C
|
|
|
1644
1644
|
HOST_NAME=localhost:7145
|
|
1645
1645
|
|
|
1646
1646
|
# Sessions
|
|
1647
|
-
TINA4_SESSION_BACKEND=
|
|
1647
|
+
TINA4_SESSION_BACKEND=file # file, redis, valkey, mongodb, database (unknown value falls back to file)
|
|
1648
1648
|
TINA4_SESSION_SAMESITE=Lax # SameSite attribute for session cookies (default: Lax)
|
|
1649
1649
|
|
|
1650
1650
|
# Swagger/OpenAPI
|
|
@@ -70,8 +70,8 @@ class Request:
|
|
|
70
70
|
"""Parsed HTTP request — everything a route handler needs."""
|
|
71
71
|
|
|
72
72
|
__slots__ = (
|
|
73
|
-
"method", "path", "url", "
|
|
74
|
-
"body", "raw_body", "cookies", "files", "ip", "remote_ip",
|
|
73
|
+
"method", "path", "url", "scheme", "query_string", "params", "query",
|
|
74
|
+
"headers", "body", "raw_body", "cookies", "files", "ip", "remote_ip",
|
|
75
75
|
"content_type", "session", "_route_params", "_handler",
|
|
76
76
|
)
|
|
77
77
|
|
|
@@ -79,6 +79,7 @@ class Request:
|
|
|
79
79
|
self.method: str = "GET"
|
|
80
80
|
self.path: str = "/"
|
|
81
81
|
self.url: str = "/"
|
|
82
|
+
self.scheme: str = "http" # Native connection scheme (see is_secure_scheme)
|
|
82
83
|
self.query_string: str = ""
|
|
83
84
|
self.params: dict = {} # Query string + route params merged
|
|
84
85
|
self.query: dict = {} # Query string params only (separate from route params)
|
|
@@ -97,6 +98,27 @@ class Request:
|
|
|
97
98
|
# middleware (e.g. CsrfMiddleware) can read
|
|
98
99
|
# handler metadata like _noauth.
|
|
99
100
|
|
|
101
|
+
def is_secure_scheme(self) -> bool:
|
|
102
|
+
"""True when the client's request scheme is https.
|
|
103
|
+
|
|
104
|
+
Proxy-aware: TLS is normally terminated at a proxy (nginx, HAProxy,
|
|
105
|
+
ALB, Cloudflare, most container deploys) which then forwards plain
|
|
106
|
+
HTTP, so the native ASGI scheme reads ``http`` on exactly the deploys
|
|
107
|
+
that ARE encrypted. ``x-forwarded-proto`` carries the scheme the
|
|
108
|
+
client actually used; the FIRST hop of a comma-separated chain
|
|
109
|
+
(``"https, http"``) is the client-facing one. Falls back to the
|
|
110
|
+
native connection scheme when no forwarded header is present.
|
|
111
|
+
|
|
112
|
+
This is the single source of truth for the URL scheme AND for the
|
|
113
|
+
Secure flag on the session cookie, so both agree instead of one
|
|
114
|
+
concluding ``https://`` while the other drops Secure (#95; mirrors
|
|
115
|
+
tina4-php ``Request::isSecureScheme()``, php#175).
|
|
116
|
+
"""
|
|
117
|
+
forwarded = self.headers.get("x-forwarded-proto", "")
|
|
118
|
+
if forwarded:
|
|
119
|
+
return forwarded.split(",")[0].strip().lower() == "https"
|
|
120
|
+
return (self.scheme or "").lower() == "https"
|
|
121
|
+
|
|
100
122
|
@classmethod
|
|
101
123
|
def from_scope(cls, scope: dict, body: bytes = b"") -> "Request":
|
|
102
124
|
"""Build a Request from an ASGI scope + body."""
|
|
@@ -117,14 +139,16 @@ class Request:
|
|
|
117
139
|
_client = scope.get("client")
|
|
118
140
|
req.remote_ip = _client[0] if _client else ""
|
|
119
141
|
|
|
142
|
+
# Native connection scheme (ASGI: "http"/"https"; TLS terminated at a
|
|
143
|
+
# proxy shows "http" here — x-forwarded-proto carries the real one).
|
|
144
|
+
req.scheme = scope.get("scheme") or "http"
|
|
145
|
+
|
|
120
146
|
# Reconstruct the full absolute URL — scheme://host[:port]/path[?query].
|
|
121
|
-
#
|
|
122
|
-
#
|
|
123
|
-
scheme
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
or "http"
|
|
127
|
-
)
|
|
147
|
+
# is_secure_scheme() is the single source of truth for the scheme (and
|
|
148
|
+
# for the session cookie's Secure flag): it honours x-forwarded-proto
|
|
149
|
+
# (first hop of a comma chain wins) then the native scheme, so an app
|
|
150
|
+
# behind a TLS-terminating proxy still sees https. PHP/Ruby/Node parity.
|
|
151
|
+
scheme = "https" if req.is_secure_scheme() else "http"
|
|
128
152
|
host = (
|
|
129
153
|
req.headers.get("x-forwarded-host")
|
|
130
154
|
or req.headers.get("host")
|
|
@@ -1108,8 +1108,13 @@ def _init_session(request: Request) -> None:
|
|
|
1108
1108
|
Session creation is skipped for WebSocket upgrade requests — they don't send
|
|
1109
1109
|
cookies and would create orphaned session files that are never cleaned up.
|
|
1110
1110
|
A session is only created when:
|
|
1111
|
-
- A
|
|
1111
|
+
- A session cookie is already present (resume existing session), OR
|
|
1112
1112
|
- The request is a normal HTTP request (not a WebSocket upgrade)
|
|
1113
|
+
|
|
1114
|
+
The incoming cookie is read by the SAME configured name the write side emits
|
|
1115
|
+
(``TINA4_SESSION_NAME``, default ``tina4_session``) via
|
|
1116
|
+
``session.session_cookie_name()`` — otherwise a renamed cookie would be
|
|
1117
|
+
written but never read back and the session would silently never resume.
|
|
1113
1118
|
"""
|
|
1114
1119
|
if request.session is not None:
|
|
1115
1120
|
return
|
|
@@ -1122,12 +1127,13 @@ def _init_session(request: Request) -> None:
|
|
|
1122
1127
|
return
|
|
1123
1128
|
|
|
1124
1129
|
try:
|
|
1125
|
-
from tina4_python.session import Session
|
|
1130
|
+
from tina4_python.session import Session, session_cookie_name
|
|
1126
1131
|
cookie_header = request.headers.get("cookie", "")
|
|
1127
1132
|
sid_match = None
|
|
1133
|
+
cookie_prefix = session_cookie_name() + "="
|
|
1128
1134
|
for part in cookie_header.split(";"):
|
|
1129
1135
|
part = part.strip()
|
|
1130
|
-
if part.startswith(
|
|
1136
|
+
if part.startswith(cookie_prefix):
|
|
1131
1137
|
sid_match = part.split("=", 1)[1]
|
|
1132
1138
|
break
|
|
1133
1139
|
|
|
@@ -1770,9 +1776,15 @@ def _finalize_response(
|
|
|
1770
1776
|
request.session.save()
|
|
1771
1777
|
sid = request.session.session_id if hasattr(request.session, 'session_id') else getattr(request.session, 'id', None)
|
|
1772
1778
|
if sid:
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1779
|
+
# Route through the single cookie-builder so every
|
|
1780
|
+
# TINA4_SESSION_* knob (Secure/HttpOnly/SameSite) and the
|
|
1781
|
+
# proxy-aware Secure detection actually take effect. Do NOT
|
|
1782
|
+
# hand-write a second Set-Cookie here — that bypass is what
|
|
1783
|
+
# made TINA4_SESSION_SECURE a silent no-op (#95).
|
|
1784
|
+
response.header(
|
|
1785
|
+
"set-cookie",
|
|
1786
|
+
request.session.cookie_header(request=request),
|
|
1787
|
+
)
|
|
1776
1788
|
import random
|
|
1777
1789
|
if random.randint(1, 100) == 1:
|
|
1778
1790
|
request.session.gc()
|
|
@@ -18,6 +18,21 @@ import secrets
|
|
|
18
18
|
from pathlib import Path
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
def session_cookie_name() -> str:
|
|
22
|
+
"""Resolve the session cookie name — the single source of truth shared by
|
|
23
|
+
the WRITE side (``Session.cookie_header``) and the READ side
|
|
24
|
+
(``core/server._init_session``), so a cookie written under a renamed name is
|
|
25
|
+
read back on the next request.
|
|
26
|
+
|
|
27
|
+
TINA4_SESSION_NAME Cookie name (default: ``tina4_session``)
|
|
28
|
+
|
|
29
|
+
Keeping this in one place means the default can never drift between the two
|
|
30
|
+
sides: an operator who sets ``TINA4_SESSION_NAME`` renames the cookie on both
|
|
31
|
+
the emit and the parse paths at once.
|
|
32
|
+
"""
|
|
33
|
+
return os.environ.get("TINA4_SESSION_NAME", "tina4_session")
|
|
34
|
+
|
|
35
|
+
|
|
21
36
|
class SessionHandler:
|
|
22
37
|
"""Base class for session storage backends."""
|
|
23
38
|
|
|
@@ -379,7 +394,7 @@ class Session:
|
|
|
379
394
|
result = self.flash(key)
|
|
380
395
|
return result if result is not None else default
|
|
381
396
|
|
|
382
|
-
def cookie_header(self, cookie_name: str = None) -> str:
|
|
397
|
+
def cookie_header(self, cookie_name: str = None, request=None) -> str:
|
|
383
398
|
"""Return a Set-Cookie header value for this session.
|
|
384
399
|
|
|
385
400
|
Cookie attributes are env-driven so deployments can flip security
|
|
@@ -387,17 +402,37 @@ class Session:
|
|
|
387
402
|
|
|
388
403
|
TINA4_SESSION_NAME Cookie name (default: tina4_session)
|
|
389
404
|
TINA4_SESSION_HTTPONLY HttpOnly flag (default: true)
|
|
390
|
-
TINA4_SESSION_SECURE Secure flag (default: false).
|
|
391
|
-
|
|
405
|
+
TINA4_SESSION_SECURE Secure flag (default: false). Forces
|
|
406
|
+
Secure on regardless of request scheme.
|
|
392
407
|
TINA4_SESSION_SAMESITE SameSite attribute (default: Lax)
|
|
408
|
+
|
|
409
|
+
The Secure attribute is set when ANY of the following holds:
|
|
410
|
+
|
|
411
|
+
1. TINA4_SESSION_SECURE is truthy (explicit opt-in), OR
|
|
412
|
+
2. SameSite is ``None`` — browsers reject SameSite=None without
|
|
413
|
+
Secure, OR
|
|
414
|
+
3. the request is really on https — detected proxy-aware via
|
|
415
|
+
``request.is_secure_scheme()`` (honours x-forwarded-proto, first
|
|
416
|
+
hop of a comma chain), so a session behind a TLS-terminating
|
|
417
|
+
proxy still ships Secure (#95).
|
|
418
|
+
|
|
419
|
+
Plain HTTP with no proxy signal and no TLS stays non-Secure: a Secure
|
|
420
|
+
cookie over plain http is undeliverable and would silently break the
|
|
421
|
+
session. Pass ``request`` so the scheme can be detected; omit it and
|
|
422
|
+
only the env/SameSite signals apply.
|
|
393
423
|
"""
|
|
394
424
|
if cookie_name is None:
|
|
395
|
-
cookie_name =
|
|
425
|
+
cookie_name = session_cookie_name()
|
|
396
426
|
samesite = os.environ.get("TINA4_SESSION_SAMESITE", "Lax")
|
|
397
427
|
# Default true for HttpOnly (matches v2 behaviour) — only drop the
|
|
398
428
|
# flag when the operator explicitly opts out.
|
|
399
429
|
httponly = str(os.environ.get("TINA4_SESSION_HTTPONLY", "true")).strip().lower() in ("true", "1", "yes", "on")
|
|
400
430
|
secure = str(os.environ.get("TINA4_SESSION_SECURE", "false")).strip().lower() in ("true", "1", "yes", "on")
|
|
431
|
+
secure = (
|
|
432
|
+
secure
|
|
433
|
+
or samesite.strip().lower() == "none"
|
|
434
|
+
or (request is not None and request.is_secure_scheme())
|
|
435
|
+
)
|
|
401
436
|
|
|
402
437
|
parts = [f"{cookie_name}={self._session_id}", "Path=/"]
|
|
403
438
|
if httponly:
|
|
@@ -421,4 +456,5 @@ class Session:
|
|
|
421
456
|
__all__ = [
|
|
422
457
|
"Session", "SessionHandler",
|
|
423
458
|
"FileSessionHandler", "DatabaseSessionHandler",
|
|
459
|
+
"session_cookie_name",
|
|
424
460
|
]
|
|
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.77 → tina4_python-3.13.79}/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.77 → tina4_python-3.13.79}/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.77 → tina4_python-3.13.79}/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
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/session_handlers/mongodb_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/session_handlers/redis_handler.py
RENAMED
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/session_handlers/valkey_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/docker/distroless/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/templates/docker/poetry/Dockerfile
RENAMED
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/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.77 → tina4_python-3.13.79}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-3.13.77 → tina4_python-3.13.79}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|