@tinyrack/issuary-server 0.30.0 → 0.32.1
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.
- package/dist/entities/auth-budget.entity.d.ts +20 -0
- package/dist/entities/auth-budget.entity.d.ts.map +1 -0
- package/dist/entities/auth-budget.entity.js +11 -0
- package/dist/entities/auth-budget.entity.js.map +1 -0
- package/dist/entities/browser-session.entity.d.ts +32 -0
- package/dist/entities/browser-session.entity.d.ts.map +1 -0
- package/dist/entities/browser-session.entity.js +12 -0
- package/dist/entities/browser-session.entity.js.map +1 -0
- package/dist/entities/email-verification.entity.d.ts +18 -0
- package/dist/entities/email-verification.entity.d.ts.map +1 -1
- package/dist/entities/email-verification.entity.js +2 -0
- package/dist/entities/email-verification.entity.js.map +1 -1
- package/dist/entities/oauth-client.entity.d.ts +120 -0
- package/dist/entities/oauth-client.entity.d.ts.map +1 -1
- package/dist/entities/oauth-code.entity.d.ts +120 -0
- package/dist/entities/oauth-code.entity.d.ts.map +1 -1
- package/dist/entities/oauth-code.entity.js +3 -0
- package/dist/entities/oauth-code.entity.js.map +1 -1
- package/dist/entities/oauth-device-code.entity.d.ts +120 -0
- package/dist/entities/oauth-device-code.entity.d.ts.map +1 -1
- package/dist/entities/oauth-device-code.entity.js +3 -0
- package/dist/entities/oauth-device-code.entity.js.map +1 -1
- package/dist/entities/oauth-grant.entity.d.ts +52 -0
- package/dist/entities/oauth-grant.entity.d.ts.map +1 -0
- package/dist/entities/oauth-grant.entity.js +19 -0
- package/dist/entities/oauth-grant.entity.js.map +1 -0
- package/dist/entities/password-reset.entity.d.ts +18 -0
- package/dist/entities/password-reset.entity.d.ts.map +1 -1
- package/dist/entities/password-reset.entity.js +2 -0
- package/dist/entities/password-reset.entity.js.map +1 -1
- package/dist/entities/pending-oauth-registration.entity.d.ts +9 -0
- package/dist/entities/pending-oauth-registration.entity.d.ts.map +1 -1
- package/dist/entities/pending-oauth-registration.entity.js +1 -0
- package/dist/entities/pending-oauth-registration.entity.js.map +1 -1
- package/dist/entities/revoked-token.entity.d.ts +120 -0
- package/dist/entities/revoked-token.entity.d.ts.map +1 -1
- package/dist/entities/terms-content.entity.d.ts +36 -0
- package/dist/entities/terms-content.entity.d.ts.map +1 -1
- package/dist/entities/terms.entity.d.ts +36 -0
- package/dist/entities/terms.entity.d.ts.map +1 -1
- package/dist/entities/user-consent.entity.d.ts +120 -0
- package/dist/entities/user-consent.entity.d.ts.map +1 -1
- package/dist/entities/user-terms-consent.entity.d.ts +36 -0
- package/dist/entities/user-terms-consent.entity.d.ts.map +1 -1
- package/dist/entities/user-totp-recovery-code.entity.d.ts +36 -0
- package/dist/entities/user-totp-recovery-code.entity.d.ts.map +1 -1
- package/dist/entities/user-totp.entity.d.ts +36 -0
- package/dist/entities/user-totp.entity.d.ts.map +1 -1
- package/dist/entities/user-totp.entity.js +1 -0
- package/dist/entities/user-totp.entity.js.map +1 -1
- package/dist/entities/user.entity.d.ts +36 -0
- package/dist/entities/user.entity.d.ts.map +1 -1
- package/dist/entities/user.entity.js +3 -0
- package/dist/entities/user.entity.js.map +1 -1
- package/dist/entrypoints/app.d.ts +438 -424
- package/dist/entrypoints/app.d.ts.map +1 -1
- package/dist/entrypoints/app.js +78 -6
- package/dist/entrypoints/app.js.map +1 -1
- package/dist/entrypoints/database/postgres/compiled-functions.d.ts +326 -200
- package/dist/entrypoints/database/postgres/compiled-functions.js +1849 -518
- package/dist/entrypoints/database/postgres/compiled-functions.js.map +1 -1
- package/dist/entrypoints/database/sqlite/compiled-functions.d.ts +326 -200
- package/dist/entrypoints/database/sqlite/compiled-functions.js +1849 -518
- package/dist/entrypoints/database/sqlite/compiled-functions.js.map +1 -1
- package/dist/entrypoints/database/sqlite/sqlite.d.ts.map +1 -1
- package/dist/entrypoints/database/sqlite/sqlite.js +1 -0
- package/dist/entrypoints/database/sqlite/sqlite.js.map +1 -1
- package/dist/entrypoints/scheduler/database.d.ts +3 -1
- package/dist/entrypoints/scheduler/database.d.ts.map +1 -1
- package/dist/entrypoints/scheduler/database.js +13 -2
- package/dist/entrypoints/scheduler/database.js.map +1 -1
- package/dist/entrypoints/scheduler/distributed-runner.d.ts +4 -0
- package/dist/entrypoints/scheduler/distributed-runner.d.ts.map +1 -1
- package/dist/entrypoints/scheduler/distributed-runner.js +26 -1
- package/dist/entrypoints/scheduler/distributed-runner.js.map +1 -1
- package/dist/lib/config/client.js +1 -1
- package/dist/lib/config/client.js.map +1 -1
- package/dist/lib/config/email.d.ts +1 -0
- package/dist/lib/config/email.d.ts.map +1 -1
- package/dist/lib/config/email.js.map +1 -1
- package/dist/lib/database/entities.d.ts.map +1 -1
- package/dist/lib/database/entities.js +6 -0
- package/dist/lib/database/entities.js.map +1 -1
- package/dist/lib/openapi.d.ts +2 -0
- package/dist/lib/openapi.d.ts.map +1 -1
- package/dist/lib/openapi.js +36 -1
- package/dist/lib/openapi.js.map +1 -1
- package/dist/lib/request-ip.d.ts +4 -0
- package/dist/lib/request-ip.d.ts.map +1 -0
- package/dist/lib/request-ip.js +39 -0
- package/dist/lib/request-ip.js.map +1 -0
- package/dist/middleware/auth-budget.d.ts +3 -0
- package/dist/middleware/auth-budget.d.ts.map +1 -0
- package/dist/middleware/auth-budget.js +80 -0
- package/dist/middleware/auth-budget.js.map +1 -0
- package/dist/middleware/session.d.ts +23 -5
- package/dist/middleware/session.d.ts.map +1 -1
- package/dist/middleware/session.js +152 -12
- package/dist/middleware/session.js.map +1 -1
- package/dist/middleware/strict-input.d.ts +4 -0
- package/dist/middleware/strict-input.d.ts.map +1 -0
- package/dist/middleware/strict-input.js +144 -0
- package/dist/middleware/strict-input.js.map +1 -0
- package/dist/migrations/postgres/Migration20260910120000_api_security.d.ts +6 -0
- package/dist/migrations/postgres/Migration20260910120000_api_security.d.ts.map +1 -0
- package/dist/migrations/postgres/Migration20260910120000_api_security.js +20 -0
- package/dist/migrations/postgres/Migration20260910120000_api_security.js.map +1 -0
- package/dist/migrations/postgres/Migration20260910160000_security_followup.d.ts +6 -0
- package/dist/migrations/postgres/Migration20260910160000_security_followup.d.ts.map +1 -0
- package/dist/migrations/postgres/Migration20260910160000_security_followup.js +23 -0
- package/dist/migrations/postgres/Migration20260910160000_security_followup.js.map +1 -0
- package/dist/migrations/postgres/Migration20260910200000_authentication_epoch.d.ts +6 -0
- package/dist/migrations/postgres/Migration20260910200000_authentication_epoch.d.ts.map +1 -0
- package/dist/migrations/postgres/Migration20260910200000_authentication_epoch.js +28 -0
- package/dist/migrations/postgres/Migration20260910200000_authentication_epoch.js.map +1 -0
- package/dist/migrations/postgres/Migration20260910220000_flow_revocation.d.ts +6 -0
- package/dist/migrations/postgres/Migration20260910220000_flow_revocation.d.ts.map +1 -0
- package/dist/migrations/postgres/Migration20260910220000_flow_revocation.js +19 -0
- package/dist/migrations/postgres/Migration20260910220000_flow_revocation.js.map +1 -0
- package/dist/migrations/postgres/index.d.ts.map +1 -1
- package/dist/migrations/postgres/index.js +8 -0
- package/dist/migrations/postgres/index.js.map +1 -1
- package/dist/migrations/sqlite/Migration20260910120000_api_security.d.ts +6 -0
- package/dist/migrations/sqlite/Migration20260910120000_api_security.d.ts.map +1 -0
- package/dist/migrations/sqlite/Migration20260910120000_api_security.js +20 -0
- package/dist/migrations/sqlite/Migration20260910120000_api_security.js.map +1 -0
- package/dist/migrations/sqlite/Migration20260910160000_security_followup.d.ts +6 -0
- package/dist/migrations/sqlite/Migration20260910160000_security_followup.d.ts.map +1 -0
- package/dist/migrations/sqlite/Migration20260910160000_security_followup.js +23 -0
- package/dist/migrations/sqlite/Migration20260910160000_security_followup.js.map +1 -0
- package/dist/migrations/sqlite/Migration20260910200000_authentication_epoch.d.ts +8 -0
- package/dist/migrations/sqlite/Migration20260910200000_authentication_epoch.d.ts.map +1 -0
- package/dist/migrations/sqlite/Migration20260910200000_authentication_epoch.js +72 -0
- package/dist/migrations/sqlite/Migration20260910200000_authentication_epoch.js.map +1 -0
- package/dist/migrations/sqlite/Migration20260910220000_flow_revocation.d.ts +6 -0
- package/dist/migrations/sqlite/Migration20260910220000_flow_revocation.d.ts.map +1 -0
- package/dist/migrations/sqlite/Migration20260910220000_flow_revocation.js +19 -0
- package/dist/migrations/sqlite/Migration20260910220000_flow_revocation.js.map +1 -0
- package/dist/migrations/sqlite/index.d.ts.map +1 -1
- package/dist/migrations/sqlite/index.js +8 -0
- package/dist/migrations/sqlite/index.js.map +1 -1
- package/dist/repositories/email-verification.repository.d.ts +1 -0
- package/dist/repositories/email-verification.repository.d.ts.map +1 -1
- package/dist/repositories/email-verification.repository.js +8 -17
- package/dist/repositories/email-verification.repository.js.map +1 -1
- package/dist/repositories/oauth-code.repository.d.ts +2 -0
- package/dist/repositories/oauth-code.repository.d.ts.map +1 -1
- package/dist/repositories/oauth-code.repository.js +8 -0
- package/dist/repositories/oauth-code.repository.js.map +1 -1
- package/dist/repositories/oauth-device-code.repository.d.ts +3 -0
- package/dist/repositories/oauth-device-code.repository.d.ts.map +1 -1
- package/dist/repositories/oauth-device-code.repository.js +64 -29
- package/dist/repositories/oauth-device-code.repository.js.map +1 -1
- package/dist/repositories/password-reset.repository.d.ts +1 -0
- package/dist/repositories/password-reset.repository.d.ts.map +1 -1
- package/dist/repositories/password-reset.repository.js +6 -19
- package/dist/repositories/password-reset.repository.js.map +1 -1
- package/dist/repositories/pending-oauth-registration.repository.d.ts +2 -0
- package/dist/repositories/pending-oauth-registration.repository.d.ts.map +1 -1
- package/dist/repositories/pending-oauth-registration.repository.js +16 -2
- package/dist/repositories/pending-oauth-registration.repository.js.map +1 -1
- package/dist/repositories/terms.repository.d.ts.map +1 -1
- package/dist/repositories/terms.repository.js +1 -0
- package/dist/repositories/terms.repository.js.map +1 -1
- package/dist/repositories/user-consent.repository.d.ts.map +1 -1
- package/dist/repositories/user-consent.repository.js +9 -3
- package/dist/repositories/user-consent.repository.js.map +1 -1
- package/dist/repositories/user-terms-consent.repository.d.ts.map +1 -1
- package/dist/repositories/user-terms-consent.repository.js +2 -0
- package/dist/repositories/user-terms-consent.repository.js.map +1 -1
- package/dist/repositories/user-totp-recovery-code.repository.d.ts +24 -0
- package/dist/repositories/user-totp-recovery-code.repository.d.ts.map +1 -1
- package/dist/repositories/user-totp.repository.d.ts +36 -0
- package/dist/repositories/user-totp.repository.d.ts.map +1 -1
- package/dist/routes/.well-known/openid-configuration/get.d.ts.map +1 -1
- package/dist/routes/.well-known/openid-configuration/get.js +5 -1
- package/dist/routes/.well-known/openid-configuration/get.js.map +1 -1
- package/dist/routes/api/admin/console/index.d.ts.map +1 -1
- package/dist/routes/api/admin/console/index.js +29 -14
- package/dist/routes/api/admin/console/index.js.map +1 -1
- package/dist/routes/api/admin/me/get.js +2 -3
- package/dist/routes/api/admin/me/get.js.map +1 -1
- package/dist/routes/api/admin/users/index.d.ts.map +1 -1
- package/dist/routes/api/admin/users/index.js +59 -52
- package/dist/routes/api/admin/users/index.js.map +1 -1
- package/dist/routes/api/auth/accounts/select.post.d.ts +6 -6
- package/dist/routes/api/auth/email/resend/post.d.ts.map +1 -1
- package/dist/routes/api/auth/email/resend/post.js +3 -24
- package/dist/routes/api/auth/email/resend/post.js.map +1 -1
- package/dist/routes/api/auth/email/verify/post.d.ts.map +1 -1
- package/dist/routes/api/auth/email/verify/post.js +29 -12
- package/dist/routes/api/auth/email/verify/post.js.map +1 -1
- package/dist/routes/api/auth/login/post.d.ts.map +1 -1
- package/dist/routes/api/auth/login/post.js +4 -3
- package/dist/routes/api/auth/login/post.js.map +1 -1
- package/dist/routes/api/auth/passkey/verify/post.d.ts.map +1 -1
- package/dist/routes/api/auth/passkey/verify/post.js +25 -11
- package/dist/routes/api/auth/passkey/verify/post.js.map +1 -1
- package/dist/routes/api/auth/password/forgot/post.d.ts.map +1 -1
- package/dist/routes/api/auth/password/forgot/post.js +2 -19
- package/dist/routes/api/auth/password/forgot/post.js.map +1 -1
- package/dist/routes/api/auth/register/post.d.ts.map +1 -1
- package/dist/routes/api/auth/register/post.js +4 -3
- package/dist/routes/api/auth/register/post.js.map +1 -1
- package/dist/routes/api/auth/totp/recovery/verify/post.d.ts.map +1 -1
- package/dist/routes/api/auth/totp/recovery/verify/post.js +7 -5
- package/dist/routes/api/auth/totp/recovery/verify/post.js.map +1 -1
- package/dist/routes/api/auth/totp/verify/post.d.ts.map +1 -1
- package/dist/routes/api/auth/totp/verify/post.js +7 -5
- package/dist/routes/api/auth/totp/verify/post.js.map +1 -1
- package/dist/routes/api/consent/get.d.ts +3 -0
- package/dist/routes/api/consent/get.d.ts.map +1 -1
- package/dist/routes/api/consent/get.js +26 -4
- package/dist/routes/api/consent/get.js.map +1 -1
- package/dist/routes/api/consent/index.d.ts +3 -0
- package/dist/routes/api/consent/index.d.ts.map +1 -1
- package/dist/routes/api/consent/post.d.ts.map +1 -1
- package/dist/routes/api/consent/post.js +142 -114
- package/dist/routes/api/consent/post.js.map +1 -1
- package/dist/routes/api/docs/get.d.ts.map +1 -1
- package/dist/routes/api/docs/get.js +8 -1
- package/dist/routes/api/docs/get.js.map +1 -1
- package/dist/routes/api/index.d.ts +382 -379
- package/dist/routes/api/index.d.ts.map +1 -1
- package/dist/routes/api/oauth/_provider/authorize/get.d.ts.map +1 -1
- package/dist/routes/api/oauth/_provider/authorize/get.js +5 -1
- package/dist/routes/api/oauth/_provider/authorize/get.js.map +1 -1
- package/dist/routes/api/oauth/_provider/callback/get.d.ts.map +1 -1
- package/dist/routes/api/oauth/_provider/callback/get.js +30 -6
- package/dist/routes/api/oauth/_provider/callback/get.js.map +1 -1
- package/dist/routes/api/oauth/_provider/callback/post.d.ts +9 -9
- package/dist/routes/api/oauth/_provider/callback/post.d.ts.map +1 -1
- package/dist/routes/api/oauth/_provider/callback/post.js +31 -31
- package/dist/routes/api/oauth/_provider/callback/post.js.map +1 -1
- package/dist/routes/api/oauth/_provider/delete.d.ts.map +1 -1
- package/dist/routes/api/oauth/_provider/delete.js +14 -11
- package/dist/routes/api/oauth/_provider/delete.js.map +1 -1
- package/dist/routes/api/terms/consent/post.d.ts.map +1 -1
- package/dist/routes/api/terms/consent/post.js +59 -43
- package/dist/routes/api/terms/consent/post.js.map +1 -1
- package/dist/routes/api/user/delete.d.ts.map +1 -1
- package/dist/routes/api/user/delete.js +8 -8
- package/dist/routes/api/user/delete.js.map +1 -1
- package/dist/routes/api/user/passkeys/_id/delete.d.ts.map +1 -1
- package/dist/routes/api/user/passkeys/_id/delete.js +17 -29
- package/dist/routes/api/user/passkeys/_id/delete.js.map +1 -1
- package/dist/routes/api/user/passkeys/_id/patch.d.ts.map +1 -1
- package/dist/routes/api/user/passkeys/_id/patch.js +16 -13
- package/dist/routes/api/user/passkeys/_id/patch.js.map +1 -1
- package/dist/routes/api/user/passkeys/register/verify/post.d.ts.map +1 -1
- package/dist/routes/api/user/passkeys/register/verify/post.js +27 -19
- package/dist/routes/api/user/passkeys/register/verify/post.js.map +1 -1
- package/dist/routes/api/user/password/delete.d.ts.map +1 -1
- package/dist/routes/api/user/password/delete.js +13 -10
- package/dist/routes/api/user/password/delete.js.map +1 -1
- package/dist/routes/api/user/password/post.d.ts.map +1 -1
- package/dist/routes/api/user/password/post.js +13 -10
- package/dist/routes/api/user/password/post.js.map +1 -1
- package/dist/routes/api/user/password/put.d.ts.map +1 -1
- package/dist/routes/api/user/password/put.js +13 -10
- package/dist/routes/api/user/password/put.js.map +1 -1
- package/dist/routes/api/user/totp/confirm/post.d.ts.map +1 -1
- package/dist/routes/api/user/totp/confirm/post.js +33 -18
- package/dist/routes/api/user/totp/confirm/post.js.map +1 -1
- package/dist/routes/api/user/totp/delete.d.ts.map +1 -1
- package/dist/routes/api/user/totp/delete.js +13 -18
- package/dist/routes/api/user/totp/delete.js.map +1 -1
- package/dist/routes/api/user/totp/recovery/regenerate/post.d.ts.map +1 -1
- package/dist/routes/api/user/totp/recovery/regenerate/post.js +13 -10
- package/dist/routes/api/user/totp/recovery/regenerate/post.js.map +1 -1
- package/dist/routes/api/user/totp/setup/post.d.ts.map +1 -1
- package/dist/routes/api/user/totp/setup/post.js +13 -8
- package/dist/routes/api/user/totp/setup/post.js.map +1 -1
- package/dist/routes/api/user/totp/verify/post.d.ts.map +1 -1
- package/dist/routes/api/user/totp/verify/post.js +23 -12
- package/dist/routes/api/user/totp/verify/post.js.map +1 -1
- package/dist/routes/index.d.ts +243 -230
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/oauth/authorize/get.d.ts.map +1 -1
- package/dist/routes/oauth/authorize/get.js +12 -4
- package/dist/routes/oauth/authorize/get.js.map +1 -1
- package/dist/routes/oauth/device/get-post.d.ts +10 -0
- package/dist/routes/oauth/device/get-post.d.ts.map +1 -1
- package/dist/routes/oauth/device/get-post.js +32 -3
- package/dist/routes/oauth/device/get-post.js.map +1 -1
- package/dist/routes/oauth/device-authorization/post.d.ts.map +1 -1
- package/dist/routes/oauth/device-authorization/post.js +13 -7
- package/dist/routes/oauth/device-authorization/post.js.map +1 -1
- package/dist/routes/oauth/end-session/get.d.ts +9 -9
- package/dist/routes/oauth/end-session/get.d.ts.map +1 -1
- package/dist/routes/oauth/end-session/get.js +2 -3
- package/dist/routes/oauth/end-session/get.js.map +1 -1
- package/dist/routes/oauth/index.d.ts +19 -9
- package/dist/routes/oauth/index.d.ts.map +1 -1
- package/dist/routes/oauth/revoke/post.d.ts.map +1 -1
- package/dist/routes/oauth/revoke/post.js +10 -2
- package/dist/routes/oauth/revoke/post.js.map +1 -1
- package/dist/routes/oauth/token/post.d.ts.map +1 -1
- package/dist/routes/oauth/token/post.js +69 -57
- package/dist/routes/oauth/token/post.js.map +1 -1
- package/dist/schemas/error.d.ts +75 -0
- package/dist/schemas/error.d.ts.map +1 -1
- package/dist/schemas/error.js +3 -0
- package/dist/schemas/error.js.map +1 -1
- package/dist/schemas/field.d.ts.map +1 -1
- package/dist/schemas/field.js +3 -0
- package/dist/schemas/field.js.map +1 -1
- package/dist/seeders/config.seeder.d.ts +1 -1
- package/dist/seeders/config.seeder.d.ts.map +1 -1
- package/dist/seeders/config.seeder.js +100 -36
- package/dist/seeders/config.seeder.js.map +1 -1
- package/dist/services/admin-console.service.d.ts.map +1 -1
- package/dist/services/admin-console.service.js +137 -100
- package/dist/services/admin-console.service.js.map +1 -1
- package/dist/services/auth-budget.service.d.ts +6 -0
- package/dist/services/auth-budget.service.d.ts.map +1 -0
- package/dist/services/auth-budget.service.js +30 -0
- package/dist/services/auth-budget.service.js.map +1 -0
- package/dist/services/authentication-epoch.d.ts +5 -0
- package/dist/services/authentication-epoch.d.ts.map +1 -0
- package/dist/services/authentication-epoch.js +22 -0
- package/dist/services/authentication-epoch.js.map +1 -0
- package/dist/services/authorization-browser.service.d.ts +18 -0
- package/dist/services/authorization-browser.service.d.ts.map +1 -0
- package/dist/services/authorization-browser.service.js +28 -0
- package/dist/services/authorization-browser.service.js.map +1 -0
- package/dist/services/browser-security.service.d.ts +14 -0
- package/dist/services/browser-security.service.d.ts.map +1 -0
- package/dist/services/browser-security.service.js +85 -0
- package/dist/services/browser-security.service.js.map +1 -0
- package/dist/services/browser-session.service.d.ts +25 -0
- package/dist/services/browser-session.service.d.ts.map +1 -0
- package/dist/services/browser-session.service.js +102 -0
- package/dist/services/browser-session.service.js.map +1 -0
- package/dist/services/cleanup.service.d.ts +1 -0
- package/dist/services/cleanup.service.d.ts.map +1 -1
- package/dist/services/cleanup.service.js +31 -0
- package/dist/services/cleanup.service.js.map +1 -1
- package/dist/services/client-security.d.ts +641 -0
- package/dist/services/client-security.d.ts.map +1 -0
- package/dist/services/client-security.js +10 -0
- package/dist/services/client-security.js.map +1 -0
- package/dist/services/container.d.ts +2 -0
- package/dist/services/container.d.ts.map +1 -1
- package/dist/services/container.js +7 -3
- package/dist/services/container.js.map +1 -1
- package/dist/services/email.service.d.ts +2 -14
- package/dist/services/email.service.d.ts.map +1 -1
- package/dist/services/email.service.js +35 -29
- package/dist/services/email.service.js.map +1 -1
- package/dist/services/jwt.service.d.ts +1 -0
- package/dist/services/jwt.service.d.ts.map +1 -1
- package/dist/services/jwt.service.js +13 -1
- package/dist/services/jwt.service.js.map +1 -1
- package/dist/services/mail-queue.service.d.ts +24 -0
- package/dist/services/mail-queue.service.d.ts.map +1 -0
- package/dist/services/mail-queue.service.js +223 -0
- package/dist/services/mail-queue.service.js.map +1 -0
- package/dist/services/mikro.service.d.ts.map +1 -1
- package/dist/services/mikro.service.js +2 -0
- package/dist/services/mikro.service.js.map +1 -1
- package/dist/services/oauth-authorize.service.d.ts +6 -1
- package/dist/services/oauth-authorize.service.d.ts.map +1 -1
- package/dist/services/oauth-authorize.service.js +136 -77
- package/dist/services/oauth-authorize.service.js.map +1 -1
- package/dist/services/oauth-browser-security.service.d.ts +7 -0
- package/dist/services/oauth-browser-security.service.d.ts.map +1 -0
- package/dist/services/oauth-browser-security.service.js +67 -0
- package/dist/services/oauth-browser-security.service.js.map +1 -0
- package/dist/services/oauth-client.service.d.ts +24 -1
- package/dist/services/oauth-client.service.d.ts.map +1 -1
- package/dist/services/oauth-client.service.js +52 -13
- package/dist/services/oauth-client.service.js.map +1 -1
- package/dist/services/oauth-connect.service.d.ts +37 -3
- package/dist/services/oauth-connect.service.d.ts.map +1 -1
- package/dist/services/oauth-connect.service.js +236 -212
- package/dist/services/oauth-connect.service.js.map +1 -1
- package/dist/services/oauth-token.service.d.ts +6 -4
- package/dist/services/oauth-token.service.d.ts.map +1 -1
- package/dist/services/oauth-token.service.js +295 -209
- package/dist/services/oauth-token.service.js.map +1 -1
- package/dist/services/passkey.service.d.ts +26 -7
- package/dist/services/passkey.service.d.ts.map +1 -1
- package/dist/services/passkey.service.js +71 -42
- package/dist/services/passkey.service.js.map +1 -1
- package/dist/services/password-auth.service.d.ts +5 -1
- package/dist/services/password-auth.service.d.ts.map +1 -1
- package/dist/services/password-auth.service.js +79 -52
- package/dist/services/password-auth.service.js.map +1 -1
- package/dist/services/password-reset.service.d.ts.map +1 -1
- package/dist/services/password-reset.service.js +34 -15
- package/dist/services/password-reset.service.js.map +1 -1
- package/dist/services/security.service.d.ts +3 -1
- package/dist/services/security.service.d.ts.map +1 -1
- package/dist/services/security.service.js +11 -2
- package/dist/services/security.service.js.map +1 -1
- package/dist/services/terms-policy.service.d.ts +7 -0
- package/dist/services/terms-policy.service.d.ts.map +1 -0
- package/dist/services/terms-policy.service.js +26 -0
- package/dist/services/terms-policy.service.js.map +1 -0
- package/dist/services/terms.service.d.ts.map +1 -1
- package/dist/services/terms.service.js +3 -2
- package/dist/services/terms.service.js.map +1 -1
- package/dist/services/totp.service.d.ts +4 -5
- package/dist/services/totp.service.d.ts.map +1 -1
- package/dist/services/totp.service.js +116 -86
- package/dist/services/totp.service.js.map +1 -1
- package/dist/services/user-consent.service.d.ts +12 -0
- package/dist/services/user-consent.service.d.ts.map +1 -1
- package/dist/services/user-consent.service.js +19 -1
- package/dist/services/user-consent.service.js.map +1 -1
- package/dist/services/user-security.service.d.ts +15 -0
- package/dist/services/user-security.service.d.ts.map +1 -0
- package/dist/services/user-security.service.js +57 -0
- package/dist/services/user-security.service.js.map +1 -0
- package/dist/services/user.service.d.ts +6 -4
- package/dist/services/user.service.d.ts.map +1 -1
- package/dist/services/user.service.js +143 -121
- package/dist/services/user.service.js.map +1 -1
- package/frontend/client/assets/{auth-layout-B4h13HhN.js → auth-layout-sea6nww4.js} +1 -1
- package/frontend/client/assets/{auth-page-header-BVY4zRzF.js → auth-page-header-CV85AJLW.js} +1 -1
- package/frontend/client/assets/document-navigation-FZbb5ldf.js +1 -0
- package/frontend/client/assets/i18n-vfKY-byx.js +1 -0
- package/frontend/client/assets/language-selector-Jso2cQNI.js +1 -0
- package/frontend/client/assets/manifest-90703545.js +1 -0
- package/frontend/client/assets/oauth-search-DebNssaC.js +1 -0
- package/frontend/client/assets/{passkey-CWcdr7Vy.js → passkey-CJhT-7yO.js} +1 -1
- package/frontend/client/assets/{promise-EbDcmV0j.js → promise-BP9iSIs-.js} +1 -1
- package/frontend/client/assets/{root-C2SlHCkE.js → root-BkavuloG.js} +1 -1
- package/frontend/client/assets/{route-3gQ9Nsqa.js → route-B0udr9eT.js} +1 -1
- package/frontend/client/assets/route-B3Uv9aTa.js +1 -0
- package/frontend/client/assets/{route-DSD60oyb.js → route-B6hIfgxz.js} +1 -1
- package/frontend/client/assets/{route-DO38I3ML.js → route-BEWds2g-.js} +1 -1
- package/frontend/client/assets/route-Bm9LsorH.js +1 -0
- package/frontend/client/assets/route-Btv5Y69z.js +1 -0
- package/frontend/client/assets/route-BvyDzziE.js +1 -0
- package/frontend/client/assets/route-C6kG9u7j.js +1 -0
- package/frontend/client/assets/route-C7C3Z0vI.js +1 -0
- package/frontend/client/assets/{route-DQpLeFuG.js → route-CVyefM3x.js} +1 -1
- package/frontend/client/assets/{route-CkpB3-_U.js → route-CXth2Wqz.js} +1 -1
- package/frontend/client/assets/{route-9FLiqn21.js → route-Clxc1C2d.js} +1 -1
- package/frontend/client/assets/route-D0IqOurp.js +1 -0
- package/frontend/client/assets/route-DHmYUnJR.js +1 -0
- package/frontend/client/assets/route-DTjZQ_Fl.js +1 -0
- package/frontend/client/assets/route-D_dTeu1b.js +1 -0
- package/frontend/client/assets/{route-CrswLAAa.js → route-Dj8gVemC.js} +1 -1
- package/frontend/client/assets/{route-BUM2hTU8.js → route-DnhPlHOi.js} +1 -1
- package/frontend/client/assets/route-FY92YQhF.js +1 -0
- package/frontend/client/assets/{route-DH6kQz8L.js → route-PcLpZHbT.js} +1 -1
- package/frontend/client/assets/{route-bKG0wKRh.js → route-qpE7i22X.js} +1 -1
- package/frontend/client/assets/{route-3IIrVTOK.js → route-wK89gmoS.js} +1 -1
- package/frontend/client/assets/security-error-message-CMsTsiWf.js +1 -0
- package/frontend/client/assets/{shell-header-bar-Bg85QIAq.js → shell-header-bar-DRx10tE5.js} +1 -1
- package/frontend/client/assets/{terms-DV0oDTRf.js → terms-Bu9Itxxs.js} +1 -1
- package/frontend/client/assets/{use-totp-setup-D7XZ6Nos.js → use-totp-setup-CoOXWOcT.js} +1 -1
- package/frontend/server/assets/{hydration-Cvbp7-6s.js → hydration-DWMjpNav.js} +1 -1
- package/frontend/server/assets/{root-loader.server-DaTcVcNU.js → root-loader.server-B4OqoLGG.js} +3 -3
- package/frontend/server/assets/{route-runtime.server-CEa264cW.js → route-runtime.server-03_pjVDT.js} +1 -1
- package/frontend/server/assets/{session-QqvIIQ6R.js → session-sJkmzJie.js} +51 -57
- package/frontend/server/index.js +337 -403
- package/package.json +1 -1
- package/frontend/client/assets/authorization-context-banner-az4f8FCY.js +0 -1
- package/frontend/client/assets/document-navigation-Cnp3Alf0.js +0 -1
- package/frontend/client/assets/i18n-CMepi_uj.js +0 -1
- package/frontend/client/assets/language-selector-Chn-k7Pw.js +0 -1
- package/frontend/client/assets/manifest-8c4a603f.js +0 -1
- package/frontend/client/assets/oauth-search-DybZ6VWp.js +0 -1
- package/frontend/client/assets/route-BFU8OK2a.js +0 -1
- package/frontend/client/assets/route-BKI6LDOW.js +0 -1
- package/frontend/client/assets/route-CusK9Y2K.js +0 -1
- package/frontend/client/assets/route-DEVG2czp.js +0 -1
- package/frontend/client/assets/route-DjCJn53Y.js +0 -1
- package/frontend/client/assets/route-E-_SSP-x.js +0 -1
- package/frontend/client/assets/route-J9z_OG4L.js +0 -1
- package/frontend/client/assets/route-LjqDZz5f.js +0 -1
- package/frontend/client/assets/route-N586tYcn.js +0 -1
- package/frontend/client/assets/route-nHjY3_n0.js +0 -1
- package/frontend/client/assets/route-sHm4cfOd.js +0 -1
|
@@ -3,6 +3,7 @@ import z from 'zod';
|
|
|
3
3
|
import { isEmailAllowed } from '../lib/email-pattern.js';
|
|
4
4
|
import { generatePKCE } from '../lib/pkce.js';
|
|
5
5
|
import { e, IssuaryError } from '../schemas/error.js';
|
|
6
|
+
import { authenticationMethods, withUserSecurity, } from './user-security.service.js';
|
|
6
7
|
function parseEmailVerified(value) {
|
|
7
8
|
if (typeof value === 'boolean') {
|
|
8
9
|
return value;
|
|
@@ -67,7 +68,7 @@ export class OAuthConnectService {
|
|
|
67
68
|
/**
|
|
68
69
|
* Process an OAuth callback: validate session, exchange tokens, and
|
|
69
70
|
* determine the appropriate next action (redirect, login, link, terms).
|
|
70
|
-
*
|
|
71
|
+
* The caller completes database mutations and browser state in one transaction.
|
|
71
72
|
*/
|
|
72
73
|
async processOAuthCallback(params) {
|
|
73
74
|
const { provider, code, state, oauthSession, userSub, requestUrl } = params;
|
|
@@ -88,12 +89,23 @@ export class OAuthConnectService {
|
|
|
88
89
|
if (!userSub) {
|
|
89
90
|
throw new e.Unauthorized.Error();
|
|
90
91
|
}
|
|
91
|
-
|
|
92
|
+
if (oauthSession.linkSubject !== userSub ||
|
|
93
|
+
!oauthSession.linkEpoch ||
|
|
94
|
+
!params.completeLink)
|
|
95
|
+
throw new e.Unauthorized.Error();
|
|
96
|
+
await params.completeLink(async () => {
|
|
97
|
+
const user = await this.mikro.user.findOneOrFail({ sub: userSub }, { refresh: true });
|
|
98
|
+
if (user.token_epoch !== oauthSession.linkEpoch)
|
|
99
|
+
throw new e.Unauthorized.Error();
|
|
100
|
+
await this.linkOAuthAccount(userSub, provider, tokens, userInfo);
|
|
101
|
+
});
|
|
92
102
|
const returnUrl = oauthSession.returnUrl || '/profile';
|
|
93
103
|
return { action: 'link_complete', returnUrl };
|
|
94
104
|
}
|
|
105
|
+
// Capture the linked identity and its authentication epoch in one joined read.
|
|
106
|
+
const loginProof = await this.prepareAuthentication(provider, userInfo);
|
|
95
107
|
// Check if this would be a new user
|
|
96
|
-
const isNewUser =
|
|
108
|
+
const isNewUser = loginProof.kind === 'registration';
|
|
97
109
|
// For new users, check registration enabled and email allowlist
|
|
98
110
|
if (isNewUser) {
|
|
99
111
|
const { enabled, allowed_email_patterns } = this.config.registration;
|
|
@@ -111,71 +123,77 @@ export class OAuthConnectService {
|
|
|
111
123
|
// Load terms once and reuse
|
|
112
124
|
const allTerms = await this.termsService.getGlobalTerms();
|
|
113
125
|
const explicitTerms = await this.termsService.getExplicitTerms(allTerms);
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
termsUrl.searchParams.set('
|
|
126
|
+
const authenticate = async () => {
|
|
127
|
+
if (isNewUser && explicitTerms.length > 0) {
|
|
128
|
+
await this.assertNewIdentity(provider, userInfo);
|
|
129
|
+
// New user with explicit terms: persist to DB
|
|
130
|
+
const pendingToken = await this.mikro.pendingOAuthRegistration.createPendingRegistration({
|
|
131
|
+
providerId: provider,
|
|
132
|
+
accessToken: tokens.access_token,
|
|
133
|
+
refreshToken: tokens.refresh_token,
|
|
134
|
+
expiresIn: tokens.expires_in,
|
|
135
|
+
tokenType: tokens.token_type,
|
|
136
|
+
userInfo: {
|
|
137
|
+
id: userInfo.id,
|
|
138
|
+
email: userInfo.email,
|
|
139
|
+
email_verified: userInfo.email_verified,
|
|
140
|
+
name: userInfo.name,
|
|
141
|
+
picture: userInfo.picture,
|
|
142
|
+
},
|
|
143
|
+
returnUrl: oauthSession.returnUrl,
|
|
144
|
+
expiresAt: new Date(Date.now() + 60 * 60 * 1000),
|
|
145
|
+
});
|
|
146
|
+
const termsUrl = new URL('/terms', `${this.config.server.public_origin}`);
|
|
147
|
+
termsUrl.searchParams.set('mode', 'complete_registration');
|
|
148
|
+
termsUrl.searchParams.set('registration_token', pendingToken);
|
|
149
|
+
if (oauthSession.returnUrl) {
|
|
150
|
+
termsUrl.searchParams.set('redirect', oauthSession.returnUrl);
|
|
151
|
+
}
|
|
152
|
+
return { action: 'terms_redirect', url: termsUrl.toString() };
|
|
137
153
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
154
|
+
// Result construction and session issuance share the caller's transaction.
|
|
155
|
+
try {
|
|
156
|
+
const result = await this.authenticateWithOAuth(provider, tokens, userInfo, loginProof);
|
|
157
|
+
// Check if existing user needs to see terms page
|
|
158
|
+
if (!result.isNewUser && explicitTerms.length > 0) {
|
|
159
|
+
const pendingTerms = await this.termsService.getPendingRequiredTerms(result.user.sub);
|
|
160
|
+
const explicitTermIds = new Set(explicitTerms.map((t) => t.id));
|
|
161
|
+
const shouldRedirectToTerms = pendingTerms.some((id) => explicitTermIds.has(id));
|
|
162
|
+
if (shouldRedirectToTerms) {
|
|
163
|
+
const url = new URL(requestUrl);
|
|
164
|
+
const termsUrl = new URL('/terms', `${url.protocol}//${url.host}`);
|
|
165
|
+
if (oauthSession.returnUrl) {
|
|
166
|
+
termsUrl.searchParams.set('redirect', oauthSession.returnUrl);
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
action: 'login_terms_redirect',
|
|
170
|
+
userSub: result.user.sub,
|
|
171
|
+
userEpoch: result.user.token_epoch,
|
|
172
|
+
termsUrl: termsUrl.toString(),
|
|
173
|
+
};
|
|
153
174
|
}
|
|
154
|
-
return {
|
|
155
|
-
action: 'login_terms_redirect',
|
|
156
|
-
userSub: result.user.sub,
|
|
157
|
-
termsUrl: termsUrl.toString(),
|
|
158
|
-
};
|
|
159
175
|
}
|
|
176
|
+
return {
|
|
177
|
+
action: 'login_complete',
|
|
178
|
+
userSub: result.user.sub,
|
|
179
|
+
userEpoch: result.user.token_epoch,
|
|
180
|
+
returnUrl: oauthSession.returnUrl,
|
|
181
|
+
};
|
|
160
182
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const errorUrl = new URL('/login', this.config.server.public_origin);
|
|
171
|
-
errorUrl.searchParams.set('oauth_error', 'registration_email_not_allowed');
|
|
172
|
-
if (oauthSession.returnUrl) {
|
|
173
|
-
errorUrl.searchParams.set('redirect', oauthSession.returnUrl);
|
|
183
|
+
catch (err) {
|
|
184
|
+
if (err instanceof IssuaryError &&
|
|
185
|
+
err.code === 'REGISTRATION_EMAIL_NOT_ALLOWED') {
|
|
186
|
+
const errorUrl = new URL('/login', this.config.server.public_origin);
|
|
187
|
+
errorUrl.searchParams.set('oauth_error', 'registration_email_not_allowed');
|
|
188
|
+
if (oauthSession.returnUrl) {
|
|
189
|
+
errorUrl.searchParams.set('redirect', oauthSession.returnUrl);
|
|
190
|
+
}
|
|
191
|
+
return { action: 'error_redirect', url: errorUrl.toString() };
|
|
174
192
|
}
|
|
175
|
-
|
|
193
|
+
throw err;
|
|
176
194
|
}
|
|
177
|
-
|
|
178
|
-
|
|
195
|
+
};
|
|
196
|
+
return params.completeAuthentication(loginProof, authenticate);
|
|
179
197
|
}
|
|
180
198
|
/**
|
|
181
199
|
* Get all enabled OAuth providers
|
|
@@ -428,71 +446,110 @@ export class OAuthConnectService {
|
|
|
428
446
|
picture: picture || undefined,
|
|
429
447
|
};
|
|
430
448
|
}
|
|
449
|
+
async prepareExistingAuthentication(providerId, providerUserId) {
|
|
450
|
+
const link = await this.mikro.userOAuth.findOne({
|
|
451
|
+
provider_name: providerId,
|
|
452
|
+
provider_user_id: providerUserId,
|
|
453
|
+
}, { populate: ['user'], strategy: 'joined', refresh: true });
|
|
454
|
+
if (!link)
|
|
455
|
+
return null;
|
|
456
|
+
const user = link.user.getEntity();
|
|
457
|
+
return {
|
|
458
|
+
kind: 'linked',
|
|
459
|
+
linkId: link.id,
|
|
460
|
+
providerId,
|
|
461
|
+
providerUserId,
|
|
462
|
+
userSub: user.sub,
|
|
463
|
+
userEpoch: user.token_epoch,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
async prepareAuthentication(providerId, userInfo) {
|
|
467
|
+
const linked = await this.prepareExistingAuthentication(providerId, userInfo.id);
|
|
468
|
+
if (linked)
|
|
469
|
+
return linked;
|
|
470
|
+
const user = await this.mikro.user.findOne({ email: userInfo.email }, { refresh: true });
|
|
471
|
+
if (user)
|
|
472
|
+
return {
|
|
473
|
+
kind: 'auto_link',
|
|
474
|
+
providerId,
|
|
475
|
+
providerUserId: userInfo.id,
|
|
476
|
+
userSub: user.sub,
|
|
477
|
+
userEpoch: user.token_epoch,
|
|
478
|
+
email: userInfo.email,
|
|
479
|
+
};
|
|
480
|
+
return {
|
|
481
|
+
kind: 'registration',
|
|
482
|
+
providerId,
|
|
483
|
+
providerUserId: userInfo.id,
|
|
484
|
+
email: userInfo.email,
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
async assertNewIdentity(providerId, userInfo) {
|
|
488
|
+
if ((await this.mikro.user.findOne({ email: userInfo.email })) ||
|
|
489
|
+
(await this.mikro.userOAuth.findByProviderUserId(providerId, userInfo.id)))
|
|
490
|
+
throw new e.OAuthSessionExpired.Error();
|
|
491
|
+
}
|
|
431
492
|
/**
|
|
432
493
|
* Authenticate with OAuth - login or register user
|
|
433
494
|
*/
|
|
434
|
-
async authenticateWithOAuth(providerId, tokens, userInfo) {
|
|
495
|
+
async authenticateWithOAuth(providerId, tokens, userInfo, preparedProof) {
|
|
435
496
|
const provider = this.getProvider(providerId);
|
|
436
497
|
// Reject if the OAuth provider has not verified the user's email
|
|
437
498
|
if (!userInfo.email_verified) {
|
|
438
499
|
throw new e.OAuthEmailNotVerified.Error();
|
|
439
500
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
:
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
501
|
+
const proof = preparedProof ?? (await this.prepareAuthentication(providerId, userInfo));
|
|
502
|
+
if (proof.providerId !== providerId || proof.providerUserId !== userInfo.id)
|
|
503
|
+
throw new e.OAuthSessionExpired.Error();
|
|
504
|
+
if (proof.kind === 'linked') {
|
|
505
|
+
return withUserSecurity(this.mikro, proof.userSub, async (user) => {
|
|
506
|
+
if (user.deleted_at || user.token_epoch !== proof.userEpoch)
|
|
507
|
+
throw new e.OAuthSessionExpired.Error();
|
|
508
|
+
const link = await this.mikro.userOAuth.findOne({
|
|
509
|
+
id: proof.linkId,
|
|
510
|
+
user: proof.userSub,
|
|
511
|
+
provider_name: providerId,
|
|
512
|
+
provider_user_id: userInfo.id,
|
|
513
|
+
}, { refresh: true });
|
|
514
|
+
if (!link ||
|
|
515
|
+
proof.providerId !== providerId ||
|
|
516
|
+
proof.providerUserId !== userInfo.id)
|
|
517
|
+
throw new e.OAuthSessionExpired.Error();
|
|
518
|
+
await this.mikro.userOAuth.updateTokens(link, {
|
|
519
|
+
accessToken: tokens.access_token,
|
|
520
|
+
refreshToken: tokens.refresh_token || '',
|
|
521
|
+
expiresAt: tokens.expires_in
|
|
522
|
+
? new Date(Date.now() + tokens.expires_in * 1000)
|
|
523
|
+
: null,
|
|
524
|
+
});
|
|
525
|
+
return {
|
|
526
|
+
isNewUser: false,
|
|
527
|
+
user: await this.authenticationResultUser(user),
|
|
528
|
+
};
|
|
529
|
+
}, { includeDeleted: true });
|
|
530
|
+
}
|
|
531
|
+
if (proof.email !== userInfo.email)
|
|
532
|
+
throw new e.OAuthSessionExpired.Error();
|
|
533
|
+
if (proof.kind === 'auto_link') {
|
|
534
|
+
if (provider.email_conflict_strategy === 'require_link')
|
|
471
535
|
throw new e.OAuthEmailConflict.Error();
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
});
|
|
490
|
-
await this.mikro.em.flush();
|
|
491
|
-
return {
|
|
492
|
-
isNewUser: false,
|
|
493
|
-
user: await this.userService.getSessionUserBySub(existingUser.sub),
|
|
494
|
-
};
|
|
495
|
-
}
|
|
536
|
+
return withUserSecurity(this.mikro, proof.userSub, async (fresh) => {
|
|
537
|
+
if (fresh.deleted_at ||
|
|
538
|
+
fresh.token_epoch !== proof.userEpoch ||
|
|
539
|
+
fresh.email !== proof.email)
|
|
540
|
+
throw new e.OAuthSessionExpired.Error();
|
|
541
|
+
if (await this.mikro.userOAuth.findByProviderUserId(providerId, userInfo.id))
|
|
542
|
+
throw new e.OAuthSessionExpired.Error();
|
|
543
|
+
fresh.email_verified = true;
|
|
544
|
+
await this.linkOAuthAccount(fresh.sub, providerId, tokens, userInfo);
|
|
545
|
+
await this.mikro.em.flush();
|
|
546
|
+
return {
|
|
547
|
+
isNewUser: false,
|
|
548
|
+
user: await this.authenticationResultUser(fresh),
|
|
549
|
+
};
|
|
550
|
+
}, { includeDeleted: true });
|
|
551
|
+
}
|
|
552
|
+
await this.assertNewIdentity(providerId, userInfo);
|
|
496
553
|
// Check if registration is enabled and email is allowed
|
|
497
554
|
if (!this.config.registration.enabled) {
|
|
498
555
|
throw new e.RegistrationDisabled.Error();
|
|
@@ -527,7 +584,7 @@ export class OAuthConnectService {
|
|
|
527
584
|
});
|
|
528
585
|
return {
|
|
529
586
|
isNewUser: true,
|
|
530
|
-
user: await this.
|
|
587
|
+
user: await this.authenticationResultUser(newUser),
|
|
531
588
|
};
|
|
532
589
|
}
|
|
533
590
|
/**
|
|
@@ -557,61 +614,15 @@ export class OAuthConnectService {
|
|
|
557
614
|
if (!userInfo.email_verified) {
|
|
558
615
|
throw new e.OAuthEmailNotVerified.Error();
|
|
559
616
|
}
|
|
560
|
-
//
|
|
617
|
+
// A registration token proves a new-account flow, never a fresh login to
|
|
618
|
+
// an account created or recovered since that flow began.
|
|
619
|
+
this.getProvider(providerId);
|
|
561
620
|
const existingOAuth = await this.mikro.userOAuth.findByProviderUserId(providerId, userInfo.id);
|
|
562
|
-
if (existingOAuth) {
|
|
563
|
-
// User was created in the meantime, just return existing user
|
|
564
|
-
const user = await existingOAuth.user.load({
|
|
565
|
-
populate: ['password_hash'],
|
|
566
|
-
});
|
|
567
|
-
if (!user) {
|
|
568
|
-
throw new e.UserNotFound.Error();
|
|
569
|
-
}
|
|
570
|
-
return {
|
|
571
|
-
isNewUser: false,
|
|
572
|
-
user: await this.userService.getSessionUserBySub(user.sub),
|
|
573
|
-
};
|
|
574
|
-
}
|
|
575
|
-
// Check if user with same email exists
|
|
576
621
|
const existingUser = await this.mikro.user.findOne({
|
|
577
622
|
email: userInfo.email,
|
|
578
623
|
});
|
|
579
|
-
if (existingUser)
|
|
580
|
-
|
|
581
|
-
const provider = this.getProvider(providerId);
|
|
582
|
-
if (provider.email_conflict_strategy === 'require_link') {
|
|
583
|
-
throw new e.OAuthEmailConflict.Error();
|
|
584
|
-
}
|
|
585
|
-
if (!existingUser.email_verified) {
|
|
586
|
-
existingUser.email_verified = true;
|
|
587
|
-
}
|
|
588
|
-
await this.mikro.userOAuth.linkAccount({
|
|
589
|
-
userSub: existingUser.sub,
|
|
590
|
-
providerName: providerId,
|
|
591
|
-
providerUserId: userInfo.id,
|
|
592
|
-
accessToken: tokens.access_token,
|
|
593
|
-
refreshToken: tokens.refresh_token || '',
|
|
594
|
-
expiresAt: tokens.expires_in
|
|
595
|
-
? new Date(Date.now() + tokens.expires_in * 1000)
|
|
596
|
-
: null,
|
|
597
|
-
});
|
|
598
|
-
// Record all consents for existing user (load terms once)
|
|
599
|
-
const terms = await this.termsService.getGlobalTerms();
|
|
600
|
-
await this.termsService.recordConsents({
|
|
601
|
-
userSub: existingUser.sub,
|
|
602
|
-
consents,
|
|
603
|
-
terms,
|
|
604
|
-
});
|
|
605
|
-
await this.termsService.recordImplicitConsents({
|
|
606
|
-
userSub: existingUser.sub,
|
|
607
|
-
terms,
|
|
608
|
-
});
|
|
609
|
-
await this.mikro.em.flush();
|
|
610
|
-
return {
|
|
611
|
-
isNewUser: false,
|
|
612
|
-
user: await this.userService.getSessionUserBySub(existingUser.sub),
|
|
613
|
-
};
|
|
614
|
-
}
|
|
624
|
+
if (existingOAuth || existingUser)
|
|
625
|
+
throw new e.OAuthSessionExpired.Error();
|
|
615
626
|
// Check if registration is enabled and email is allowed
|
|
616
627
|
if (!this.config.registration.enabled) {
|
|
617
628
|
throw new e.RegistrationDisabled.Error();
|
|
@@ -650,69 +661,82 @@ export class OAuthConnectService {
|
|
|
650
661
|
userSub: newUser.sub,
|
|
651
662
|
terms,
|
|
652
663
|
});
|
|
664
|
+
await this.mikro.pendingOAuthRegistration.invalidateIdentity(providerId, userInfo.id, userInfo.email);
|
|
653
665
|
return {
|
|
654
666
|
isNewUser: true,
|
|
655
|
-
user: await this.
|
|
667
|
+
user: await this.authenticationResultUser(newUser),
|
|
656
668
|
};
|
|
657
669
|
}
|
|
658
670
|
/**
|
|
659
671
|
* Link OAuth account to existing user
|
|
660
672
|
*/
|
|
673
|
+
async authenticationResultUser(user) {
|
|
674
|
+
const token_epoch = user.token_epoch;
|
|
675
|
+
return {
|
|
676
|
+
...(await this.userService.getSessionUserBySub(user.sub)),
|
|
677
|
+
token_epoch,
|
|
678
|
+
};
|
|
679
|
+
}
|
|
661
680
|
async linkOAuthAccount(userSub, providerId, tokens, userInfo) {
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
681
|
+
return withUserSecurity(this.mikro, userSub, async () => {
|
|
682
|
+
// Check if OAuth account is already linked to another user
|
|
683
|
+
const existingOAuth = await this.mikro.userOAuth.findByProviderUserId(providerId, userInfo.id);
|
|
684
|
+
if (existingOAuth && existingOAuth.user.sub !== userSub) {
|
|
685
|
+
throw new e.OAuthAccountAlreadyLinked.Error();
|
|
686
|
+
}
|
|
687
|
+
// Get user
|
|
688
|
+
const user = await this.mikro.user.findOneOrFail({ sub: userSub }, { failHandler: () => new e.UserNotFound.Error() });
|
|
689
|
+
// Check if already linked
|
|
690
|
+
const existingLink = await this.mikro.userOAuth.findByUserAndProvider(userSub, providerId);
|
|
691
|
+
if (existingLink) {
|
|
692
|
+
// Update tokens
|
|
693
|
+
await this.mikro.userOAuth.updateTokens(existingLink, {
|
|
694
|
+
accessToken: tokens.access_token,
|
|
695
|
+
refreshToken: tokens.refresh_token || '',
|
|
696
|
+
expiresAt: tokens.expires_in
|
|
697
|
+
? new Date(Date.now() + tokens.expires_in * 1000)
|
|
698
|
+
: null,
|
|
699
|
+
});
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
// Link OAuth account
|
|
703
|
+
await this.mikro.userOAuth.linkAccount({
|
|
704
|
+
userSub: user.sub,
|
|
705
|
+
providerName: providerId,
|
|
706
|
+
providerUserId: userInfo.id,
|
|
674
707
|
accessToken: tokens.access_token,
|
|
675
708
|
refreshToken: tokens.refresh_token || '',
|
|
676
709
|
expiresAt: tokens.expires_in
|
|
677
710
|
? new Date(Date.now() + tokens.expires_in * 1000)
|
|
678
711
|
: null,
|
|
679
712
|
});
|
|
680
|
-
return;
|
|
681
|
-
}
|
|
682
|
-
// Link OAuth account
|
|
683
|
-
await this.mikro.userOAuth.linkAccount({
|
|
684
|
-
userSub: user.sub,
|
|
685
|
-
providerName: providerId,
|
|
686
|
-
providerUserId: userInfo.id,
|
|
687
|
-
accessToken: tokens.access_token,
|
|
688
|
-
refreshToken: tokens.refresh_token || '',
|
|
689
|
-
expiresAt: tokens.expires_in
|
|
690
|
-
? new Date(Date.now() + tokens.expires_in * 1000)
|
|
691
|
-
: null,
|
|
692
713
|
});
|
|
693
714
|
}
|
|
694
715
|
/**
|
|
695
716
|
* Unlink OAuth account from user
|
|
696
717
|
*/
|
|
697
718
|
async unlinkOAuthAccount(userSub, providerId) {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
719
|
+
return withUserSecurity(this.mikro, userSub, async () => {
|
|
720
|
+
// Get user from database (config users are now synced to DB)
|
|
721
|
+
const user = await this.mikro.user.findOneOrFail({ sub: userSub }, {
|
|
722
|
+
failHandler: () => new e.UserNotFound.Error(),
|
|
723
|
+
populate: ['password_hash'],
|
|
724
|
+
});
|
|
725
|
+
// Check if OAuth account is linked
|
|
726
|
+
const oauthAccount = await this.mikro.userOAuth.findByUserAndProvider(userSub, providerId);
|
|
727
|
+
if (!oauthAccount) {
|
|
728
|
+
throw new e.OAuthAccountNotLinked.Error();
|
|
729
|
+
}
|
|
730
|
+
// Check if this is the last auth method
|
|
731
|
+
const methods = await authenticationMethods(this.mikro, this.config, user);
|
|
732
|
+
const enabled = this.config.identity_providers.some((provider) => provider.id === providerId && provider.enabled);
|
|
733
|
+
if (methods.oauth - Number(enabled) <= 0 &&
|
|
734
|
+
!methods.password &&
|
|
735
|
+
methods.passkeys === 0) {
|
|
736
|
+
throw new e.CannotUnlinkLastAuthMethod.Error();
|
|
737
|
+
}
|
|
738
|
+
await this.mikro.userOAuth.unlinkAccount(userSub, providerId);
|
|
702
739
|
});
|
|
703
|
-
// Check if OAuth account is linked
|
|
704
|
-
const oauthAccount = await this.mikro.userOAuth.findByUserAndProvider(userSub, providerId);
|
|
705
|
-
if (!oauthAccount) {
|
|
706
|
-
throw new e.OAuthAccountNotLinked.Error();
|
|
707
|
-
}
|
|
708
|
-
// Check if this is the last auth method
|
|
709
|
-
const oauthCount = await this.mikro.userOAuth.countByUser(userSub);
|
|
710
|
-
const hasPassword = user.hasPassword();
|
|
711
|
-
// If only one OAuth and no password, can't unlink
|
|
712
|
-
if (oauthCount <= 1 && !hasPassword) {
|
|
713
|
-
throw new e.CannotUnlinkLastAuthMethod.Error();
|
|
714
|
-
}
|
|
715
|
-
await this.mikro.userOAuth.unlinkAccount(userSub, providerId);
|
|
716
740
|
}
|
|
717
741
|
/**
|
|
718
742
|
* Get all OAuth accounts linked to a user
|