@portaidentity/server 1.7.3 → 1.8.0
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/CHANGELOG.md +5 -0
- package/dist/applications/index.d.ts +2 -2
- package/dist/applications/index.d.ts.map +1 -1
- package/dist/applications/index.js +2 -2
- package/dist/applications/index.js.map +1 -1
- package/dist/applications/repository.d.ts +49 -4
- package/dist/applications/repository.d.ts.map +1 -1
- package/dist/applications/repository.js +148 -10
- package/dist/applications/repository.js.map +1 -1
- package/dist/applications/service.d.ts +35 -17
- package/dist/applications/service.d.ts.map +1 -1
- package/dist/applications/service.js +144 -35
- package/dist/applications/service.js.map +1 -1
- package/dist/applications/types.d.ts +1 -1
- package/dist/applications/types.d.ts.map +1 -1
- package/dist/applications/validators.d.ts +14 -0
- package/dist/applications/validators.d.ts.map +1 -0
- package/dist/applications/validators.js +14 -0
- package/dist/applications/validators.js.map +1 -0
- package/dist/auth/effective-branding.d.ts +35 -0
- package/dist/auth/effective-branding.d.ts.map +1 -0
- package/dist/auth/effective-branding.js +81 -0
- package/dist/auth/effective-branding.js.map +1 -0
- package/dist/auth/email-service.d.ts +3 -8
- package/dist/auth/email-service.d.ts.map +1 -1
- package/dist/auth/email-service.js +22 -30
- package/dist/auth/email-service.js.map +1 -1
- package/dist/auth/i18n.d.ts +5 -0
- package/dist/auth/i18n.d.ts.map +1 -1
- package/dist/auth/i18n.js +6 -5
- package/dist/auth/i18n.js.map +1 -1
- package/dist/auth/rate-limiter.d.ts +6 -10
- package/dist/auth/rate-limiter.d.ts.map +1 -1
- package/dist/auth/rate-limiter.js +12 -16
- package/dist/auth/rate-limiter.js.map +1 -1
- package/dist/auth/recovery-job-processor.d.ts.map +1 -1
- package/dist/auth/recovery-job-processor.js +1 -1
- package/dist/auth/recovery-job-processor.js.map +1 -1
- package/dist/auth/template-engine.d.ts +3 -1
- package/dist/auth/template-engine.d.ts.map +1 -1
- package/dist/auth/template-engine.js +1 -1
- package/dist/auth/template-engine.js.map +1 -1
- package/dist/cli/commands/init.d.ts +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +12 -12
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/error-handler.d.ts +3 -2
- package/dist/cli/error-handler.d.ts.map +1 -1
- package/dist/cli/error-handler.js +9 -2
- package/dist/cli/error-handler.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/clients/index.d.ts +1 -1
- package/dist/clients/index.js +1 -1
- package/dist/clients/repository.d.ts +18 -0
- package/dist/clients/repository.d.ts.map +1 -1
- package/dist/clients/repository.js +36 -0
- package/dist/clients/repository.js.map +1 -1
- package/dist/clients/secret-repository.d.ts +35 -8
- package/dist/clients/secret-repository.d.ts.map +1 -1
- package/dist/clients/secret-repository.js +69 -16
- package/dist/clients/secret-repository.js.map +1 -1
- package/dist/clients/secret-service.d.ts +5 -9
- package/dist/clients/secret-service.d.ts.map +1 -1
- package/dist/clients/secret-service.js +13 -22
- package/dist/clients/secret-service.js.map +1 -1
- package/dist/clients/service.d.ts +10 -13
- package/dist/clients/service.d.ts.map +1 -1
- package/dist/clients/service.js +112 -40
- package/dist/clients/service.js.map +1 -1
- package/dist/clients/types.d.ts +1 -1
- package/dist/clients/types.d.ts.map +1 -1
- package/dist/clients/validators.d.ts +83 -1
- package/dist/clients/validators.d.ts.map +1 -1
- package/dist/clients/validators.js +110 -0
- package/dist/clients/validators.js.map +1 -1
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/schema.d.ts +1 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +23 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/custom-claims/repository.d.ts +14 -9
- package/dist/custom-claims/repository.d.ts.map +1 -1
- package/dist/custom-claims/repository.js +38 -11
- package/dist/custom-claims/repository.js.map +1 -1
- package/dist/custom-claims/service.d.ts +11 -6
- package/dist/custom-claims/service.d.ts.map +1 -1
- package/dist/custom-claims/service.js +43 -20
- package/dist/custom-claims/service.js.map +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/admin-permissions.d.ts +12 -7
- package/dist/lib/admin-permissions.d.ts.map +1 -1
- package/dist/lib/admin-permissions.js +26 -16
- package/dist/lib/admin-permissions.js.map +1 -1
- package/dist/lib/audit-log.d.ts +2 -2
- package/dist/lib/audit-log.d.ts.map +1 -1
- package/dist/lib/audit-log.js +1 -1
- package/dist/lib/audit-log.js.map +1 -1
- package/dist/lib/authority-revocation.d.ts +18 -0
- package/dist/lib/authority-revocation.d.ts.map +1 -0
- package/dist/lib/authority-revocation.js +37 -0
- package/dist/lib/authority-revocation.js.map +1 -0
- package/dist/lib/branding-assets.d.ts +35 -5
- package/dist/lib/branding-assets.d.ts.map +1 -1
- package/dist/lib/branding-assets.js +33 -26
- package/dist/lib/branding-assets.js.map +1 -1
- package/dist/lib/bulk-operations.d.ts +1 -1
- package/dist/lib/bulk-operations.d.ts.map +1 -1
- package/dist/lib/bulk-operations.js +1 -13
- package/dist/lib/bulk-operations.js.map +1 -1
- package/dist/lib/cursor.d.ts +2 -0
- package/dist/lib/cursor.d.ts.map +1 -1
- package/dist/lib/cursor.js +2 -7
- package/dist/lib/cursor.js.map +1 -1
- package/dist/lib/database.d.ts.map +1 -1
- package/dist/lib/database.js +5 -0
- package/dist/lib/database.js.map +1 -1
- package/dist/lib/deletion-cleanup.d.ts +43 -0
- package/dist/lib/deletion-cleanup.d.ts.map +1 -0
- package/dist/lib/deletion-cleanup.js +207 -0
- package/dist/lib/deletion-cleanup.js.map +1 -0
- package/dist/lib/image-validator.d.ts +3 -1
- package/dist/lib/image-validator.d.ts.map +1 -1
- package/dist/lib/image-validator.js +32 -19
- package/dist/lib/image-validator.js.map +1 -1
- package/dist/lib/log-format.d.ts +20 -0
- package/dist/lib/log-format.d.ts.map +1 -0
- package/dist/lib/log-format.js +22 -0
- package/dist/lib/log-format.js.map +1 -0
- package/dist/lib/logger.d.ts +3 -1
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +21 -4
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/redis.d.ts.map +1 -1
- package/dist/lib/redis.js +3 -0
- package/dist/lib/redis.js.map +1 -1
- package/dist/lib/session-tracking.d.ts +73 -11
- package/dist/lib/session-tracking.d.ts.map +1 -1
- package/dist/lib/session-tracking.js +76 -32
- package/dist/lib/session-tracking.js.map +1 -1
- package/dist/lib/signing-key-crypto.d.ts.map +1 -1
- package/dist/lib/signing-key-crypto.js +4 -5
- package/dist/lib/signing-key-crypto.js.map +1 -1
- package/dist/lib/signing-keys.d.ts +3 -4
- package/dist/lib/signing-keys.d.ts.map +1 -1
- package/dist/lib/signing-keys.js +66 -41
- package/dist/lib/signing-keys.js.map +1 -1
- package/dist/lib/super-admin-protection.d.ts +5 -5
- package/dist/lib/super-admin-protection.d.ts.map +1 -1
- package/dist/lib/super-admin-protection.js +6 -9
- package/dist/lib/super-admin-protection.js.map +1 -1
- package/dist/lib/system-config-catalog.d.ts +268 -0
- package/dist/lib/system-config-catalog.d.ts.map +1 -0
- package/dist/lib/system-config-catalog.js +90 -0
- package/dist/lib/system-config-catalog.js.map +1 -0
- package/dist/lib/system-config.d.ts +30 -33
- package/dist/lib/system-config.d.ts.map +1 -1
- package/dist/lib/system-config.js +78 -93
- package/dist/lib/system-config.js.map +1 -1
- package/dist/lib/with-timeout.d.ts +32 -0
- package/dist/lib/with-timeout.d.ts.map +1 -0
- package/dist/lib/with-timeout.js +45 -0
- package/dist/lib/with-timeout.js.map +1 -0
- package/dist/middleware/admin-auth.d.ts +6 -5
- package/dist/middleware/admin-auth.d.ts.map +1 -1
- package/dist/middleware/admin-auth.js +30 -20
- package/dist/middleware/admin-auth.js.map +1 -1
- package/dist/middleware/admin-cors.d.ts +3 -3
- package/dist/middleware/admin-cors.js +3 -3
- package/dist/middleware/admin-mutation-audit.d.ts +3 -2
- package/dist/middleware/admin-mutation-audit.d.ts.map +1 -1
- package/dist/middleware/admin-mutation-audit.js +12 -5
- package/dist/middleware/admin-mutation-audit.js.map +1 -1
- package/dist/middleware/admin-rate-limiter.d.ts +7 -8
- package/dist/middleware/admin-rate-limiter.d.ts.map +1 -1
- package/dist/middleware/admin-rate-limiter.js +7 -8
- package/dist/middleware/admin-rate-limiter.js.map +1 -1
- package/dist/middleware/client-secret-hash.d.ts +10 -29
- package/dist/middleware/client-secret-hash.d.ts.map +1 -1
- package/dist/middleware/client-secret-hash.js +161 -59
- package/dist/middleware/client-secret-hash.js.map +1 -1
- package/dist/middleware/health.d.ts +17 -0
- package/dist/middleware/health.d.ts.map +1 -1
- package/dist/middleware/health.js +25 -21
- package/dist/middleware/health.js.map +1 -1
- package/dist/middleware/ready.d.ts.map +1 -1
- package/dist/middleware/ready.js +1 -12
- package/dist/middleware/ready.js.map +1 -1
- package/dist/middleware/require-existing-organization.d.ts +18 -0
- package/dist/middleware/require-existing-organization.d.ts.map +1 -0
- package/dist/middleware/require-existing-organization.js +38 -0
- package/dist/middleware/require-existing-organization.js.map +1 -0
- package/dist/middleware/require-permission.d.ts.map +1 -1
- package/dist/middleware/require-permission.js +35 -1
- package/dist/middleware/require-permission.js.map +1 -1
- package/dist/middleware/require-user-organization.d.ts.map +1 -1
- package/dist/middleware/require-user-organization.js +4 -2
- package/dist/middleware/require-user-organization.js.map +1 -1
- package/dist/middleware/security-headers.d.ts +18 -0
- package/dist/middleware/security-headers.d.ts.map +1 -1
- package/dist/middleware/security-headers.js +32 -1
- package/dist/middleware/security-headers.js.map +1 -1
- package/dist/middleware/tenant-resolver.d.ts +1 -2
- package/dist/middleware/tenant-resolver.d.ts.map +1 -1
- package/dist/middleware/tenant-resolver.js +1 -5
- package/dist/middleware/tenant-resolver.js.map +1 -1
- package/dist/middleware/token-rate-limiter.d.ts +37 -16
- package/dist/middleware/token-rate-limiter.d.ts.map +1 -1
- package/dist/middleware/token-rate-limiter.js +126 -54
- package/dist/middleware/token-rate-limiter.js.map +1 -1
- package/dist/oidc/account-finder.d.ts +5 -5
- package/dist/oidc/account-finder.d.ts.map +1 -1
- package/dist/oidc/account-finder.js +31 -23
- package/dist/oidc/account-finder.js.map +1 -1
- package/dist/oidc/adapter-factory.d.ts.map +1 -1
- package/dist/oidc/adapter-factory.js +83 -3
- package/dist/oidc/adapter-factory.js.map +1 -1
- package/dist/oidc/configuration.d.ts +3 -8
- package/dist/oidc/configuration.d.ts.map +1 -1
- package/dist/oidc/configuration.js +64 -50
- package/dist/oidc/configuration.js.map +1 -1
- package/dist/oidc/provider.d.ts.map +1 -1
- package/dist/oidc/provider.js +7 -0
- package/dist/oidc/provider.js.map +1 -1
- package/dist/oidc/redis-adapter.d.ts +2 -3
- package/dist/oidc/redis-adapter.d.ts.map +1 -1
- package/dist/oidc/redis-adapter.js +54 -46
- package/dist/oidc/redis-adapter.js.map +1 -1
- package/dist/organizations/branding-url.d.ts +17 -0
- package/dist/organizations/branding-url.d.ts.map +1 -0
- package/dist/organizations/branding-url.js +38 -0
- package/dist/organizations/branding-url.js.map +1 -0
- package/dist/organizations/index.d.ts +2 -2
- package/dist/organizations/index.d.ts.map +1 -1
- package/dist/organizations/index.js +1 -1
- package/dist/organizations/index.js.map +1 -1
- package/dist/organizations/repository.d.ts +22 -32
- package/dist/organizations/repository.d.ts.map +1 -1
- package/dist/organizations/repository.js +64 -45
- package/dist/organizations/repository.js.map +1 -1
- package/dist/organizations/service.d.ts +14 -46
- package/dist/organizations/service.d.ts.map +1 -1
- package/dist/organizations/service.js +60 -112
- package/dist/organizations/service.js.map +1 -1
- package/dist/organizations/types.d.ts +1 -15
- package/dist/organizations/types.d.ts.map +1 -1
- package/dist/organizations/validators.d.ts +41 -0
- package/dist/organizations/validators.d.ts.map +1 -0
- package/dist/organizations/validators.js +48 -0
- package/dist/organizations/validators.js.map +1 -0
- package/dist/portability/apply.d.ts +15 -0
- package/dist/portability/apply.d.ts.map +1 -0
- package/dist/portability/apply.js +274 -0
- package/dist/portability/apply.js.map +1 -0
- package/dist/portability/authorization.d.ts +30 -0
- package/dist/portability/authorization.d.ts.map +1 -0
- package/dist/portability/authorization.js +130 -0
- package/dist/portability/authorization.js.map +1 -0
- package/dist/portability/cleanup.d.ts +29 -0
- package/dist/portability/cleanup.d.ts.map +1 -0
- package/dist/portability/cleanup.js +167 -0
- package/dist/portability/cleanup.js.map +1 -0
- package/dist/portability/export.d.ts +18 -0
- package/dist/portability/export.d.ts.map +1 -0
- package/dist/portability/export.js +125 -0
- package/dist/portability/export.js.map +1 -0
- package/dist/portability/import-repository.d.ts +204 -0
- package/dist/portability/import-repository.d.ts.map +1 -0
- package/dist/portability/import-repository.js +347 -0
- package/dist/portability/import-repository.js.map +1 -0
- package/dist/portability/import-user-client-writers.d.ts +40 -0
- package/dist/portability/import-user-client-writers.d.ts.map +1 -0
- package/dist/portability/import-user-client-writers.js +168 -0
- package/dist/portability/import-user-client-writers.js.map +1 -0
- package/dist/portability/index.d.ts +8 -0
- package/dist/portability/index.d.ts.map +1 -0
- package/dist/portability/index.js +8 -0
- package/dist/portability/index.js.map +1 -0
- package/dist/portability/plan-support.d.ts +137 -0
- package/dist/portability/plan-support.d.ts.map +1 -0
- package/dist/portability/plan-support.js +336 -0
- package/dist/portability/plan-support.js.map +1 -0
- package/dist/portability/plan.d.ts +34 -0
- package/dist/portability/plan.d.ts.map +1 -0
- package/dist/portability/plan.js +450 -0
- package/dist/portability/plan.js.map +1 -0
- package/dist/portability/repository.d.ts +95 -0
- package/dist/portability/repository.d.ts.map +1 -0
- package/dist/portability/repository.js +388 -0
- package/dist/portability/repository.js.map +1 -0
- package/dist/portability/schema.d.ts +589 -0
- package/dist/portability/schema.d.ts.map +1 -0
- package/dist/portability/schema.js +458 -0
- package/dist/portability/schema.js.map +1 -0
- package/dist/portability/types.d.ts +381 -0
- package/dist/portability/types.d.ts.map +1 -0
- package/dist/portability/types.js +19 -0
- package/dist/portability/types.js.map +1 -0
- package/dist/rbac/errors.d.ts +4 -0
- package/dist/rbac/errors.d.ts.map +1 -1
- package/dist/rbac/errors.js +7 -0
- package/dist/rbac/errors.js.map +1 -1
- package/dist/rbac/index.d.ts +3 -3
- package/dist/rbac/index.d.ts.map +1 -1
- package/dist/rbac/index.js +3 -3
- package/dist/rbac/index.js.map +1 -1
- package/dist/rbac/mapping-repository.d.ts +84 -9
- package/dist/rbac/mapping-repository.d.ts.map +1 -1
- package/dist/rbac/mapping-repository.js +222 -55
- package/dist/rbac/mapping-repository.js.map +1 -1
- package/dist/rbac/permission-repository.d.ts +36 -19
- package/dist/rbac/permission-repository.d.ts.map +1 -1
- package/dist/rbac/permission-repository.js +93 -35
- package/dist/rbac/permission-repository.js.map +1 -1
- package/dist/rbac/permission-service.d.ts +18 -19
- package/dist/rbac/permission-service.d.ts.map +1 -1
- package/dist/rbac/permission-service.js +100 -57
- package/dist/rbac/permission-service.js.map +1 -1
- package/dist/rbac/role-repository.d.ts +29 -24
- package/dist/rbac/role-repository.d.ts.map +1 -1
- package/dist/rbac/role-repository.js +66 -43
- package/dist/rbac/role-repository.js.map +1 -1
- package/dist/rbac/role-service.d.ts +35 -32
- package/dist/rbac/role-service.d.ts.map +1 -1
- package/dist/rbac/role-service.js +210 -96
- package/dist/rbac/role-service.js.map +1 -1
- package/dist/rbac/slugs.d.ts +16 -27
- package/dist/rbac/slugs.d.ts.map +1 -1
- package/dist/rbac/slugs.js +36 -59
- package/dist/rbac/slugs.js.map +1 -1
- package/dist/rbac/types.d.ts +2 -4
- package/dist/rbac/types.d.ts.map +1 -1
- package/dist/rbac/types.js.map +1 -1
- package/dist/rbac/user-role-service.d.ts +23 -24
- package/dist/rbac/user-role-service.d.ts.map +1 -1
- package/dist/rbac/user-role-service.js +117 -61
- package/dist/rbac/user-role-service.js.map +1 -1
- package/dist/routes/applications.d.ts +4 -2
- package/dist/routes/applications.d.ts.map +1 -1
- package/dist/routes/applications.js +57 -19
- package/dist/routes/applications.js.map +1 -1
- package/dist/routes/audit.js +1 -1
- package/dist/routes/audit.js.map +1 -1
- package/dist/routes/branding.d.ts +3 -3
- package/dist/routes/branding.d.ts.map +1 -1
- package/dist/routes/branding.js +44 -16
- package/dist/routes/branding.js.map +1 -1
- package/dist/routes/bulk.d.ts +0 -5
- package/dist/routes/bulk.d.ts.map +1 -1
- package/dist/routes/bulk.js +3 -5
- package/dist/routes/bulk.js.map +1 -1
- package/dist/routes/clients.d.ts +4 -4
- package/dist/routes/clients.d.ts.map +1 -1
- package/dist/routes/clients.js +111 -52
- package/dist/routes/clients.js.map +1 -1
- package/dist/routes/config.d.ts +17 -12
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +165 -64
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/custom-claims.d.ts.map +1 -1
- package/dist/routes/custom-claims.js +8 -2
- package/dist/routes/custom-claims.js.map +1 -1
- package/dist/routes/exports.d.ts +2 -1
- package/dist/routes/exports.d.ts.map +1 -1
- package/dist/routes/exports.js +57 -1
- package/dist/routes/exports.js.map +1 -1
- package/dist/routes/imports.d.ts +2 -2
- package/dist/routes/imports.d.ts.map +1 -1
- package/dist/routes/imports.js +95 -40
- package/dist/routes/imports.js.map +1 -1
- package/dist/routes/interactions.d.ts.map +1 -1
- package/dist/routes/interactions.js +16 -34
- package/dist/routes/interactions.js.map +1 -1
- package/dist/routes/invitation.d.ts.map +1 -1
- package/dist/routes/invitation.js +10 -23
- package/dist/routes/invitation.js.map +1 -1
- package/dist/routes/keys.d.ts.map +1 -1
- package/dist/routes/keys.js +26 -13
- package/dist/routes/keys.js.map +1 -1
- package/dist/routes/magic-link.d.ts.map +1 -1
- package/dist/routes/magic-link.js +5 -17
- package/dist/routes/magic-link.js.map +1 -1
- package/dist/routes/organizations.d.ts +1 -2
- package/dist/routes/organizations.d.ts.map +1 -1
- package/dist/routes/organizations.js +43 -104
- package/dist/routes/organizations.js.map +1 -1
- package/dist/routes/password-reset.d.ts.map +1 -1
- package/dist/routes/password-reset.js +13 -35
- package/dist/routes/password-reset.js.map +1 -1
- package/dist/routes/permissions.d.ts +1 -1
- package/dist/routes/permissions.d.ts.map +1 -1
- package/dist/routes/permissions.js +58 -17
- package/dist/routes/permissions.js.map +1 -1
- package/dist/routes/public-branding.d.ts +16 -0
- package/dist/routes/public-branding.d.ts.map +1 -0
- package/dist/routes/public-branding.js +52 -0
- package/dist/routes/public-branding.js.map +1 -0
- package/dist/routes/roles.d.ts +1 -1
- package/dist/routes/roles.d.ts.map +1 -1
- package/dist/routes/roles.js +63 -21
- package/dist/routes/roles.js.map +1 -1
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +23 -12
- package/dist/routes/sessions.js.map +1 -1
- package/dist/routes/two-factor.d.ts.map +1 -1
- package/dist/routes/two-factor.js +91 -38
- package/dist/routes/two-factor.js.map +1 -1
- package/dist/routes/user-roles.d.ts.map +1 -1
- package/dist/routes/user-roles.js +56 -9
- package/dist/routes/user-roles.js.map +1 -1
- package/dist/routes/users.d.ts +4 -8
- package/dist/routes/users.d.ts.map +1 -1
- package/dist/routes/users.js +108 -265
- package/dist/routes/users.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +53 -37
- package/dist/server.js.map +1 -1
- package/dist/two-factor/errors.d.ts +9 -0
- package/dist/two-factor/errors.d.ts.map +1 -1
- package/dist/two-factor/errors.js +12 -0
- package/dist/two-factor/errors.js.map +1 -1
- package/dist/two-factor/index.d.ts +5 -4
- package/dist/two-factor/index.d.ts.map +1 -1
- package/dist/two-factor/index.js +4 -4
- package/dist/two-factor/index.js.map +1 -1
- package/dist/two-factor/repository.d.ts +17 -6
- package/dist/two-factor/repository.d.ts.map +1 -1
- package/dist/two-factor/repository.js +37 -9
- package/dist/two-factor/repository.js.map +1 -1
- package/dist/two-factor/service.d.ts.map +1 -1
- package/dist/two-factor/service.js +26 -19
- package/dist/two-factor/service.js.map +1 -1
- package/dist/two-factor/totp.d.ts +13 -2
- package/dist/two-factor/totp.d.ts.map +1 -1
- package/dist/two-factor/totp.js +20 -7
- package/dist/two-factor/totp.js.map +1 -1
- package/dist/two-factor/types.d.ts +3 -0
- package/dist/two-factor/types.d.ts.map +1 -1
- package/dist/two-factor/types.js +5 -0
- package/dist/two-factor/types.js.map +1 -1
- package/dist/users/gdpr.d.ts +2 -40
- package/dist/users/gdpr.d.ts.map +1 -1
- package/dist/users/gdpr.js +3 -110
- package/dist/users/gdpr.js.map +1 -1
- package/dist/users/index.d.ts +5 -4
- package/dist/users/index.d.ts.map +1 -1
- package/dist/users/index.js +5 -4
- package/dist/users/index.js.map +1 -1
- package/dist/users/repository.d.ts +49 -3
- package/dist/users/repository.d.ts.map +1 -1
- package/dist/users/repository.js +169 -18
- package/dist/users/repository.js.map +1 -1
- package/dist/users/service.d.ts +19 -51
- package/dist/users/service.d.ts.map +1 -1
- package/dist/users/service.js +72 -122
- package/dist/users/service.js.map +1 -1
- package/dist/users/types.d.ts +4 -5
- package/dist/users/types.d.ts.map +1 -1
- package/dist/users/types.js.map +1 -1
- package/dist/users/validators.d.ts +28 -0
- package/dist/users/validators.d.ts.map +1 -0
- package/dist/users/validators.js +25 -0
- package/dist/users/validators.js.map +1 -0
- package/locales/default/en/errors.json +2 -1
- package/migrations/024_application_client_correction.sql +39 -0
- package/migrations/025_record_deletion_lifecycle.sql +26 -0
- package/migrations/026_simplify_user_lifecycle.sql +33 -0
- package/migrations/027_branding_asset_size_limits.sql +19 -0
- package/migrations/028_totp_replay_protection.sql +17 -0
- package/migrations/029_public_session_identifiers.sql +16 -0
- package/migrations/030_global_configuration_catalog.sql +39 -0
- package/migrations/031_monotonic_updated_at.sql +28 -0
- package/package.json +2 -2
- package/dist/lib/data-import-plan.d.ts +0 -50
- package/dist/lib/data-import-plan.d.ts.map +0 -1
- package/dist/lib/data-import-plan.js +0 -235
- package/dist/lib/data-import-plan.js.map +0 -1
- package/dist/lib/data-import.d.ts +0 -276
- package/dist/lib/data-import.d.ts.map +0 -1
- package/dist/lib/data-import.js +0 -1694
- package/dist/lib/data-import.js.map +0 -1
package/dist/routes/roles.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* GET / — List all roles for an application
|
|
12
12
|
* GET /:roleId — Get a role by ID
|
|
13
13
|
* PUT /:roleId — Update a role
|
|
14
|
-
* DELETE /:roleId — Delete a role
|
|
14
|
+
* DELETE /:roleId — Delete a role
|
|
15
15
|
* GET /:roleId/permissions — List permissions for a role
|
|
16
16
|
* PUT /:roleId/permissions — Assign permissions to a role
|
|
17
17
|
* DELETE /:roleId/permissions — Remove permissions from a role
|
|
@@ -26,23 +26,26 @@ import Router from '@koa/router';
|
|
|
26
26
|
import { z } from 'zod';
|
|
27
27
|
import { requireAdminAuth } from '../middleware/admin-auth.js';
|
|
28
28
|
import { requirePermission } from '../middleware/require-permission.js';
|
|
29
|
-
import { ADMIN_PERMISSIONS } from '../lib/admin-permissions.js';
|
|
29
|
+
import { ADMIN_PERMISSIONS, ALL_ADMIN_ROLES } from '../lib/admin-permissions.js';
|
|
30
|
+
import { getApplicationBySlug } from '../applications/service.js';
|
|
30
31
|
import * as roleService from '../rbac/role-service.js';
|
|
31
32
|
import * as userRoleService from '../rbac/user-role-service.js';
|
|
32
33
|
import { RoleNotFoundError, PermissionNotFoundError, RbacValidationError } from '../rbac/errors.js';
|
|
34
|
+
const ADMIN_APPLICATION_SLUG = 'porta-admin';
|
|
35
|
+
const ADMIN_ROLE_SLUGS = new Set(ALL_ADMIN_ROLES.map((role) => role.slug));
|
|
33
36
|
// ---------------------------------------------------------------------------
|
|
34
37
|
// Validation schemas
|
|
35
38
|
// ---------------------------------------------------------------------------
|
|
36
39
|
/** Schema for creating a new role */
|
|
37
40
|
const createRoleSchema = z.object({
|
|
38
41
|
name: z.string().min(1).max(255),
|
|
39
|
-
slug: z.string().min(1).max(100).optional(),
|
|
42
|
+
slug: z.string().trim().min(1).max(100).optional(),
|
|
40
43
|
description: z.string().max(1000).optional(),
|
|
41
44
|
});
|
|
42
45
|
/** Schema for updating a role (all fields optional) */
|
|
43
46
|
const updateRoleSchema = z.object({
|
|
44
47
|
name: z.string().min(1).max(255).optional(),
|
|
45
|
-
slug: z.string().min(1).max(100).optional(),
|
|
48
|
+
slug: z.string().trim().min(1).max(100).optional(),
|
|
46
49
|
description: z.string().max(1000).nullable().optional(),
|
|
47
50
|
});
|
|
48
51
|
/** Schema for assigning/removing permissions (array of UUIDs) */
|
|
@@ -55,6 +58,13 @@ const listUsersWithRoleSchema = z.object({
|
|
|
55
58
|
page: z.coerce.number().int().min(1).default(1),
|
|
56
59
|
pageSize: z.coerce.number().int().min(1).max(100).default(20),
|
|
57
60
|
});
|
|
61
|
+
/** Parent-qualified parameters accepted by role deletion. */
|
|
62
|
+
const identifierSchema = z.object({
|
|
63
|
+
appId: z.string().uuid(),
|
|
64
|
+
roleId: z.string().uuid(),
|
|
65
|
+
});
|
|
66
|
+
/** Application parent parameter accepted by collection routes. */
|
|
67
|
+
const applicationIdentifierSchema = z.object({ appId: z.string().uuid() });
|
|
58
68
|
// ---------------------------------------------------------------------------
|
|
59
69
|
// Error handler helper
|
|
60
70
|
// ---------------------------------------------------------------------------
|
|
@@ -79,6 +89,20 @@ function handleError(ctx, err) {
|
|
|
79
89
|
}
|
|
80
90
|
throw err;
|
|
81
91
|
}
|
|
92
|
+
/** Reject generic route mutations of a canonical Porta Admin role. */
|
|
93
|
+
async function requireMutableRole(applicationId, roleId) {
|
|
94
|
+
const role = await roleService.findRoleById(applicationId, roleId);
|
|
95
|
+
// The mutation service remains responsible for authoritative not-found handling and repeats the
|
|
96
|
+
// canonical check after locking. This route lookup exists only for an early sanitized rejection.
|
|
97
|
+
if (!role)
|
|
98
|
+
return;
|
|
99
|
+
if (!ADMIN_ROLE_SLUGS.has(role.slug))
|
|
100
|
+
return;
|
|
101
|
+
const adminApplication = await getApplicationBySlug(ADMIN_APPLICATION_SLUG);
|
|
102
|
+
if (adminApplication?.id === role.applicationId) {
|
|
103
|
+
throw new RbacValidationError('Canonical Porta Admin roles cannot be modified');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
82
106
|
// ---------------------------------------------------------------------------
|
|
83
107
|
// Router factory
|
|
84
108
|
// ---------------------------------------------------------------------------
|
|
@@ -101,11 +125,12 @@ export function createRoleRouter() {
|
|
|
101
125
|
// -------------------------------------------------------------------------
|
|
102
126
|
router.post('/', requirePermission(ADMIN_PERMISSIONS.ROLE_CREATE), async (ctx) => {
|
|
103
127
|
try {
|
|
128
|
+
applicationIdentifierSchema.parse(ctx.params);
|
|
104
129
|
const body = createRoleSchema.parse(ctx.request.body);
|
|
105
130
|
const role = await roleService.createRole({
|
|
106
131
|
applicationId: ctx.params.appId,
|
|
107
132
|
...body,
|
|
108
|
-
});
|
|
133
|
+
}, ctx.state.adminUser?.id);
|
|
109
134
|
ctx.status = 201;
|
|
110
135
|
ctx.body = { data: role };
|
|
111
136
|
}
|
|
@@ -118,6 +143,7 @@ export function createRoleRouter() {
|
|
|
118
143
|
// -------------------------------------------------------------------------
|
|
119
144
|
router.get('/', requirePermission(ADMIN_PERMISSIONS.ROLE_READ), async (ctx) => {
|
|
120
145
|
try {
|
|
146
|
+
applicationIdentifierSchema.parse(ctx.params);
|
|
121
147
|
const roles = await roleService.listRolesByApplication(ctx.params.appId);
|
|
122
148
|
ctx.body = { data: roles };
|
|
123
149
|
}
|
|
@@ -129,20 +155,28 @@ export function createRoleRouter() {
|
|
|
129
155
|
// GET /:roleId — Get role by ID
|
|
130
156
|
// -------------------------------------------------------------------------
|
|
131
157
|
router.get('/:roleId', requirePermission(ADMIN_PERMISSIONS.ROLE_READ), async (ctx) => {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
ctx.
|
|
158
|
+
try {
|
|
159
|
+
identifierSchema.parse(ctx.params);
|
|
160
|
+
const role = await roleService.findRoleById(ctx.params.appId, ctx.params.roleId);
|
|
161
|
+
if (!role) {
|
|
162
|
+
ctx.throw(404, 'Role not found');
|
|
163
|
+
}
|
|
164
|
+
ctx.body = { data: role };
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
handleError(ctx, err);
|
|
135
168
|
}
|
|
136
|
-
ctx.body = { data: role };
|
|
137
169
|
});
|
|
138
170
|
// -------------------------------------------------------------------------
|
|
139
171
|
// PUT /:roleId — Update role
|
|
140
172
|
// -------------------------------------------------------------------------
|
|
141
173
|
router.put('/:roleId', requirePermission(ADMIN_PERMISSIONS.ROLE_UPDATE), async (ctx) => {
|
|
142
174
|
try {
|
|
175
|
+
identifierSchema.parse(ctx.params);
|
|
143
176
|
const body = updateRoleSchema.parse(ctx.request.body);
|
|
144
|
-
|
|
145
|
-
|
|
177
|
+
await requireMutableRole(ctx.params.appId, ctx.params.roleId);
|
|
178
|
+
const result = await roleService.updateRole(ctx.params.appId, ctx.params.roleId, body, ctx.state.adminUser?.id);
|
|
179
|
+
ctx.body = { data: result };
|
|
146
180
|
}
|
|
147
181
|
catch (err) {
|
|
148
182
|
handleError(ctx, err);
|
|
@@ -150,13 +184,14 @@ export function createRoleRouter() {
|
|
|
150
184
|
});
|
|
151
185
|
// -------------------------------------------------------------------------
|
|
152
186
|
// DELETE /:roleId — Delete role
|
|
153
|
-
// Supports ?force=true to delete even when users are assigned
|
|
154
187
|
// -------------------------------------------------------------------------
|
|
155
|
-
router.delete('/:roleId', requirePermission(ADMIN_PERMISSIONS.
|
|
188
|
+
router.delete('/:roleId', requirePermission(ADMIN_PERMISSIONS.ROLE_DELETE), async (ctx) => {
|
|
156
189
|
try {
|
|
157
|
-
|
|
158
|
-
await
|
|
159
|
-
ctx.
|
|
190
|
+
identifierSchema.parse(ctx.params);
|
|
191
|
+
await requireMutableRole(ctx.params.appId, ctx.params.roleId);
|
|
192
|
+
const result = await roleService.deleteRole(ctx.params.appId, ctx.params.roleId, ctx.state.adminUser?.id);
|
|
193
|
+
ctx.status = 200;
|
|
194
|
+
ctx.body = { data: result };
|
|
160
195
|
}
|
|
161
196
|
catch (err) {
|
|
162
197
|
handleError(ctx, err);
|
|
@@ -167,7 +202,8 @@ export function createRoleRouter() {
|
|
|
167
202
|
// -------------------------------------------------------------------------
|
|
168
203
|
router.get('/:roleId/permissions', requirePermission(ADMIN_PERMISSIONS.ROLE_READ), async (ctx) => {
|
|
169
204
|
try {
|
|
170
|
-
|
|
205
|
+
identifierSchema.parse(ctx.params);
|
|
206
|
+
const permissions = await roleService.getPermissionsForRole(ctx.params.appId, ctx.params.roleId);
|
|
171
207
|
ctx.body = { data: permissions };
|
|
172
208
|
}
|
|
173
209
|
catch (err) {
|
|
@@ -179,8 +215,10 @@ export function createRoleRouter() {
|
|
|
179
215
|
// -------------------------------------------------------------------------
|
|
180
216
|
router.put('/:roleId/permissions', requirePermission(ADMIN_PERMISSIONS.ROLE_UPDATE), async (ctx) => {
|
|
181
217
|
try {
|
|
218
|
+
identifierSchema.parse(ctx.params);
|
|
182
219
|
const body = permissionIdsSchema.parse(ctx.request.body);
|
|
183
|
-
await
|
|
220
|
+
await requireMutableRole(ctx.params.appId, ctx.params.roleId);
|
|
221
|
+
await roleService.assignPermissionsToRole(ctx.params.appId, ctx.params.roleId, body.permissionIds, ctx.state.adminUser?.id);
|
|
184
222
|
ctx.status = 204;
|
|
185
223
|
}
|
|
186
224
|
catch (err) {
|
|
@@ -192,9 +230,12 @@ export function createRoleRouter() {
|
|
|
192
230
|
// -------------------------------------------------------------------------
|
|
193
231
|
router.delete('/:roleId/permissions', requirePermission(ADMIN_PERMISSIONS.ROLE_UPDATE), async (ctx) => {
|
|
194
232
|
try {
|
|
233
|
+
identifierSchema.parse(ctx.params);
|
|
195
234
|
const body = permissionIdsSchema.parse(ctx.request.body);
|
|
196
|
-
await
|
|
197
|
-
ctx.
|
|
235
|
+
await requireMutableRole(ctx.params.appId, ctx.params.roleId);
|
|
236
|
+
const result = await roleService.removePermissionsFromRole(ctx.params.appId, ctx.params.roleId, body.permissionIds, ctx.state.adminUser?.id);
|
|
237
|
+
ctx.status = 200;
|
|
238
|
+
ctx.body = { data: result };
|
|
198
239
|
}
|
|
199
240
|
catch (err) {
|
|
200
241
|
handleError(ctx, err);
|
|
@@ -206,8 +247,9 @@ export function createRoleRouter() {
|
|
|
206
247
|
// -------------------------------------------------------------------------
|
|
207
248
|
router.get('/:roleId/users', requirePermission(ADMIN_PERMISSIONS.ROLE_READ), async (ctx) => {
|
|
208
249
|
try {
|
|
250
|
+
identifierSchema.parse(ctx.params);
|
|
209
251
|
const query = listUsersWithRoleSchema.parse(ctx.query);
|
|
210
|
-
const result = await userRoleService.getUsersWithRole(ctx.params.roleId, query.orgId, {
|
|
252
|
+
const result = await userRoleService.getUsersWithRole(ctx.params.appId, ctx.params.roleId, query.orgId, {
|
|
211
253
|
page: query.page,
|
|
212
254
|
pageSize: query.pageSize,
|
|
213
255
|
});
|
package/dist/routes/roles.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roles.js","sourceRoot":"","sources":["../../src/routes/roles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"roles.js","sourceRoot":"","sources":["../../src/routes/roles.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,MAAM,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,MAAM,MAAM,aAAa,CAAC;AA0CjC;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CA2D5C;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAehD"}
|
package/dist/routes/sessions.js
CHANGED
|
@@ -35,6 +35,15 @@ const listSessionsSchema = z.object({
|
|
|
35
35
|
page: z.coerce.number().int().min(1).default(1),
|
|
36
36
|
pageSize: z.coerce.number().int().min(1).max(100).default(20),
|
|
37
37
|
});
|
|
38
|
+
/** Public UUID accepted by single-session administrative operations. */
|
|
39
|
+
const publicSessionIdSchema = z.string().uuid();
|
|
40
|
+
/** Validate a public session identifier without exposing parser details. */
|
|
41
|
+
function publicSessionId(ctx, value) {
|
|
42
|
+
const result = publicSessionIdSchema.safeParse(value);
|
|
43
|
+
if (!result.success)
|
|
44
|
+
ctx.throw(400, 'Session request is invalid');
|
|
45
|
+
return result.data;
|
|
46
|
+
}
|
|
38
47
|
// ---------------------------------------------------------------------------
|
|
39
48
|
// Router factory
|
|
40
49
|
// ---------------------------------------------------------------------------
|
|
@@ -64,7 +73,7 @@ export function createSessionRouter() {
|
|
|
64
73
|
// GET /:sessionId — Get session detail
|
|
65
74
|
// -------------------------------------------------------------------------
|
|
66
75
|
router.get('/:sessionId', requirePermission(ADMIN_PERMISSIONS.SESSION_READ), async (ctx) => {
|
|
67
|
-
const session = await sessionTracking.
|
|
76
|
+
const session = await sessionTracking.getSessionByPublicId(publicSessionId(ctx, ctx.params.sessionId));
|
|
68
77
|
if (!session) {
|
|
69
78
|
ctx.throw(404, 'Session not found');
|
|
70
79
|
return;
|
|
@@ -80,19 +89,21 @@ export function createSessionRouter() {
|
|
|
80
89
|
// 3. Audit log entry for session revocation
|
|
81
90
|
// -------------------------------------------------------------------------
|
|
82
91
|
router.delete('/:sessionId', requirePermission(ADMIN_PERMISSIONS.SESSION_REVOKE), async (ctx) => {
|
|
83
|
-
const
|
|
92
|
+
const requestedSessionId = publicSessionId(ctx, ctx.params.sessionId);
|
|
84
93
|
// 1. Mark revoked in PG tracking table
|
|
85
|
-
await sessionTracking.
|
|
94
|
+
const redisSessionId = await sessionTracking.revokeSessionByPublicId(requestedSessionId);
|
|
86
95
|
// 2. Delete from Redis to kill the live session
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
if (redisSessionId !== null) {
|
|
97
|
+
await afterDatabaseCommit(async () => {
|
|
98
|
+
try {
|
|
99
|
+
const redis = getRedis();
|
|
100
|
+
await redis.del(`oidc:Session:${redisSessionId}`);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Redis deletion failure is non-fatal — session will expire naturally.
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
96
107
|
ctx.status = 204;
|
|
97
108
|
});
|
|
98
109
|
return router;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,eAAe,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IACpC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IAC5C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IACtC,UAAU,EAAE,CAAC;SACV,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SACvB,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC;SAC9B,QAAQ,EAAE;IACb,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/C,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CAC9D,CAAC,CAAC;AAEH,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC,CAAC;IAE7D,0CAA0C;IAC1C,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAE/B,4EAA4E;IAC5E,oCAAoC;IACpC,4EAA4E;IAC5E,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,iBAAiB,CAAC,iBAAiB,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QAC/E,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACzD,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,4EAA4E;IAC5E,uCAAuC;IACvC,4EAA4E;IAC5E,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,iBAAiB,CAAC,iBAAiB,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACzF,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"two-factor.d.ts","sourceRoot":"","sources":["../../src/routes/two-factor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"two-factor.d.ts","sourceRoot":"","sources":["../../src/routes/two-factor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AA+I1C;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CA6BhE"}
|
|
@@ -21,10 +21,12 @@ import { generateCsrfToken, verifyCsrfToken, setCsrfCookie, getCsrfFromCookie, }
|
|
|
21
21
|
import { checkRateLimit, buildRateLimitKey } from '../auth/rate-limiter.js';
|
|
22
22
|
import { resolveLocale, getTranslationFunction } from '../auth/i18n.js';
|
|
23
23
|
import { renderPage } from '../auth/template-engine.js';
|
|
24
|
+
import { resolveEffectiveBranding } from '../auth/effective-branding.js';
|
|
24
25
|
import { sendOtpCodeEmail } from '../auth/email-service.js';
|
|
25
26
|
import { recordLogin } from '../users/service.js';
|
|
26
27
|
import { findUserById } from '../users/repository.js';
|
|
27
28
|
import { verifyOtp, verifyTotp, verifyRecoveryCode as verifyRecoveryCodeService, sendOtpCode, setupTotp, getPendingTotpSetupInfo, setupEmailOtp, confirmTotpSetup, } from '../two-factor/service.js';
|
|
29
|
+
import { UnsupportedTotpConfigurationError } from '../two-factor/errors.js';
|
|
28
30
|
import { writeAuditLog } from '../lib/audit-log.js';
|
|
29
31
|
import { logger } from '../lib/logger.js';
|
|
30
32
|
import { resolveOrganizationForInteraction } from './interactions.js';
|
|
@@ -38,21 +40,6 @@ const RESEND_RATE_LIMIT = { max: 3, windowSeconds: 300 };
|
|
|
38
40
|
// ---------------------------------------------------------------------------
|
|
39
41
|
// Helpers
|
|
40
42
|
// ---------------------------------------------------------------------------
|
|
41
|
-
/**
|
|
42
|
-
* Build branding context from organization data.
|
|
43
|
-
*
|
|
44
|
-
* @param org - Organization with branding fields
|
|
45
|
-
* @returns Branding context for templates
|
|
46
|
-
*/
|
|
47
|
-
function buildBrandingFromOrg(org) {
|
|
48
|
-
return {
|
|
49
|
-
logoUrl: org.brandingLogoUrl,
|
|
50
|
-
faviconUrl: org.brandingFaviconUrl,
|
|
51
|
-
primaryColor: org.brandingPrimaryColor ?? '#3B82F6',
|
|
52
|
-
companyName: org.brandingCompanyName ?? org.name,
|
|
53
|
-
customCss: org.brandingCustomCss,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
43
|
/**
|
|
57
44
|
* Build a base template context for 2FA pages.
|
|
58
45
|
*
|
|
@@ -60,11 +47,11 @@ function buildBrandingFromOrg(org) {
|
|
|
60
47
|
* @param locale - Resolved locale
|
|
61
48
|
* @param csrfToken - CSRF token for form protection
|
|
62
49
|
* @param orgSlug - Organization slug
|
|
63
|
-
* @returns Base template context
|
|
50
|
+
* @returns Base template context.
|
|
64
51
|
*/
|
|
65
|
-
function buildBaseContext(ctx, locale, csrfToken, orgSlug) {
|
|
52
|
+
async function buildBaseContext(ctx, locale, csrfToken, orgSlug) {
|
|
66
53
|
return {
|
|
67
|
-
branding:
|
|
54
|
+
branding: await resolveEffectiveBranding(ctx.state.organization),
|
|
68
55
|
locale,
|
|
69
56
|
csrfToken,
|
|
70
57
|
orgSlug,
|
|
@@ -79,6 +66,7 @@ function buildBaseContext(ctx, locale, csrfToken, orgSlug) {
|
|
|
79
66
|
* @param statusCode - HTTP status (default: 200)
|
|
80
67
|
*/
|
|
81
68
|
async function renderAndRespond(ctx, pageName, context, statusCode = 200) {
|
|
69
|
+
ctx.state.brandingImageSources = context.branding.imageSources;
|
|
82
70
|
const html = await renderPage(pageName, context);
|
|
83
71
|
ctx.status = statusCode;
|
|
84
72
|
ctx.type = 'text/html';
|
|
@@ -182,7 +170,7 @@ async function showTwoFactor(ctx, provider) {
|
|
|
182
170
|
const csrfToken = generateCsrfToken();
|
|
183
171
|
setCsrfCookie(ctx, csrfToken);
|
|
184
172
|
const context = {
|
|
185
|
-
...buildBaseContext(ctx, locale, csrfToken, org.slug),
|
|
173
|
+
...(await buildBaseContext(ctx, locale, csrfToken, org.slug)),
|
|
186
174
|
t,
|
|
187
175
|
interaction: {
|
|
188
176
|
uid: interaction.uid,
|
|
@@ -216,7 +204,10 @@ async function showTwoFactor(ctx, provider) {
|
|
|
216
204
|
async function verifyTwoFactor(ctx, provider) {
|
|
217
205
|
const body = ctx.request.body;
|
|
218
206
|
const code = (body.code ?? '').trim();
|
|
219
|
-
const
|
|
207
|
+
const submittedCodeType = body.codeType;
|
|
208
|
+
const codeType = submittedCodeType === 'totp' || submittedCodeType === 'recovery' || submittedCodeType === 'otp'
|
|
209
|
+
? submittedCodeType
|
|
210
|
+
: 'otp';
|
|
220
211
|
const submittedCsrf = body._csrf ?? '';
|
|
221
212
|
const storedCsrf = getCsrfFromCookie(ctx) ?? '';
|
|
222
213
|
try {
|
|
@@ -273,7 +264,12 @@ async function verifyTwoFactor(ctx, provider) {
|
|
|
273
264
|
verified = await verifyOtp(pending.pendingAccountId, code);
|
|
274
265
|
}
|
|
275
266
|
}
|
|
276
|
-
catch {
|
|
267
|
+
catch (error) {
|
|
268
|
+
if (error instanceof UnsupportedTotpConfigurationError) {
|
|
269
|
+
logUnsupportedTotpConfiguration();
|
|
270
|
+
await renderTwoFactorWithError(ctx, interaction.uid, pending, locale, t, t('errors.two_factor_unavailable'), 503);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
277
273
|
// Verification service threw an error (invalid code, expired, exhausted, etc.)
|
|
278
274
|
logger.debug({ event: 'two-factor-code-rejected', codeType }, 'Two-factor code rejected');
|
|
279
275
|
verified = false;
|
|
@@ -351,13 +347,7 @@ async function resendOtpCode(ctx, provider) {
|
|
|
351
347
|
email: pending.email,
|
|
352
348
|
givenName: user?.givenName,
|
|
353
349
|
familyName: user?.familyName,
|
|
354
|
-
},
|
|
355
|
-
id: org.id,
|
|
356
|
-
slug: org.slug,
|
|
357
|
-
brandingLogoUrl: org.brandingLogoUrl,
|
|
358
|
-
brandingPrimaryColor: org.brandingPrimaryColor,
|
|
359
|
-
brandingCompanyName: org.brandingCompanyName,
|
|
360
|
-
}, otpCode, 10, locale);
|
|
350
|
+
}, org, otpCode, 10, locale);
|
|
361
351
|
}
|
|
362
352
|
catch {
|
|
363
353
|
logger.warn({ event: 'two-factor-otp-resend-failed' }, 'OTP resend failed');
|
|
@@ -423,7 +413,7 @@ async function showTwoFactorSetup(ctx, provider) {
|
|
|
423
413
|
// Check for error indicator from failed verification redirect
|
|
424
414
|
const errorParam = ctx.query.error ?? '';
|
|
425
415
|
const context = {
|
|
426
|
-
...buildBaseContext(ctx, locale, csrfToken, org.slug),
|
|
416
|
+
...(await buildBaseContext(ctx, locale, csrfToken, org.slug)),
|
|
427
417
|
t,
|
|
428
418
|
interaction: {
|
|
429
419
|
uid: interaction.uid,
|
|
@@ -501,13 +491,7 @@ async function processTwoFactorSetup(ctx, provider) {
|
|
|
501
491
|
email: pending.email,
|
|
502
492
|
givenName: user?.givenName,
|
|
503
493
|
familyName: user?.familyName,
|
|
504
|
-
},
|
|
505
|
-
id: org.id,
|
|
506
|
-
slug: org.slug,
|
|
507
|
-
brandingLogoUrl: org.brandingLogoUrl,
|
|
508
|
-
brandingPrimaryColor: org.brandingPrimaryColor,
|
|
509
|
-
brandingCompanyName: org.brandingCompanyName,
|
|
510
|
-
}, otpCode, 10, locale);
|
|
494
|
+
}, org, otpCode, 10, locale);
|
|
511
495
|
}
|
|
512
496
|
catch {
|
|
513
497
|
logger.warn({ event: 'two-factor-setup-otp-failed' }, 'Setup OTP delivery failed');
|
|
@@ -519,12 +503,42 @@ async function processTwoFactorSetup(ctx, provider) {
|
|
|
519
503
|
ctx.redirect(`/interaction/${interaction.uid}/two-factor`);
|
|
520
504
|
return;
|
|
521
505
|
}
|
|
506
|
+
// TOTP confirmation uses the same attempt budget as normal 2FA verification.
|
|
507
|
+
// Email setup returns above because it does not verify a user-entered code.
|
|
508
|
+
const rateLimitKey = buildRateLimitKey('2fa_verify', org.id, pending.pendingAccountId);
|
|
509
|
+
const rateLimitResult = await checkRateLimit(rateLimitKey, VERIFY_RATE_LIMIT);
|
|
510
|
+
if (!rateLimitResult.allowed) {
|
|
511
|
+
ctx.set('Retry-After', String(rateLimitResult.retryAfter));
|
|
512
|
+
writeAuditLog({
|
|
513
|
+
organizationId: org.id,
|
|
514
|
+
userId: pending.pendingAccountId,
|
|
515
|
+
eventType: 'rate_limit.2fa_verify',
|
|
516
|
+
eventCategory: 'security',
|
|
517
|
+
description: 'TOTP setup verification rate limit exceeded',
|
|
518
|
+
ipAddress: ctx.ip,
|
|
519
|
+
});
|
|
520
|
+
const t = getTranslationFunction(locale, org.slug);
|
|
521
|
+
await renderTotpSetupWithError(ctx, interaction.uid, pending, locale, t, t('errors.rate_limit_exceeded'), 429);
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
522
524
|
// TOTP setup confirmation — verify the code from authenticator app
|
|
523
525
|
if (!code) {
|
|
524
526
|
ctx.redirect(`/interaction/${interaction.uid}/two-factor/setup`);
|
|
525
527
|
return;
|
|
526
528
|
}
|
|
527
|
-
|
|
529
|
+
let confirmed;
|
|
530
|
+
try {
|
|
531
|
+
confirmed = await confirmTotpSetup(pending.pendingAccountId, code);
|
|
532
|
+
}
|
|
533
|
+
catch (error) {
|
|
534
|
+
if (error instanceof UnsupportedTotpConfigurationError) {
|
|
535
|
+
logUnsupportedTotpConfiguration();
|
|
536
|
+
const t = getTranslationFunction(locale, org.slug);
|
|
537
|
+
await renderTotpSetupWithError(ctx, interaction.uid, pending, locale, t, t('errors.two_factor_unavailable'), 503);
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
throw error;
|
|
541
|
+
}
|
|
528
542
|
if (!confirmed) {
|
|
529
543
|
writeAuditLog({
|
|
530
544
|
organizationId: org.id,
|
|
@@ -558,6 +572,45 @@ async function processTwoFactorSetup(ctx, provider) {
|
|
|
558
572
|
ctx.body = 'Interaction expired';
|
|
559
573
|
}
|
|
560
574
|
}
|
|
575
|
+
/** Record the fixed diagnostic for unsupported persisted TOTP parameters. */
|
|
576
|
+
function logUnsupportedTotpConfiguration() {
|
|
577
|
+
logger.error({ event: 'totp-configuration-unsupported' }, 'TOTP configuration is unsupported');
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Render pending TOTP enrollment data with an error without creating new secrets.
|
|
581
|
+
*
|
|
582
|
+
* @param ctx - Koa context
|
|
583
|
+
* @param uid - Interaction UID
|
|
584
|
+
* @param pending - Pending two-factor state
|
|
585
|
+
* @param locale - Resolved locale
|
|
586
|
+
* @param t - Translation function
|
|
587
|
+
* @param errorMessage - Error to display
|
|
588
|
+
* @param statusCode - HTTP response status
|
|
589
|
+
* @throws Error when the pending enrollment record no longer exists
|
|
590
|
+
*/
|
|
591
|
+
async function renderTotpSetupWithError(ctx, uid, pending, locale, t, errorMessage, statusCode) {
|
|
592
|
+
const setup = await getPendingTotpSetupInfo(pending.pendingAccountId, pending.email, ctx.state.organization.slug);
|
|
593
|
+
if (!setup) {
|
|
594
|
+
throw new Error('Pending TOTP setup is unavailable');
|
|
595
|
+
}
|
|
596
|
+
const csrfToken = generateCsrfToken();
|
|
597
|
+
setCsrfCookie(ctx, csrfToken);
|
|
598
|
+
const context = {
|
|
599
|
+
...(await buildBaseContext(ctx, locale, csrfToken, ctx.state.organization.slug)),
|
|
600
|
+
t,
|
|
601
|
+
interaction: {
|
|
602
|
+
uid,
|
|
603
|
+
prompt: 'two-factor-setup',
|
|
604
|
+
params: {},
|
|
605
|
+
client: { clientName: '' },
|
|
606
|
+
},
|
|
607
|
+
method: 'totp',
|
|
608
|
+
qrCodeDataUri: setup.qrCodeDataUri,
|
|
609
|
+
totpSecret: setup.totpSecret,
|
|
610
|
+
flash: { error: errorMessage },
|
|
611
|
+
};
|
|
612
|
+
await renderAndRespond(ctx, 'two-factor-setup', context, statusCode);
|
|
613
|
+
}
|
|
561
614
|
// ---------------------------------------------------------------------------
|
|
562
615
|
// Helper: render 2FA verify page with error
|
|
563
616
|
// ---------------------------------------------------------------------------
|
|
@@ -576,7 +629,7 @@ async function renderTwoFactorWithError(ctx, uid, pending, locale, t, errorMessa
|
|
|
576
629
|
const csrfToken = generateCsrfToken();
|
|
577
630
|
setCsrfCookie(ctx, csrfToken);
|
|
578
631
|
const context = {
|
|
579
|
-
...buildBaseContext(ctx, locale, csrfToken, ctx.state.organization.slug),
|
|
632
|
+
...(await buildBaseContext(ctx, locale, csrfToken, ctx.state.organization.slug)),
|
|
580
633
|
t,
|
|
581
634
|
interaction: {
|
|
582
635
|
uid,
|