supython 0.1.2__tar.gz → 0.1.4__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.
- {supython-0.1.2 → supython-0.1.4}/PKG-INFO +66 -3
- {supython-0.1.2 → supython-0.1.4}/README.md +65 -2
- {supython-0.1.2 → supython-0.1.4}/pyproject.toml +1 -1
- {supython-0.1.2 → supython-0.1.4}/src/supython/app.py +2 -0
- supython-0.1.4/src/supython/auth/__init__.py +4 -0
- supython-0.1.4/src/supython/auth/claims.py +72 -0
- supython-0.1.4/src/supython/auth/deps.py +57 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/auth/service.py +9 -2
- supython-0.1.2/src/supython/auth/__init__.py +0 -3
- {supython-0.1.2 → supython-0.1.4}/.gitignore +0 -0
- {supython-0.1.2 → supython-0.1.4}/CHANGELOG.md +0 -0
- {supython-0.1.2 → supython-0.1.4}/LICENSE +0 -0
- {supython-0.1.2 → supython-0.1.4}/SECURITY.md +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/__init__.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/__init__.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/__init__.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/auth.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/auth_templates.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/auth_users.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/db.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/functions.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/jobs.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/ops.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/realtime.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/service_auth.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/service_auth_templates.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/service_auth_users.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/service_db.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/service_functions.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/service_jobs.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/service_ops.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/service_realtime.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/service_storage.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/storage.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/api/system.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/audit.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/deps.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/errors.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/schemas.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/session.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/spa.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Alert-dluGVkos.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Alert-dluGVkos.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Audit-Njung3HI.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Audit-Njung3HI.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Backups-DzPlFgrm.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Backups-DzPlFgrm.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Buckets-ByacGkU1.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Buckets-ByacGkU1.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Channels-BoIuTtam.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Channels-BoIuTtam.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/ChevronRight-CtQH1EQ1.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/ChevronRight-CtQH1EQ1.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/CodeViewer-Bqy7-wvH.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/CodeViewer-Bqy7-wvH.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Crons-B67vc39F.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Crons-B67vc39F.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/DashboardView-CUTFVL6k.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/DashboardView-CUTFVL6k.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/DataTable-COAAWEft.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/DataTable-COAAWEft.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/DescriptionsItem-P8JUDaBs.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/DescriptionsItem-P8JUDaBs.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/DrawerContent-TpYTFgF1.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/DrawerContent-TpYTFgF1.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Empty-cr2r7e2u.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Empty-cr2r7e2u.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/EmptyState-DeDck-OL.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/EmptyState-DeDck-OL.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Grid-hFkp9F4P.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Grid-hFkp9F4P.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Input-DppYTq9C.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Input-DppYTq9C.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Invoke-DW3Nveeh.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Invoke-DW3Nveeh.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/JsonField-DibyJgun.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/JsonField-DibyJgun.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/LoginView-BjLyE3Ds.css +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/LoginView-CoOjECT_.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/LoginView-CoOjECT_.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Logs-D9WYrnIT.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Logs-D9WYrnIT.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Logs-DS1XPa0h.css +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Migrations-DOSC2ddQ.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Migrations-DOSC2ddQ.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/ObjectBrowser-_5w8vOX8.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/ObjectBrowser-_5w8vOX8.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Queue-CywZs6vI.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Queue-CywZs6vI.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/RefreshTokens-Ccjr53jg.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/RefreshTokens-Ccjr53jg.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/RlsEditor-BSlH9vSc.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/RlsEditor-BSlH9vSc.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Routes-BiLXE49D.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Routes-BiLXE49D.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Routes-C-ianIGD.css +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/SchemaBrowser-DKy2_KQi.css +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/SchemaBrowser-XFvFbtDB.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/SchemaBrowser-XFvFbtDB.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Select-DIzZyRZb.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Select-DIzZyRZb.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Space-n5-XcguU.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Space-n5-XcguU.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/SqlEditor-b8pTsILY.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/SqlEditor-b8pTsILY.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/SqlWorkspace-BUS7IntH.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/SqlWorkspace-BUS7IntH.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/TableData-CQIagLKn.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/TableData-CQIagLKn.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Tag-D1fOKpTH.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Tag-D1fOKpTH.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Templates-BS-ugkdq.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Templates-BS-ugkdq.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Thing-CEAniuMg.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Thing-CEAniuMg.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Users-wzwajhlh.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Users-wzwajhlh.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/_plugin-vue_export-helper-DGA9ry_j.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/dist-VXIJLCYq.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/dist-VXIJLCYq.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/format-length-CGCY1rMh.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/format-length-CGCY1rMh.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/get-Ca6unauB.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/get-Ca6unauB.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/index-CeE6v959.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/index-CeE6v959.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/pinia-COXwfrOX.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/pinia-COXwfrOX.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/resources-Bt6thQCD.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/resources-Bt6thQCD.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/use-locale-mtgM0a3a.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/use-locale-mtgM0a3a.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/use-merged-state-BvhkaHNX.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/use-merged-state-BvhkaHNX.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/useConfirm-tMjvBFXR.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/useConfirm-tMjvBFXR.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/useResource-C_rJCY8C.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/useResource-C_rJCY8C.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/useTable-CnZc5zhi.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/useTable-CnZc5zhi.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/useTable-Dg0XlRlq.css +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/useToast-DsZKx0IX.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/useToast-DsZKx0IX.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/utils-sbXoq7Ir.js +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/utils-sbXoq7Ir.js.map +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/favicon.svg +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/icons.svg +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/index.html +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/auth/_email_job.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/auth/providers/__init__.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/auth/providers/github.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/auth/providers/google.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/auth/providers/oauth.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/auth/providers/registry.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/auth/ratelimit.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/auth/router.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/auth/schemas.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/backups/__init__.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/backups/_backup_job.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/backups/schemas.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/backups/service.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/body_size.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/cli.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/client/__init__.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/client/_auth.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/client/_client.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/client/_config.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/client/_functions.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/client/_storage.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/client/py.typed +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/db.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/db_admin.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/extensions.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/functions/__init__.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/functions/context.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/functions/loader.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/functions/router.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/functions/schemas.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/gen/__init__.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/gen/_introspect.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/gen/types_py.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/gen/types_ts.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/health.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/hooks.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/jobs/__init__.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/jobs/backends.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/jobs/context.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/jobs/cron.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/jobs/cron_inproc.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/jobs/decorators.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/jobs/registry.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/jobs/router.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/jobs/schemas.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/jobs/service.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/jobs/worker.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/jwks.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/keyset.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/logging_config.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/mail.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/mailer.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrate.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrations/0001_extensions_and_roles.sql +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrations/0002_auth_schema.sql +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrations/0003_demo_todos.sql +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrations/0004_auth_v0_2.sql +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrations/0005_storage_schema.sql +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrations/0006_realtime_schema.sql +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrations/0007_jobs_schema.sql +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrations/0008_jobs_last_error.sql +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrations/0009_auth_rate_limits.sql +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrations/0010_worker_heartbeat.sql +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrations/0011_admin_schema.sql +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrations/0012_auth_banned_until.sql +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrations/0013_email_templates.sql +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrations/0014_realtime_payload_warning.sql +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/migrations/0015_backups_schema.sql +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/passwords.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/realtime/__init__.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/realtime/broker.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/realtime/protocol.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/realtime/router.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/realtime/schemas.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/realtime/service.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/realtime/topics.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/realtime/websocket.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/__init__.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/init_project.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/Caddyfile.tmpl +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/README.md.tmpl +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/apps_hooks.py.tmpl +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/apps_jobs.py.tmpl +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/asgi.py.tmpl +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/docker-compose.prod.yml.tmpl +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/docker-compose.yml.tmpl +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/docker_postgres_Dockerfile.tmpl +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/docker_postgres_postgresql.conf.tmpl +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/env.example.tmpl +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/functions_README.md.tmpl +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/gitignore.tmpl +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/manage.py.tmpl +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/migrations/.gitkeep +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/package_init.py.tmpl +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/scaffold/templates/settings.py.tmpl +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/secretset.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/security_headers.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/settings.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/settings_module.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/storage/__init__.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/storage/backends.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/storage/router.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/storage/schemas.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/storage/service.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/storage/signing.py +0 -0
- {supython-0.1.2 → supython-0.1.4}/src/supython/tokens.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: supython
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: A lightweight Postgres-first BaaS framework for Python
|
|
5
5
|
Project-URL: Homepage, https://github.com/Tkeby/supython
|
|
6
6
|
Project-URL: Repository, https://github.com/Tkeby/supython
|
|
@@ -58,7 +58,7 @@ Description-Content-Type: text/markdown
|
|
|
58
58
|
|
|
59
59
|
# supython
|
|
60
60
|
|
|
61
|
-
> A lightweight, Postgres-first BaaS framework for Python. **v0.1.
|
|
61
|
+
> A lightweight, Postgres-first BaaS framework for Python. **v0.1.4 release**
|
|
62
62
|
|
|
63
63
|
**the database owns the schema, Python owns the things SQL is bad at**.
|
|
64
64
|
It leans on [PostgREST](https://postgrest.org)
|
|
@@ -95,7 +95,7 @@ Shipped [v0.1.2]:
|
|
|
95
95
|
**Jobs & cron**
|
|
96
96
|
- **Job queue** — Postgres-backed (`SELECT FOR UPDATE SKIP LOCKED`), idempotent enqueue, retry with backoff
|
|
97
97
|
- **Cron scheduling** — `pg_cron` (primary) or in-process `croniter` fallback
|
|
98
|
-
- **Generic hooks** — `@app.on_signup` / `@app.on_login` lifecycle hooks
|
|
98
|
+
- **Generic hooks** — `@app.on_signup` / `@app.on_login` lifecycle hooks; `@app.claims_provider` for custom JWT claims
|
|
99
99
|
- **`supython worker run`** — long-running worker with graceful SIGTERM drain
|
|
100
100
|
|
|
101
101
|
**Operations & security**
|
|
@@ -418,6 +418,69 @@ SMTP_PASSWORD`.
|
|
|
418
418
|
**OAuth** — add `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET` (and/or GitHub
|
|
419
419
|
equivalents) to `.env`. Providers without credentials are silently disabled.
|
|
420
420
|
|
|
421
|
+
### Custom JWT claims [shipped v0.1.3]
|
|
422
|
+
|
|
423
|
+
Register a `claims_provider` to inject application-specific claims into every
|
|
424
|
+
access token minted by the auth endpoints. Each provider is an async callable
|
|
425
|
+
`(user, conn) -> dict` whose return value is merged into the token payload —
|
|
426
|
+
on signup, password login, refresh, magic-link, OTP, and OAuth callbacks.
|
|
427
|
+
|
|
428
|
+
```python
|
|
429
|
+
from supython.app import app
|
|
430
|
+
|
|
431
|
+
@app.claims_provider
|
|
432
|
+
async def add_org(user, conn):
|
|
433
|
+
org_id = await conn.fetchval(
|
|
434
|
+
"select org_id from public.memberships where user_id = $1", user.id
|
|
435
|
+
)
|
|
436
|
+
return {"org_id": str(org_id)} if org_id else {}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Notes:
|
|
440
|
+
|
|
441
|
+
- Reserved JWT claims (`sub`, `email`, `role`, `aud`, `iat`, `exp`, `jti`)
|
|
442
|
+
cannot be overridden — they are filtered out automatically.
|
|
443
|
+
- Providers run on the **service-role** connection used by the auth flow, so
|
|
444
|
+
they can read tables that RLS would block during issuance. Treat the
|
|
445
|
+
function as privileged code (same posture as a Postgres `security definer`
|
|
446
|
+
routine — sanitize any user-supplied input).
|
|
447
|
+
- A provider that raises aborts issuance: a missing claim is a silent authz
|
|
448
|
+
bug, not a missing welcome email.
|
|
449
|
+
- Refresh re-collects claims, so a token rotated via `/auth/v1/refresh`
|
|
450
|
+
reflects current state.
|
|
451
|
+
|
|
452
|
+
### Reading the caller in your routes [shipped v0.1.4]
|
|
453
|
+
|
|
454
|
+
Application code mounts its own routers alongside supython's. To gate an
|
|
455
|
+
endpoint on a valid bearer token — or to read custom claims out of it —
|
|
456
|
+
use the public dependencies re-exported from `supython.auth`:
|
|
457
|
+
|
|
458
|
+
```python
|
|
459
|
+
from typing import Annotated
|
|
460
|
+
from uuid import UUID
|
|
461
|
+
|
|
462
|
+
from fastapi import APIRouter, Depends
|
|
463
|
+
from supython.auth import current_claims, current_user_id
|
|
464
|
+
|
|
465
|
+
router = APIRouter(prefix="/api/v1")
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
@router.get("/me")
|
|
469
|
+
async def me(user_id: Annotated[UUID, Depends(current_user_id)]) -> dict:
|
|
470
|
+
return {"user_id": str(user_id)}
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
@router.get("/whoami")
|
|
474
|
+
async def whoami(claims: Annotated[dict, Depends(current_claims)]) -> dict:
|
|
475
|
+
# Read whatever your `claims_provider` injected — e.g. org_id.
|
|
476
|
+
return {"user_id": claims["sub"], "org_id": claims.get("org_id")}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Both dependencies raise `401 Unauthorized` when the `Authorization` header
|
|
480
|
+
is missing, malformed, or carries an invalid/expired token. `current_user_id`
|
|
481
|
+
is a thin convenience over `current_claims` — pick the dict version when you
|
|
482
|
+
need any claim beyond the user UUID.
|
|
483
|
+
|
|
421
484
|
### Auth hardening settings (`.env`)
|
|
422
485
|
|
|
423
486
|
| Variable | Default | Purpose |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# supython
|
|
2
2
|
|
|
3
|
-
> A lightweight, Postgres-first BaaS framework for Python. **v0.1.
|
|
3
|
+
> A lightweight, Postgres-first BaaS framework for Python. **v0.1.4 release**
|
|
4
4
|
|
|
5
5
|
**the database owns the schema, Python owns the things SQL is bad at**.
|
|
6
6
|
It leans on [PostgREST](https://postgrest.org)
|
|
@@ -37,7 +37,7 @@ Shipped [v0.1.2]:
|
|
|
37
37
|
**Jobs & cron**
|
|
38
38
|
- **Job queue** — Postgres-backed (`SELECT FOR UPDATE SKIP LOCKED`), idempotent enqueue, retry with backoff
|
|
39
39
|
- **Cron scheduling** — `pg_cron` (primary) or in-process `croniter` fallback
|
|
40
|
-
- **Generic hooks** — `@app.on_signup` / `@app.on_login` lifecycle hooks
|
|
40
|
+
- **Generic hooks** — `@app.on_signup` / `@app.on_login` lifecycle hooks; `@app.claims_provider` for custom JWT claims
|
|
41
41
|
- **`supython worker run`** — long-running worker with graceful SIGTERM drain
|
|
42
42
|
|
|
43
43
|
**Operations & security**
|
|
@@ -360,6 +360,69 @@ SMTP_PASSWORD`.
|
|
|
360
360
|
**OAuth** — add `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET` (and/or GitHub
|
|
361
361
|
equivalents) to `.env`. Providers without credentials are silently disabled.
|
|
362
362
|
|
|
363
|
+
### Custom JWT claims [shipped v0.1.3]
|
|
364
|
+
|
|
365
|
+
Register a `claims_provider` to inject application-specific claims into every
|
|
366
|
+
access token minted by the auth endpoints. Each provider is an async callable
|
|
367
|
+
`(user, conn) -> dict` whose return value is merged into the token payload —
|
|
368
|
+
on signup, password login, refresh, magic-link, OTP, and OAuth callbacks.
|
|
369
|
+
|
|
370
|
+
```python
|
|
371
|
+
from supython.app import app
|
|
372
|
+
|
|
373
|
+
@app.claims_provider
|
|
374
|
+
async def add_org(user, conn):
|
|
375
|
+
org_id = await conn.fetchval(
|
|
376
|
+
"select org_id from public.memberships where user_id = $1", user.id
|
|
377
|
+
)
|
|
378
|
+
return {"org_id": str(org_id)} if org_id else {}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Notes:
|
|
382
|
+
|
|
383
|
+
- Reserved JWT claims (`sub`, `email`, `role`, `aud`, `iat`, `exp`, `jti`)
|
|
384
|
+
cannot be overridden — they are filtered out automatically.
|
|
385
|
+
- Providers run on the **service-role** connection used by the auth flow, so
|
|
386
|
+
they can read tables that RLS would block during issuance. Treat the
|
|
387
|
+
function as privileged code (same posture as a Postgres `security definer`
|
|
388
|
+
routine — sanitize any user-supplied input).
|
|
389
|
+
- A provider that raises aborts issuance: a missing claim is a silent authz
|
|
390
|
+
bug, not a missing welcome email.
|
|
391
|
+
- Refresh re-collects claims, so a token rotated via `/auth/v1/refresh`
|
|
392
|
+
reflects current state.
|
|
393
|
+
|
|
394
|
+
### Reading the caller in your routes [shipped v0.1.4]
|
|
395
|
+
|
|
396
|
+
Application code mounts its own routers alongside supython's. To gate an
|
|
397
|
+
endpoint on a valid bearer token — or to read custom claims out of it —
|
|
398
|
+
use the public dependencies re-exported from `supython.auth`:
|
|
399
|
+
|
|
400
|
+
```python
|
|
401
|
+
from typing import Annotated
|
|
402
|
+
from uuid import UUID
|
|
403
|
+
|
|
404
|
+
from fastapi import APIRouter, Depends
|
|
405
|
+
from supython.auth import current_claims, current_user_id
|
|
406
|
+
|
|
407
|
+
router = APIRouter(prefix="/api/v1")
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
@router.get("/me")
|
|
411
|
+
async def me(user_id: Annotated[UUID, Depends(current_user_id)]) -> dict:
|
|
412
|
+
return {"user_id": str(user_id)}
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
@router.get("/whoami")
|
|
416
|
+
async def whoami(claims: Annotated[dict, Depends(current_claims)]) -> dict:
|
|
417
|
+
# Read whatever your `claims_provider` injected — e.g. org_id.
|
|
418
|
+
return {"user_id": claims["sub"], "org_id": claims.get("org_id")}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
Both dependencies raise `401 Unauthorized` when the `Authorization` header
|
|
422
|
+
is missing, malformed, or carries an invalid/expired token. `current_user_id`
|
|
423
|
+
is a thin convenience over `current_claims` — pick the dict version when you
|
|
424
|
+
need any claim beyond the user UUID.
|
|
425
|
+
|
|
363
426
|
### Auth hardening settings (`.env`)
|
|
364
427
|
|
|
365
428
|
| Variable | Default | Purpose |
|
|
@@ -11,6 +11,7 @@ from fastapi.middleware.cors import CORSMiddleware
|
|
|
11
11
|
from . import __version__, db, jwks
|
|
12
12
|
from .admin import router as admin_api_router
|
|
13
13
|
from .admin import spa as admin_spa
|
|
14
|
+
from .auth import claims as auth_claims
|
|
14
15
|
from .auth.router import router as auth_router
|
|
15
16
|
from .extensions import load_extensions
|
|
16
17
|
from .settings_module import UserSettings, load_user_settings
|
|
@@ -155,6 +156,7 @@ def create_app() -> FastAPI:
|
|
|
155
156
|
app.on_signup = _make_hook_decorator("signup")
|
|
156
157
|
app.on_login = _make_hook_decorator("login")
|
|
157
158
|
app.on_logout = _make_hook_decorator("logout")
|
|
159
|
+
app.claims_provider = auth_claims.register
|
|
158
160
|
|
|
159
161
|
return app
|
|
160
162
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Custom-claim providers for access-token issuance.
|
|
2
|
+
|
|
3
|
+
Library users register an async callable via ``@app.claims_provider`` (or
|
|
4
|
+
``claims.register``) and the auth service invokes it inside ``_issue_pair``
|
|
5
|
+
just before minting the JWT. Each provider returns a ``dict`` that is
|
|
6
|
+
merged into the access token's payload.
|
|
7
|
+
|
|
8
|
+
Contract (intentionally narrower than ``hooks.fire``):
|
|
9
|
+
|
|
10
|
+
- Providers run on the **service-role** connection used by the auth flow,
|
|
11
|
+
so they can read tables that RLS would block during issuance (e.g. a
|
|
12
|
+
``user_roles`` lookup keyed by a brand-new user). Treat the function as
|
|
13
|
+
privileged — same posture as a Postgres ``security definer`` routine.
|
|
14
|
+
- A provider raising propagates: a missing claim is a silent authz bug,
|
|
15
|
+
not a missing welcome email. ``hooks.fire`` swallows on purpose;
|
|
16
|
+
``collect`` does not.
|
|
17
|
+
- Reserved JWT claims (``sub``, ``email``, ``role``, ``aud``, ``iat``,
|
|
18
|
+
``exp``, ``jti``) cannot be overridden — they are filtered out of every
|
|
19
|
+
provider's return value so a misbehaving provider can't mint a token
|
|
20
|
+
that contradicts its own header or expiry.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import logging
|
|
24
|
+
from collections.abc import Awaitable, Callable
|
|
25
|
+
from typing import Any
|
|
26
|
+
|
|
27
|
+
import asyncpg
|
|
28
|
+
|
|
29
|
+
from .schemas import UserResponse
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
ClaimsProvider = Callable[[UserResponse, asyncpg.Connection], Awaitable[dict[str, Any]]]
|
|
34
|
+
|
|
35
|
+
_RESERVED: frozenset[str] = frozenset(
|
|
36
|
+
{"sub", "email", "role", "aud", "iat", "exp", "jti"}
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
_providers: list[ClaimsProvider] = []
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def register(fn: ClaimsProvider) -> ClaimsProvider:
|
|
43
|
+
"""Register *fn* as a claims provider. Usable as a decorator."""
|
|
44
|
+
_providers.append(fn)
|
|
45
|
+
return fn
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
async def collect(user: UserResponse, conn: asyncpg.Connection) -> dict[str, Any]:
|
|
49
|
+
"""Run every registered provider and return the merged claim dict.
|
|
50
|
+
|
|
51
|
+
Providers run in registration order; later providers win on key
|
|
52
|
+
collisions. Reserved JWT claims are stripped from each return value
|
|
53
|
+
before merging.
|
|
54
|
+
"""
|
|
55
|
+
merged: dict[str, Any] = {}
|
|
56
|
+
for fn in _providers:
|
|
57
|
+
out = await fn(user, conn)
|
|
58
|
+
if not out:
|
|
59
|
+
continue
|
|
60
|
+
for key in _RESERVED.intersection(out):
|
|
61
|
+
logger.warning(
|
|
62
|
+
"claims provider %r returned reserved claim %r; dropping",
|
|
63
|
+
getattr(fn, "__qualname__", fn),
|
|
64
|
+
key,
|
|
65
|
+
)
|
|
66
|
+
merged.update({k: v for k, v in out.items() if k not in _RESERVED})
|
|
67
|
+
return merged
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def reset() -> None:
|
|
71
|
+
"""Clear all registered providers. Test-only."""
|
|
72
|
+
_providers.clear()
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Public FastAPI dependencies for downstream apps.
|
|
2
|
+
|
|
3
|
+
These are the supported way for application code to read the authenticated
|
|
4
|
+
caller out of an incoming request — equivalent to the auth router's private
|
|
5
|
+
``_current_user_id`` but stable, re-exported, and documented.
|
|
6
|
+
|
|
7
|
+
Usage::
|
|
8
|
+
|
|
9
|
+
from typing import Annotated
|
|
10
|
+
from uuid import UUID
|
|
11
|
+
|
|
12
|
+
from fastapi import Depends
|
|
13
|
+
from supython.auth import current_user_id, current_claims
|
|
14
|
+
|
|
15
|
+
@router.get("/me")
|
|
16
|
+
async def me(user_id: Annotated[UUID, Depends(current_user_id)]):
|
|
17
|
+
...
|
|
18
|
+
|
|
19
|
+
@router.get("/whoami")
|
|
20
|
+
async def whoami(claims: Annotated[dict, Depends(current_claims)]):
|
|
21
|
+
return {"org_id": claims.get("org_id")}
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from typing import Annotated, Any
|
|
25
|
+
from uuid import UUID
|
|
26
|
+
|
|
27
|
+
import jwt
|
|
28
|
+
from fastapi import Depends, Header, HTTPException, status
|
|
29
|
+
|
|
30
|
+
from .. import tokens
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
async def current_claims(
|
|
34
|
+
authorization: Annotated[str | None, Header()] = None,
|
|
35
|
+
) -> dict[str, Any]:
|
|
36
|
+
"""Return the decoded JWT claims of the bearer token, or 401."""
|
|
37
|
+
if not authorization or not authorization.lower().startswith("bearer "):
|
|
38
|
+
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "Missing bearer token")
|
|
39
|
+
token = authorization.split(" ", 1)[1]
|
|
40
|
+
try:
|
|
41
|
+
return tokens.decode_access_token(token)
|
|
42
|
+
except jwt.PyJWTError as exc:
|
|
43
|
+
raise HTTPException(
|
|
44
|
+
status.HTTP_401_UNAUTHORIZED, f"Invalid token: {exc}"
|
|
45
|
+
) from exc
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
async def current_user_id(
|
|
49
|
+
claims: Annotated[dict[str, Any], Depends(current_claims)],
|
|
50
|
+
) -> UUID:
|
|
51
|
+
"""Return the authenticated user's UUID from the bearer token, or 401."""
|
|
52
|
+
try:
|
|
53
|
+
return UUID(claims["sub"])
|
|
54
|
+
except (KeyError, ValueError) as exc:
|
|
55
|
+
raise HTTPException(
|
|
56
|
+
status.HTTP_401_UNAUTHORIZED, "Token missing valid sub claim"
|
|
57
|
+
) from exc
|
|
@@ -14,6 +14,7 @@ from itsdangerous import BadSignature, URLSafeTimedSerializer
|
|
|
14
14
|
from .. import mail, passwords, tokens
|
|
15
15
|
from ..mailer import EmailMessage
|
|
16
16
|
from ..settings import get_settings
|
|
17
|
+
from . import claims
|
|
17
18
|
from .schemas import UserResponse
|
|
18
19
|
|
|
19
20
|
logger = logging.getLogger(__name__)
|
|
@@ -63,7 +64,10 @@ async def _audit_log(
|
|
|
63
64
|
async def _issue_pair(
|
|
64
65
|
conn: asyncpg.Connection, user: UserResponse
|
|
65
66
|
) -> tuple[str, str, int]:
|
|
66
|
-
|
|
67
|
+
extra = await claims.collect(user, conn)
|
|
68
|
+
access, ttl = tokens.issue_access_token(
|
|
69
|
+
user.id, user.email, extra_claims=extra or None
|
|
70
|
+
)
|
|
67
71
|
refresh = tokens.issue_refresh_token()
|
|
68
72
|
await conn.execute(
|
|
69
73
|
"insert into auth.refresh_tokens (user_id, token) values ($1, $2)",
|
|
@@ -273,7 +277,10 @@ async def refresh_grant(
|
|
|
273
277
|
new_refresh,
|
|
274
278
|
refresh_token,
|
|
275
279
|
)
|
|
276
|
-
|
|
280
|
+
extra = await claims.collect(user, conn)
|
|
281
|
+
access, ttl = tokens.issue_access_token(
|
|
282
|
+
user.id, user.email, extra_claims=extra or None
|
|
283
|
+
)
|
|
277
284
|
return user, access, new_refresh, ttl
|
|
278
285
|
|
|
279
286
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/ChevronRight-CtQH1EQ1.js.map
RENAMED
|
File without changes
|
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/CodeViewer-Bqy7-wvH.js.map
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/DashboardView-CUTFVL6k.js
RENAMED
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/DashboardView-CUTFVL6k.js.map
RENAMED
|
File without changes
|
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/DataTable-COAAWEft.js.map
RENAMED
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/DescriptionsItem-P8JUDaBs.js
RENAMED
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/DescriptionsItem-P8JUDaBs.js.map
RENAMED
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/DrawerContent-TpYTFgF1.js
RENAMED
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/DrawerContent-TpYTFgF1.js.map
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/EmptyState-DeDck-OL.js.map
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
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/JsonField-DibyJgun.js.map
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/LoginView-CoOjECT_.js.map
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/Migrations-DOSC2ddQ.js.map
RENAMED
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/ObjectBrowser-_5w8vOX8.js
RENAMED
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/ObjectBrowser-_5w8vOX8.js.map
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/RefreshTokens-Ccjr53jg.js
RENAMED
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/RefreshTokens-Ccjr53jg.js.map
RENAMED
|
File without changes
|
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/RlsEditor-BSlH9vSc.js.map
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/SchemaBrowser-DKy2_KQi.css
RENAMED
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/SchemaBrowser-XFvFbtDB.js
RENAMED
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/SchemaBrowser-XFvFbtDB.js.map
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/SqlEditor-b8pTsILY.js.map
RENAMED
|
File without changes
|
|
File without changes
|
{supython-0.1.2 → supython-0.1.4}/src/supython/admin/static/assets/SqlWorkspace-BUS7IntH.js.map
RENAMED
|
File without changes
|