@portaidentity/server 1.7.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 +11 -0
- package/LICENSE +21 -0
- package/README.md +33 -0
- package/dist/applications/cache.d.ts +64 -0
- package/dist/applications/cache.d.ts.map +1 -0
- package/dist/applications/cache.js +161 -0
- package/dist/applications/cache.js.map +1 -0
- package/dist/applications/errors.d.ts +25 -0
- package/dist/applications/errors.d.ts.map +1 -0
- package/dist/applications/errors.js +31 -0
- package/dist/applications/errors.js.map +1 -0
- package/dist/applications/index.d.ts +17 -0
- package/dist/applications/index.d.ts.map +1 -0
- package/dist/applications/index.js +19 -0
- package/dist/applications/index.js.map +1 -0
- package/dist/applications/repository.d.ts +184 -0
- package/dist/applications/repository.d.ts.map +1 -0
- package/dist/applications/repository.js +367 -0
- package/dist/applications/repository.js.map +1 -0
- package/dist/applications/service.d.ts +160 -0
- package/dist/applications/service.d.ts.map +1 -0
- package/dist/applications/service.js +388 -0
- package/dist/applications/service.js.map +1 -0
- package/dist/applications/slugs.d.ts +61 -0
- package/dist/applications/slugs.d.ts.map +1 -0
- package/dist/applications/slugs.js +115 -0
- package/dist/applications/slugs.js.map +1 -0
- package/dist/applications/types.d.ts +129 -0
- package/dist/applications/types.d.ts.map +1 -0
- package/dist/applications/types.js +62 -0
- package/dist/applications/types.js.map +1 -0
- package/dist/auth/csrf.d.ts +71 -0
- package/dist/auth/csrf.d.ts.map +1 -0
- package/dist/auth/csrf.js +112 -0
- package/dist/auth/csrf.js.map +1 -0
- package/dist/auth/email-renderer.d.ts +37 -0
- package/dist/auth/email-renderer.d.ts.map +1 -0
- package/dist/auth/email-renderer.js +116 -0
- package/dist/auth/email-renderer.js.map +1 -0
- package/dist/auth/email-service.d.ts +154 -0
- package/dist/auth/email-service.d.ts.map +1 -0
- package/dist/auth/email-service.js +415 -0
- package/dist/auth/email-service.js.map +1 -0
- package/dist/auth/email-transport.d.ts +65 -0
- package/dist/auth/email-transport.d.ts.map +1 -0
- package/dist/auth/email-transport.js +82 -0
- package/dist/auth/email-transport.js.map +1 -0
- package/dist/auth/i18n.d.ts +81 -0
- package/dist/auth/i18n.d.ts.map +1 -0
- package/dist/auth/i18n.js +395 -0
- package/dist/auth/i18n.js.map +1 -0
- package/dist/auth/index.d.ts +28 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +31 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/interaction-authority.d.ts +39 -0
- package/dist/auth/interaction-authority.d.ts.map +1 -0
- package/dist/auth/interaction-authority.js +30 -0
- package/dist/auth/interaction-authority.js.map +1 -0
- package/dist/auth/magic-link-session.d.ts +81 -0
- package/dist/auth/magic-link-session.d.ts.map +1 -0
- package/dist/auth/magic-link-session.js +183 -0
- package/dist/auth/magic-link-session.js.map +1 -0
- package/dist/auth/rate-limiter.d.ts +143 -0
- package/dist/auth/rate-limiter.d.ts.map +1 -0
- package/dist/auth/rate-limiter.js +220 -0
- package/dist/auth/rate-limiter.js.map +1 -0
- package/dist/auth/recovery-crypto.d.ts +34 -0
- package/dist/auth/recovery-crypto.d.ts.map +1 -0
- package/dist/auth/recovery-crypto.js +103 -0
- package/dist/auth/recovery-crypto.js.map +1 -0
- package/dist/auth/recovery-job-processor.d.ts +24 -0
- package/dist/auth/recovery-job-processor.d.ts.map +1 -0
- package/dist/auth/recovery-job-processor.js +123 -0
- package/dist/auth/recovery-job-processor.js.map +1 -0
- package/dist/auth/recovery-job-repository.d.ts +219 -0
- package/dist/auth/recovery-job-repository.d.ts.map +1 -0
- package/dist/auth/recovery-job-repository.js +340 -0
- package/dist/auth/recovery-job-repository.js.map +1 -0
- package/dist/auth/recovery-service.d.ts +27 -0
- package/dist/auth/recovery-service.d.ts.map +1 -0
- package/dist/auth/recovery-service.js +53 -0
- package/dist/auth/recovery-service.js.map +1 -0
- package/dist/auth/recovery-worker.d.ts +158 -0
- package/dist/auth/recovery-worker.d.ts.map +1 -0
- package/dist/auth/recovery-worker.js +306 -0
- package/dist/auth/recovery-worker.js.map +1 -0
- package/dist/auth/template-engine.d.ts +134 -0
- package/dist/auth/template-engine.d.ts.map +1 -0
- package/dist/auth/template-engine.js +225 -0
- package/dist/auth/template-engine.js.map +1 -0
- package/dist/auth/token-repository.d.ts +238 -0
- package/dist/auth/token-repository.d.ts.map +1 -0
- package/dist/auth/token-repository.js +475 -0
- package/dist/auth/token-repository.js.map +1 -0
- package/dist/auth/tokens.d.ts +45 -0
- package/dist/auth/tokens.d.ts.map +1 -0
- package/dist/auth/tokens.js +51 -0
- package/dist/auth/tokens.js.map +1 -0
- package/dist/cli/bootstrap.d.ts +55 -0
- package/dist/cli/bootstrap.d.ts.map +1 -0
- package/dist/cli/bootstrap.js +90 -0
- package/dist/cli/bootstrap.js.map +1 -0
- package/dist/cli/commands/health.d.ts +20 -0
- package/dist/cli/commands/health.d.ts.map +1 -0
- package/dist/cli/commands/health.js +80 -0
- package/dist/cli/commands/health.js.map +1 -0
- package/dist/cli/commands/init.d.ts +48 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +349 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/migrate.d.ts +19 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -0
- package/dist/cli/commands/migrate.js +88 -0
- package/dist/cli/commands/migrate.js.map +1 -0
- package/dist/cli/commands/seed.d.ts +19 -0
- package/dist/cli/commands/seed.d.ts.map +1 -0
- package/dist/cli/commands/seed.js +71 -0
- package/dist/cli/commands/seed.js.map +1 -0
- package/dist/cli/commands/user-2fa.d.ts +29 -0
- package/dist/cli/commands/user-2fa.d.ts.map +1 -0
- package/dist/cli/commands/user-2fa.js +113 -0
- package/dist/cli/commands/user-2fa.js.map +1 -0
- package/dist/cli/error-handler.d.ts +31 -0
- package/dist/cli/error-handler.d.ts.map +1 -0
- package/dist/cli/error-handler.js +65 -0
- package/dist/cli/error-handler.js.map +1 -0
- package/dist/cli/index.d.ts +48 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +99 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/output.d.ts +94 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +124 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/prompt.d.ts +48 -0
- package/dist/cli/prompt.d.ts.map +1 -0
- package/dist/cli/prompt.js +96 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/clients/cache.d.ts +63 -0
- package/dist/clients/cache.d.ts.map +1 -0
- package/dist/clients/cache.js +160 -0
- package/dist/clients/cache.js.map +1 -0
- package/dist/clients/crypto.d.ts +69 -0
- package/dist/clients/crypto.d.ts.map +1 -0
- package/dist/clients/crypto.js +83 -0
- package/dist/clients/crypto.js.map +1 -0
- package/dist/clients/errors.d.ts +27 -0
- package/dist/clients/errors.d.ts.map +1 -0
- package/dist/clients/errors.js +33 -0
- package/dist/clients/errors.js.map +1 -0
- package/dist/clients/index.d.ts +19 -0
- package/dist/clients/index.d.ts.map +1 -0
- package/dist/clients/index.js +23 -0
- package/dist/clients/index.js.map +1 -0
- package/dist/clients/repository.d.ts +161 -0
- package/dist/clients/repository.d.ts.map +1 -0
- package/dist/clients/repository.js +318 -0
- package/dist/clients/repository.js.map +1 -0
- package/dist/clients/resolve-login-methods.d.ts +74 -0
- package/dist/clients/resolve-login-methods.d.ts.map +1 -0
- package/dist/clients/resolve-login-methods.js +68 -0
- package/dist/clients/resolve-login-methods.js.map +1 -0
- package/dist/clients/secret-repository.d.ts +109 -0
- package/dist/clients/secret-repository.d.ts.map +1 -0
- package/dist/clients/secret-repository.js +166 -0
- package/dist/clients/secret-repository.js.map +1 -0
- package/dist/clients/secret-service.d.ts +87 -0
- package/dist/clients/secret-service.d.ts.map +1 -0
- package/dist/clients/secret-service.js +204 -0
- package/dist/clients/secret-service.js.map +1 -0
- package/dist/clients/service.d.ts +158 -0
- package/dist/clients/service.d.ts.map +1 -0
- package/dist/clients/service.js +523 -0
- package/dist/clients/service.js.map +1 -0
- package/dist/clients/types.d.ts +214 -0
- package/dist/clients/types.d.ts.map +1 -0
- package/dist/clients/types.js +77 -0
- package/dist/clients/types.js.map +1 -0
- package/dist/clients/validators.d.ts +87 -0
- package/dist/clients/validators.d.ts.map +1 -0
- package/dist/clients/validators.js +164 -0
- package/dist/clients/validators.js.map +1 -0
- package/dist/config/index.d.ts +23 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +52 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/schema.d.ts +35 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +167 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/custom-claims/cache.d.ts +48 -0
- package/dist/custom-claims/cache.d.ts.map +1 -0
- package/dist/custom-claims/cache.js +122 -0
- package/dist/custom-claims/cache.js.map +1 -0
- package/dist/custom-claims/errors.d.ts +25 -0
- package/dist/custom-claims/errors.d.ts.map +1 -0
- package/dist/custom-claims/errors.js +31 -0
- package/dist/custom-claims/errors.js.map +1 -0
- package/dist/custom-claims/index.d.ts +14 -0
- package/dist/custom-claims/index.d.ts.map +1 -0
- package/dist/custom-claims/index.js +17 -0
- package/dist/custom-claims/index.js.map +1 -0
- package/dist/custom-claims/repository.d.ts +147 -0
- package/dist/custom-claims/repository.d.ts.map +1 -0
- package/dist/custom-claims/repository.js +338 -0
- package/dist/custom-claims/repository.js.map +1 -0
- package/dist/custom-claims/service.d.ts +129 -0
- package/dist/custom-claims/service.d.ts.map +1 -0
- package/dist/custom-claims/service.js +296 -0
- package/dist/custom-claims/service.js.map +1 -0
- package/dist/custom-claims/types.d.ts +132 -0
- package/dist/custom-claims/types.d.ts.map +1 -0
- package/dist/custom-claims/types.js +61 -0
- package/dist/custom-claims/types.js.map +1 -0
- package/dist/custom-claims/validators.d.ts +61 -0
- package/dist/custom-claims/validators.d.ts.map +1 -0
- package/dist/custom-claims/validators.js +136 -0
- package/dist/custom-claims/validators.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +91 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/admin-permissions.d.ts +147 -0
- package/dist/lib/admin-permissions.d.ts.map +1 -0
- package/dist/lib/admin-permissions.js +261 -0
- package/dist/lib/admin-permissions.js.map +1 -0
- package/dist/lib/audit-log.d.ts +45 -0
- package/dist/lib/audit-log.d.ts.map +1 -0
- package/dist/lib/audit-log.js +79 -0
- package/dist/lib/audit-log.js.map +1 -0
- package/dist/lib/branding-assets.d.ts +47 -0
- package/dist/lib/branding-assets.d.ts.map +1 -0
- package/dist/lib/branding-assets.js +93 -0
- package/dist/lib/branding-assets.js.map +1 -0
- package/dist/lib/bulk-operations.d.ts +54 -0
- package/dist/lib/bulk-operations.d.ts.map +1 -0
- package/dist/lib/bulk-operations.js +201 -0
- package/dist/lib/bulk-operations.js.map +1 -0
- package/dist/lib/cursor.d.ts +110 -0
- package/dist/lib/cursor.d.ts.map +1 -0
- package/dist/lib/cursor.js +115 -0
- package/dist/lib/cursor.js.map +1 -0
- package/dist/lib/data-export.d.ts +67 -0
- package/dist/lib/data-export.d.ts.map +1 -0
- package/dist/lib/data-export.js +272 -0
- package/dist/lib/data-export.js.map +1 -0
- package/dist/lib/data-import-plan.d.ts +50 -0
- package/dist/lib/data-import-plan.d.ts.map +1 -0
- package/dist/lib/data-import-plan.js +235 -0
- package/dist/lib/data-import-plan.js.map +1 -0
- package/dist/lib/data-import.d.ts +276 -0
- package/dist/lib/data-import.d.ts.map +1 -0
- package/dist/lib/data-import.js +1694 -0
- package/dist/lib/data-import.js.map +1 -0
- package/dist/lib/database.d.ts +22 -0
- package/dist/lib/database.d.ts.map +1 -0
- package/dist/lib/database.js +103 -0
- package/dist/lib/database.js.map +1 -0
- package/dist/lib/entity-history.d.ts +52 -0
- package/dist/lib/entity-history.d.ts.map +1 -0
- package/dist/lib/entity-history.js +121 -0
- package/dist/lib/entity-history.js.map +1 -0
- package/dist/lib/etag.d.ts +92 -0
- package/dist/lib/etag.d.ts.map +1 -0
- package/dist/lib/etag.js +155 -0
- package/dist/lib/etag.js.map +1 -0
- package/dist/lib/image-validator.d.ts +44 -0
- package/dist/lib/image-validator.d.ts.map +1 -0
- package/dist/lib/image-validator.js +204 -0
- package/dist/lib/image-validator.js.map +1 -0
- package/dist/lib/logger.d.ts +15 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +84 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/migrator.d.ts +14 -0
- package/dist/lib/migrator.d.ts.map +1 -0
- package/dist/lib/migrator.js +34 -0
- package/dist/lib/migrator.js.map +1 -0
- package/dist/lib/redis.d.ts +5 -0
- package/dist/lib/redis.d.ts.map +1 -0
- package/dist/lib/redis.js +29 -0
- package/dist/lib/redis.js.map +1 -0
- package/dist/lib/runtime-paths.d.ts +38 -0
- package/dist/lib/runtime-paths.d.ts.map +1 -0
- package/dist/lib/runtime-paths.js +50 -0
- package/dist/lib/runtime-paths.js.map +1 -0
- package/dist/lib/session-tracking.d.ts +81 -0
- package/dist/lib/session-tracking.d.ts.map +1 -0
- package/dist/lib/session-tracking.js +145 -0
- package/dist/lib/session-tracking.js.map +1 -0
- package/dist/lib/signing-key-crypto.d.ts +53 -0
- package/dist/lib/signing-key-crypto.d.ts.map +1 -0
- package/dist/lib/signing-key-crypto.js +108 -0
- package/dist/lib/signing-key-crypto.js.map +1 -0
- package/dist/lib/signing-keys.d.ts +141 -0
- package/dist/lib/signing-keys.d.ts.map +1 -0
- package/dist/lib/signing-keys.js +206 -0
- package/dist/lib/signing-keys.js.map +1 -0
- package/dist/lib/stats.d.ts +83 -0
- package/dist/lib/stats.d.ts.map +1 -0
- package/dist/lib/stats.js +187 -0
- package/dist/lib/stats.js.map +1 -0
- package/dist/lib/super-admin-protection.d.ts +69 -0
- package/dist/lib/super-admin-protection.d.ts.map +1 -0
- package/dist/lib/super-admin-protection.js +102 -0
- package/dist/lib/super-admin-protection.js.map +1 -0
- package/dist/lib/system-config.d.ts +79 -0
- package/dist/lib/system-config.d.ts.map +1 -0
- package/dist/lib/system-config.js +159 -0
- package/dist/lib/system-config.js.map +1 -0
- package/dist/middleware/admin-auth.d.ts +100 -0
- package/dist/middleware/admin-auth.d.ts.map +1 -0
- package/dist/middleware/admin-auth.js +241 -0
- package/dist/middleware/admin-auth.js.map +1 -0
- package/dist/middleware/admin-cors.d.ts +41 -0
- package/dist/middleware/admin-cors.d.ts.map +1 -0
- package/dist/middleware/admin-cors.js +83 -0
- package/dist/middleware/admin-cors.js.map +1 -0
- package/dist/middleware/admin-mutation-audit.d.ts +9 -0
- package/dist/middleware/admin-mutation-audit.d.ts.map +1 -0
- package/dist/middleware/admin-mutation-audit.js +76 -0
- package/dist/middleware/admin-mutation-audit.js.map +1 -0
- package/dist/middleware/admin-rate-limiter.d.ts +56 -0
- package/dist/middleware/admin-rate-limiter.d.ts.map +1 -0
- package/dist/middleware/admin-rate-limiter.js +97 -0
- package/dist/middleware/admin-rate-limiter.js.map +1 -0
- package/dist/middleware/client-secret-hash.d.ts +34 -0
- package/dist/middleware/client-secret-hash.d.ts.map +1 -0
- package/dist/middleware/client-secret-hash.js +74 -0
- package/dist/middleware/client-secret-hash.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +3 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +93 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/health.d.ts +3 -0
- package/dist/middleware/health.d.ts.map +1 -0
- package/dist/middleware/health.js +35 -0
- package/dist/middleware/health.js.map +1 -0
- package/dist/middleware/metrics.d.ts +40 -0
- package/dist/middleware/metrics.d.ts.map +1 -0
- package/dist/middleware/metrics.js +75 -0
- package/dist/middleware/metrics.js.map +1 -0
- package/dist/middleware/oidc-client-tenant.d.ts +37 -0
- package/dist/middleware/oidc-client-tenant.d.ts.map +1 -0
- package/dist/middleware/oidc-client-tenant.js +156 -0
- package/dist/middleware/oidc-client-tenant.js.map +1 -0
- package/dist/middleware/oidc-cors.d.ts +33 -0
- package/dist/middleware/oidc-cors.d.ts.map +1 -0
- package/dist/middleware/oidc-cors.js +68 -0
- package/dist/middleware/oidc-cors.js.map +1 -0
- package/dist/middleware/oidc-preflight-cors.d.ts +54 -0
- package/dist/middleware/oidc-preflight-cors.d.ts.map +1 -0
- package/dist/middleware/oidc-preflight-cors.js +267 -0
- package/dist/middleware/oidc-preflight-cors.js.map +1 -0
- package/dist/middleware/prompt-login-reset.d.ts +103 -0
- package/dist/middleware/prompt-login-reset.d.ts.map +1 -0
- package/dist/middleware/prompt-login-reset.js +204 -0
- package/dist/middleware/prompt-login-reset.js.map +1 -0
- package/dist/middleware/ready.d.ts +23 -0
- package/dist/middleware/ready.d.ts.map +1 -0
- package/dist/middleware/ready.js +60 -0
- package/dist/middleware/ready.js.map +1 -0
- package/dist/middleware/request-logger.d.ts +27 -0
- package/dist/middleware/request-logger.d.ts.map +1 -0
- package/dist/middleware/request-logger.js +46 -0
- package/dist/middleware/request-logger.js.map +1 -0
- package/dist/middleware/require-permission.d.ts +28 -0
- package/dist/middleware/require-permission.d.ts.map +1 -0
- package/dist/middleware/require-permission.js +63 -0
- package/dist/middleware/require-permission.js.map +1 -0
- package/dist/middleware/require-user-organization.d.ts +18 -0
- package/dist/middleware/require-user-organization.d.ts.map +1 -0
- package/dist/middleware/require-user-organization.js +53 -0
- package/dist/middleware/require-user-organization.js.map +1 -0
- package/dist/middleware/root-page.d.ts +62 -0
- package/dist/middleware/root-page.d.ts.map +1 -0
- package/dist/middleware/root-page.js +134 -0
- package/dist/middleware/root-page.js.map +1 -0
- package/dist/middleware/security-headers.d.ts +98 -0
- package/dist/middleware/security-headers.d.ts.map +1 -0
- package/dist/middleware/security-headers.js +159 -0
- package/dist/middleware/security-headers.js.map +1 -0
- package/dist/middleware/tenant-resolver.d.ts +37 -0
- package/dist/middleware/tenant-resolver.d.ts.map +1 -0
- package/dist/middleware/tenant-resolver.js +71 -0
- package/dist/middleware/tenant-resolver.js.map +1 -0
- package/dist/middleware/token-rate-limiter.d.ts +89 -0
- package/dist/middleware/token-rate-limiter.d.ts.map +1 -0
- package/dist/middleware/token-rate-limiter.js +189 -0
- package/dist/middleware/token-rate-limiter.js.map +1 -0
- package/dist/oidc/account-finder.d.ts +52 -0
- package/dist/oidc/account-finder.d.ts.map +1 -0
- package/dist/oidc/account-finder.js +134 -0
- package/dist/oidc/account-finder.js.map +1 -0
- package/dist/oidc/adapter-factory.d.ts +90 -0
- package/dist/oidc/adapter-factory.d.ts.map +1 -0
- package/dist/oidc/adapter-factory.js +165 -0
- package/dist/oidc/adapter-factory.js.map +1 -0
- package/dist/oidc/configuration.d.ts +155 -0
- package/dist/oidc/configuration.d.ts.map +1 -0
- package/dist/oidc/configuration.js +531 -0
- package/dist/oidc/configuration.js.map +1 -0
- package/dist/oidc/postgres-adapter.d.ts +159 -0
- package/dist/oidc/postgres-adapter.d.ts.map +1 -0
- package/dist/oidc/postgres-adapter.js +222 -0
- package/dist/oidc/postgres-adapter.js.map +1 -0
- package/dist/oidc/protocol-security-observer.d.ts +38 -0
- package/dist/oidc/protocol-security-observer.d.ts.map +1 -0
- package/dist/oidc/protocol-security-observer.js +93 -0
- package/dist/oidc/protocol-security-observer.js.map +1 -0
- package/dist/oidc/provider.d.ts +37 -0
- package/dist/oidc/provider.d.ts.map +1 -0
- package/dist/oidc/provider.js +71 -0
- package/dist/oidc/provider.js.map +1 -0
- package/dist/oidc/redis-adapter.d.ts +140 -0
- package/dist/oidc/redis-adapter.d.ts.map +1 -0
- package/dist/oidc/redis-adapter.js +344 -0
- package/dist/oidc/redis-adapter.js.map +1 -0
- package/dist/organizations/cache.d.ts +60 -0
- package/dist/organizations/cache.d.ts.map +1 -0
- package/dist/organizations/cache.js +157 -0
- package/dist/organizations/cache.js.map +1 -0
- package/dist/organizations/errors.d.ts +25 -0
- package/dist/organizations/errors.d.ts.map +1 -0
- package/dist/organizations/errors.js +31 -0
- package/dist/organizations/errors.js.map +1 -0
- package/dist/organizations/index.d.ts +15 -0
- package/dist/organizations/index.d.ts.map +1 -0
- package/dist/organizations/index.js +15 -0
- package/dist/organizations/index.js.map +1 -0
- package/dist/organizations/repository.d.ts +183 -0
- package/dist/organizations/repository.d.ts.map +1 -0
- package/dist/organizations/repository.js +354 -0
- package/dist/organizations/repository.js.map +1 -0
- package/dist/organizations/service.d.ts +168 -0
- package/dist/organizations/service.d.ts.map +1 -0
- package/dist/organizations/service.js +511 -0
- package/dist/organizations/service.js.map +1 -0
- package/dist/organizations/slugs.d.ts +57 -0
- package/dist/organizations/slugs.d.ts.map +1 -0
- package/dist/organizations/slugs.js +130 -0
- package/dist/organizations/slugs.js.map +1 -0
- package/dist/organizations/types.d.ts +146 -0
- package/dist/organizations/types.d.ts.map +1 -0
- package/dist/organizations/types.js +49 -0
- package/dist/organizations/types.js.map +1 -0
- package/dist/rbac/cache.d.ts +110 -0
- package/dist/rbac/cache.d.ts.map +1 -0
- package/dist/rbac/cache.js +271 -0
- package/dist/rbac/cache.js.map +1 -0
- package/dist/rbac/errors.d.ts +34 -0
- package/dist/rbac/errors.d.ts.map +1 -0
- package/dist/rbac/errors.js +43 -0
- package/dist/rbac/errors.js.map +1 -0
- package/dist/rbac/index.d.ts +17 -0
- package/dist/rbac/index.d.ts.map +1 -0
- package/dist/rbac/index.js +21 -0
- package/dist/rbac/index.js.map +1 -0
- package/dist/rbac/mapping-repository.d.ts +121 -0
- package/dist/rbac/mapping-repository.d.ts.map +1 -0
- package/dist/rbac/mapping-repository.js +224 -0
- package/dist/rbac/mapping-repository.js.map +1 -0
- package/dist/rbac/permission-repository.d.ts +100 -0
- package/dist/rbac/permission-repository.d.ts.map +1 -0
- package/dist/rbac/permission-repository.js +190 -0
- package/dist/rbac/permission-repository.js.map +1 -0
- package/dist/rbac/permission-service.d.ts +85 -0
- package/dist/rbac/permission-service.d.ts.map +1 -0
- package/dist/rbac/permission-service.js +179 -0
- package/dist/rbac/permission-service.js.map +1 -0
- package/dist/rbac/role-repository.d.ts +104 -0
- package/dist/rbac/role-repository.d.ts.map +1 -0
- package/dist/rbac/role-repository.js +202 -0
- package/dist/rbac/role-repository.js.map +1 -0
- package/dist/rbac/role-service.d.ts +111 -0
- package/dist/rbac/role-service.d.ts.map +1 -0
- package/dist/rbac/role-service.js +256 -0
- package/dist/rbac/role-service.js.map +1 -0
- package/dist/rbac/slugs.d.ts +116 -0
- package/dist/rbac/slugs.d.ts.map +1 -0
- package/dist/rbac/slugs.js +178 -0
- package/dist/rbac/slugs.js.map +1 -0
- package/dist/rbac/types.d.ts +187 -0
- package/dist/rbac/types.d.ts.map +1 -0
- package/dist/rbac/types.js +75 -0
- package/dist/rbac/types.js.map +1 -0
- package/dist/rbac/user-role-service.d.ts +101 -0
- package/dist/rbac/user-role-service.d.ts.map +1 -0
- package/dist/rbac/user-role-service.js +166 -0
- package/dist/rbac/user-role-service.js.map +1 -0
- package/dist/routes/applications.d.ts +40 -0
- package/dist/routes/applications.d.ts.map +1 -0
- package/dist/routes/applications.js +284 -0
- package/dist/routes/applications.js.map +1 -0
- package/dist/routes/audit.d.ts +31 -0
- package/dist/routes/audit.d.ts.map +1 -0
- package/dist/routes/audit.js +140 -0
- package/dist/routes/audit.js.map +1 -0
- package/dist/routes/branding.d.ts +17 -0
- package/dist/routes/branding.d.ts.map +1 -0
- package/dist/routes/branding.js +104 -0
- package/dist/routes/branding.js.map +1 -0
- package/dist/routes/bulk.d.ts +37 -0
- package/dist/routes/bulk.d.ts.map +1 -0
- package/dist/routes/bulk.js +94 -0
- package/dist/routes/bulk.js.map +1 -0
- package/dist/routes/clients.d.ts +44 -0
- package/dist/routes/clients.d.ts.map +1 -0
- package/dist/routes/clients.js +353 -0
- package/dist/routes/clients.js.map +1 -0
- package/dist/routes/config.d.ts +35 -0
- package/dist/routes/config.d.ts.map +1 -0
- package/dist/routes/config.js +115 -0
- package/dist/routes/config.js.map +1 -0
- package/dist/routes/custom-claims.d.ts +38 -0
- package/dist/routes/custom-claims.d.ts.map +1 -0
- package/dist/routes/custom-claims.js +208 -0
- package/dist/routes/custom-claims.js.map +1 -0
- package/dist/routes/exports.d.ts +21 -0
- package/dist/routes/exports.d.ts.map +1 -0
- package/dist/routes/exports.js +98 -0
- package/dist/routes/exports.js.map +1 -0
- package/dist/routes/imports.d.ts +18 -0
- package/dist/routes/imports.d.ts.map +1 -0
- package/dist/routes/imports.js +72 -0
- package/dist/routes/imports.js.map +1 -0
- package/dist/routes/interactions.d.ts +111 -0
- package/dist/routes/interactions.d.ts.map +1 -0
- package/dist/routes/interactions.js +1074 -0
- package/dist/routes/interactions.js.map +1 -0
- package/dist/routes/invitation.d.ts +31 -0
- package/dist/routes/invitation.d.ts.map +1 -0
- package/dist/routes/invitation.js +342 -0
- package/dist/routes/invitation.js.map +1 -0
- package/dist/routes/keys.d.ts +28 -0
- package/dist/routes/keys.d.ts.map +1 -0
- package/dist/routes/keys.js +91 -0
- package/dist/routes/keys.js.map +1 -0
- package/dist/routes/magic-link.d.ts +43 -0
- package/dist/routes/magic-link.d.ts.map +1 -0
- package/dist/routes/magic-link.js +264 -0
- package/dist/routes/magic-link.js.map +1 -0
- package/dist/routes/organizations.d.ts +38 -0
- package/dist/routes/organizations.d.ts.map +1 -0
- package/dist/routes/organizations.js +347 -0
- package/dist/routes/organizations.js.map +1 -0
- package/dist/routes/password-reset.d.ts +65 -0
- package/dist/routes/password-reset.d.ts.map +1 -0
- package/dist/routes/password-reset.js +493 -0
- package/dist/routes/password-reset.js.map +1 -0
- package/dist/routes/permissions.d.ts +33 -0
- package/dist/routes/permissions.d.ts.map +1 -0
- package/dist/routes/permissions.js +166 -0
- package/dist/routes/permissions.js.map +1 -0
- package/dist/routes/roles.d.ts +37 -0
- package/dist/routes/roles.d.ts.map +1 -0
- package/dist/routes/roles.js +222 -0
- package/dist/routes/roles.js.map +1 -0
- package/dist/routes/sessions.d.ts +37 -0
- package/dist/routes/sessions.d.ts.map +1 -0
- package/dist/routes/sessions.js +121 -0
- package/dist/routes/sessions.js.map +1 -0
- package/dist/routes/stats.d.ts +28 -0
- package/dist/routes/stats.d.ts.map +1 -0
- package/dist/routes/stats.js +65 -0
- package/dist/routes/stats.js.map +1 -0
- package/dist/routes/two-factor-admin.d.ts +54 -0
- package/dist/routes/two-factor-admin.d.ts.map +1 -0
- package/dist/routes/two-factor-admin.js +344 -0
- package/dist/routes/two-factor-admin.js.map +1 -0
- package/dist/routes/two-factor.d.ts +31 -0
- package/dist/routes/two-factor.d.ts.map +1 -0
- package/dist/routes/two-factor.js +595 -0
- package/dist/routes/two-factor.js.map +1 -0
- package/dist/routes/user-roles.d.ts +33 -0
- package/dist/routes/user-roles.d.ts.map +1 -0
- package/dist/routes/user-roles.js +129 -0
- package/dist/routes/user-roles.js.map +1 -0
- package/dist/routes/users.d.ts +61 -0
- package/dist/routes/users.d.ts.map +1 -0
- package/dist/routes/users.js +868 -0
- package/dist/routes/users.js.map +1 -0
- package/dist/security/decision-context.d.ts +52 -0
- package/dist/security/decision-context.d.ts.map +1 -0
- package/dist/security/decision-context.js +150 -0
- package/dist/security/decision-context.js.map +1 -0
- package/dist/security/decision-event.d.ts +128 -0
- package/dist/security/decision-event.d.ts.map +1 -0
- package/dist/security/decision-event.js +225 -0
- package/dist/security/decision-event.js.map +1 -0
- package/dist/security/transport-decision.d.ts +6 -0
- package/dist/security/transport-decision.d.ts.map +1 -0
- package/dist/security/transport-decision.js +37 -0
- package/dist/security/transport-decision.js.map +1 -0
- package/dist/server.d.ts +50 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +491 -0
- package/dist/server.js.map +1 -0
- package/dist/two-factor/cache.d.ts +47 -0
- package/dist/two-factor/cache.d.ts.map +1 -0
- package/dist/two-factor/cache.js +122 -0
- package/dist/two-factor/cache.js.map +1 -0
- package/dist/two-factor/crypto.d.ts +41 -0
- package/dist/two-factor/crypto.d.ts.map +1 -0
- package/dist/two-factor/crypto.js +94 -0
- package/dist/two-factor/crypto.js.map +1 -0
- package/dist/two-factor/errors.d.ts +82 -0
- package/dist/two-factor/errors.d.ts.map +1 -0
- package/dist/two-factor/errors.js +112 -0
- package/dist/two-factor/errors.js.map +1 -0
- package/dist/two-factor/index.d.ts +18 -0
- package/dist/two-factor/index.d.ts.map +1 -0
- package/dist/two-factor/index.js +25 -0
- package/dist/two-factor/index.js.map +1 -0
- package/dist/two-factor/otp.d.ts +43 -0
- package/dist/two-factor/otp.d.ts.map +1 -0
- package/dist/two-factor/otp.js +57 -0
- package/dist/two-factor/otp.js.map +1 -0
- package/dist/two-factor/recovery.d.ts +45 -0
- package/dist/two-factor/recovery.d.ts.map +1 -0
- package/dist/two-factor/recovery.js +104 -0
- package/dist/two-factor/recovery.js.map +1 -0
- package/dist/two-factor/repository.d.ts +156 -0
- package/dist/two-factor/repository.d.ts.map +1 -0
- package/dist/two-factor/repository.js +251 -0
- package/dist/two-factor/repository.js.map +1 -0
- package/dist/two-factor/service.d.ts +232 -0
- package/dist/two-factor/service.d.ts.map +1 -0
- package/dist/two-factor/service.js +599 -0
- package/dist/two-factor/service.js.map +1 -0
- package/dist/two-factor/totp.d.ts +57 -0
- package/dist/two-factor/totp.d.ts.map +1 -0
- package/dist/two-factor/totp.js +96 -0
- package/dist/two-factor/totp.js.map +1 -0
- package/dist/two-factor/types.d.ts +152 -0
- package/dist/two-factor/types.d.ts.map +1 -0
- package/dist/two-factor/types.js +64 -0
- package/dist/two-factor/types.js.map +1 -0
- package/dist/users/cache.d.ts +49 -0
- package/dist/users/cache.d.ts.map +1 -0
- package/dist/users/cache.js +140 -0
- package/dist/users/cache.js.map +1 -0
- package/dist/users/claims.d.ts +67 -0
- package/dist/users/claims.d.ts.map +1 -0
- package/dist/users/claims.js +104 -0
- package/dist/users/claims.js.map +1 -0
- package/dist/users/errors.d.ts +25 -0
- package/dist/users/errors.d.ts.map +1 -0
- package/dist/users/errors.js +31 -0
- package/dist/users/errors.js.map +1 -0
- package/dist/users/gdpr.d.ts +110 -0
- package/dist/users/gdpr.d.ts.map +1 -0
- package/dist/users/gdpr.js +211 -0
- package/dist/users/gdpr.js.map +1 -0
- package/dist/users/index.d.ts +20 -0
- package/dist/users/index.d.ts.map +1 -0
- package/dist/users/index.js +19 -0
- package/dist/users/index.js.map +1 -0
- package/dist/users/password.d.ts +85 -0
- package/dist/users/password.d.ts.map +1 -0
- package/dist/users/password.js +138 -0
- package/dist/users/password.js.map +1 -0
- package/dist/users/repository.d.ts +263 -0
- package/dist/users/repository.d.ts.map +1 -0
- package/dist/users/repository.js +499 -0
- package/dist/users/repository.js.map +1 -0
- package/dist/users/service.d.ts +299 -0
- package/dist/users/service.d.ts.map +1 -0
- package/dist/users/service.js +698 -0
- package/dist/users/service.js.map +1 -0
- package/dist/users/types.d.ts +220 -0
- package/dist/users/types.d.ts.map +1 -0
- package/dist/users/types.js +77 -0
- package/dist/users/types.js.map +1 -0
- package/locales/default/en/common.json +10 -0
- package/locales/default/en/consent.json +13 -0
- package/locales/default/en/emails.json +17 -0
- package/locales/default/en/errors.json +21 -0
- package/locales/default/en/forgot-password.json +11 -0
- package/locales/default/en/invitation.json +18 -0
- package/locales/default/en/login.json +17 -0
- package/locales/default/en/logout.json +9 -0
- package/locales/default/en/magic-link.json +12 -0
- package/locales/default/en/reset-password.json +16 -0
- package/locales/default/en/two-factor.json +29 -0
- package/migrations/.gitkeep +0 -0
- package/migrations/001_extensions.sql +22 -0
- package/migrations/002_organizations.sql +43 -0
- package/migrations/003_applications.sql +50 -0
- package/migrations/004_clients.sql +74 -0
- package/migrations/005_users.sql +119 -0
- package/migrations/006_roles_permissions.sql +80 -0
- package/migrations/007_custom_claims.sql +55 -0
- package/migrations/008_config.sql +51 -0
- package/migrations/009_audit_log.sql +31 -0
- package/migrations/010_oidc_adapter.sql +34 -0
- package/migrations/011_seed.sql +53 -0
- package/migrations/012_two_factor.sql +88 -0
- package/migrations/013_client_secret_sha256.sql +22 -0
- package/migrations/014_login_methods.sql +34 -0
- package/migrations/015_signing_key_encryption.sql +20 -0
- package/migrations/016_failed_login_count.sql +27 -0
- package/migrations/017_audit_retention.sql +11 -0
- package/migrations/018_admin_api_enhancements.sql +78 -0
- package/migrations/019_invitation_details.sql +27 -0
- package/migrations/020_two_factor_admin_permission.sql +108 -0
- package/migrations/021_auth_recovery_jobs.sql +74 -0
- package/migrations/022_recovery_artifact_ownership.sql +25 -0
- package/migrations/023_magic_link_authority.sql +39 -0
- package/package.json +106 -0
- package/templates/default/emails/invitation.hbs +39 -0
- package/templates/default/emails/invitation.txt.hbs +18 -0
- package/templates/default/emails/magic-link.hbs +30 -0
- package/templates/default/emails/magic-link.txt.hbs +11 -0
- package/templates/default/emails/otp-code.hbs +31 -0
- package/templates/default/emails/otp-code.txt.hbs +15 -0
- package/templates/default/emails/password-changed.hbs +24 -0
- package/templates/default/emails/password-changed.txt.hbs +7 -0
- package/templates/default/emails/password-reset.hbs +30 -0
- package/templates/default/emails/password-reset.txt.hbs +11 -0
- package/templates/default/emails/welcome.hbs +25 -0
- package/templates/default/emails/welcome.txt.hbs +9 -0
- package/templates/default/layouts/main.hbs +49 -0
- package/templates/default/pages/accept-invite.hbs +25 -0
- package/templates/default/pages/consent.hbs +27 -0
- package/templates/default/pages/error.hbs +15 -0
- package/templates/default/pages/forgot-password.hbs +21 -0
- package/templates/default/pages/invite-expired.hbs +6 -0
- package/templates/default/pages/invite-success.hbs +9 -0
- package/templates/default/pages/login.hbs +108 -0
- package/templates/default/pages/logout-success.hbs +5 -0
- package/templates/default/pages/logout.hbs +24 -0
- package/templates/default/pages/magic-link-sent.hbs +10 -0
- package/templates/default/pages/magic-link-success.hbs +17 -0
- package/templates/default/pages/reset-password.hbs +20 -0
- package/templates/default/pages/reset-success.hbs +9 -0
- package/templates/default/pages/two-factor-setup.hbs +65 -0
- package/templates/default/pages/two-factor-verify.hbs +77 -0
- package/templates/default/partials/flash-messages.hbs +10 -0
- package/templates/default/partials/footer.hbs +4 -0
- package/templates/default/partials/header.hbs +8 -0
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Two-factor authentication route handlers.
|
|
3
|
+
*
|
|
4
|
+
* Handles the 2FA challenge during OIDC login interactions:
|
|
5
|
+
* GET /interaction/:uid/two-factor → showTwoFactor (render verification page)
|
|
6
|
+
* POST /interaction/:uid/two-factor → verifyTwoFactor (verify code + finish login)
|
|
7
|
+
* POST /interaction/:uid/two-factor/resend → resendOtpCode (rate-limited OTP resend)
|
|
8
|
+
* GET /interaction/:uid/two-factor/setup → showTwoFactorSetup (TOTP enrollment)
|
|
9
|
+
* POST /interaction/:uid/two-factor/setup → processTwoFactorSetup (confirm enrollment)
|
|
10
|
+
*
|
|
11
|
+
* Security features:
|
|
12
|
+
* - CSRF protection on all POST endpoints
|
|
13
|
+
* - Rate limiting on verification and resend
|
|
14
|
+
* - Recovery code fallback support
|
|
15
|
+
* - Audit logging for all 2FA events
|
|
16
|
+
*
|
|
17
|
+
* @module routes/two-factor
|
|
18
|
+
*/
|
|
19
|
+
import Router from '@koa/router';
|
|
20
|
+
import { generateCsrfToken, verifyCsrfToken, setCsrfCookie, getCsrfFromCookie, } from '../auth/csrf.js';
|
|
21
|
+
import { checkRateLimit, buildRateLimitKey } from '../auth/rate-limiter.js';
|
|
22
|
+
import { resolveLocale, getTranslationFunction } from '../auth/i18n.js';
|
|
23
|
+
import { renderPage } from '../auth/template-engine.js';
|
|
24
|
+
import { sendOtpCodeEmail } from '../auth/email-service.js';
|
|
25
|
+
import { recordLogin } from '../users/service.js';
|
|
26
|
+
import { findUserById } from '../users/repository.js';
|
|
27
|
+
import { verifyOtp, verifyTotp, verifyRecoveryCode as verifyRecoveryCodeService, sendOtpCode, setupTotp, getPendingTotpSetupInfo, setupEmailOtp, confirmTotpSetup, } from '../two-factor/service.js';
|
|
28
|
+
import { writeAuditLog } from '../lib/audit-log.js';
|
|
29
|
+
import { logger } from '../lib/logger.js';
|
|
30
|
+
import { resolveOrganizationForInteraction } from './interactions.js';
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Constants
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
/** Rate limit config for 2FA verification attempts: 5 per 5 min */
|
|
35
|
+
const VERIFY_RATE_LIMIT = { max: 5, windowSeconds: 300 };
|
|
36
|
+
/** Rate limit config for OTP resend: 3 per 5 min */
|
|
37
|
+
const RESEND_RATE_LIMIT = { max: 3, windowSeconds: 300 };
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Helpers
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
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
|
+
/**
|
|
57
|
+
* Build a base template context for 2FA pages.
|
|
58
|
+
*
|
|
59
|
+
* @param ctx - Koa context with organization state
|
|
60
|
+
* @param locale - Resolved locale
|
|
61
|
+
* @param csrfToken - CSRF token for form protection
|
|
62
|
+
* @param orgSlug - Organization slug
|
|
63
|
+
* @returns Base template context
|
|
64
|
+
*/
|
|
65
|
+
function buildBaseContext(ctx, locale, csrfToken, orgSlug) {
|
|
66
|
+
return {
|
|
67
|
+
branding: buildBrandingFromOrg(ctx.state.organization),
|
|
68
|
+
locale,
|
|
69
|
+
csrfToken,
|
|
70
|
+
orgSlug,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Render a page template and send as response.
|
|
75
|
+
*
|
|
76
|
+
* @param ctx - Koa context
|
|
77
|
+
* @param pageName - Template name
|
|
78
|
+
* @param context - Template context
|
|
79
|
+
* @param statusCode - HTTP status (default: 200)
|
|
80
|
+
*/
|
|
81
|
+
async function renderAndRespond(ctx, pageName, context, statusCode = 200) {
|
|
82
|
+
const html = await renderPage(pageName, context);
|
|
83
|
+
ctx.status = statusCode;
|
|
84
|
+
ctx.type = 'text/html';
|
|
85
|
+
ctx.body = html;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Mask an email address for display (e.g., "u***r@test.com").
|
|
89
|
+
* Shows first char, last char before @, and full domain.
|
|
90
|
+
*
|
|
91
|
+
* @param email - Full email address
|
|
92
|
+
* @returns Masked email string
|
|
93
|
+
*/
|
|
94
|
+
function maskEmail(email) {
|
|
95
|
+
const [local, domain] = email.split('@');
|
|
96
|
+
if (!local || !domain)
|
|
97
|
+
return '***@***';
|
|
98
|
+
if (local.length <= 2)
|
|
99
|
+
return `${local[0]}***@${domain}`;
|
|
100
|
+
return `${local[0]}***${local[local.length - 1]}@${domain}`;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Extract the pending 2FA state from an interaction result.
|
|
104
|
+
* Returns null if no pending 2FA exists (interaction expired or invalid).
|
|
105
|
+
*
|
|
106
|
+
* @param interaction - OIDC interaction details
|
|
107
|
+
* @returns Pending 2FA state, or null
|
|
108
|
+
*/
|
|
109
|
+
function getPendingTwoFactor(interaction) {
|
|
110
|
+
const result = interaction.result;
|
|
111
|
+
if (!result?.twoFactor)
|
|
112
|
+
return null;
|
|
113
|
+
const tf = result.twoFactor;
|
|
114
|
+
if (!tf.pendingAccountId || !tf.method || !tf.email)
|
|
115
|
+
return null;
|
|
116
|
+
return tf;
|
|
117
|
+
}
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Router factory
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
/**
|
|
122
|
+
* Create the two-factor authentication router.
|
|
123
|
+
*
|
|
124
|
+
* Mounts 2FA verification, resend, and setup routes under /interaction/:uid/two-factor.
|
|
125
|
+
* Requires a Provider instance to read/write interaction state.
|
|
126
|
+
*
|
|
127
|
+
* @param provider - node-oidc-provider instance
|
|
128
|
+
* @returns Koa router with 2FA routes
|
|
129
|
+
*/
|
|
130
|
+
export function createTwoFactorRouter(provider) {
|
|
131
|
+
const router = new Router({ prefix: '/interaction' });
|
|
132
|
+
// GET /interaction/:uid/two-factor — Show 2FA verification page
|
|
133
|
+
router.get('/:uid/two-factor', async (ctx) => {
|
|
134
|
+
await showTwoFactor(ctx, provider);
|
|
135
|
+
});
|
|
136
|
+
// POST /interaction/:uid/two-factor — Verify 2FA code
|
|
137
|
+
router.post('/:uid/two-factor', async (ctx) => {
|
|
138
|
+
await verifyTwoFactor(ctx, provider);
|
|
139
|
+
});
|
|
140
|
+
// POST /interaction/:uid/two-factor/resend — Resend OTP code
|
|
141
|
+
router.post('/:uid/two-factor/resend', async (ctx) => {
|
|
142
|
+
await resendOtpCode(ctx, provider);
|
|
143
|
+
});
|
|
144
|
+
// GET /interaction/:uid/two-factor/setup — Show 2FA setup page
|
|
145
|
+
router.get('/:uid/two-factor/setup', async (ctx) => {
|
|
146
|
+
await showTwoFactorSetup(ctx, provider);
|
|
147
|
+
});
|
|
148
|
+
// POST /interaction/:uid/two-factor/setup — Process 2FA setup
|
|
149
|
+
router.post('/:uid/two-factor/setup', async (ctx) => {
|
|
150
|
+
await processTwoFactorSetup(ctx, provider);
|
|
151
|
+
});
|
|
152
|
+
return router;
|
|
153
|
+
}
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
// Route handlers
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
/**
|
|
158
|
+
* Show the 2FA verification page.
|
|
159
|
+
*
|
|
160
|
+
* Reads the pending 2FA state from the interaction session.
|
|
161
|
+
* Renders the two-factor-verify page with method info and masked email.
|
|
162
|
+
*
|
|
163
|
+
* @param ctx - Koa context
|
|
164
|
+
* @param provider - OIDC provider instance
|
|
165
|
+
*/
|
|
166
|
+
async function showTwoFactor(ctx, provider) {
|
|
167
|
+
try {
|
|
168
|
+
const interaction = await provider.interactionDetails(ctx.req, ctx.res);
|
|
169
|
+
// Resolve organization from the interaction's client_id.
|
|
170
|
+
// 2FA routes don't go through the tenant resolver middleware,
|
|
171
|
+
// so we resolve the org from the client → organization chain.
|
|
172
|
+
await resolveOrganizationForInteraction(ctx, interaction.params.client_id, interaction.uid);
|
|
173
|
+
const pending = getPendingTwoFactor(interaction);
|
|
174
|
+
if (!pending) {
|
|
175
|
+
// No pending 2FA — redirect back to login
|
|
176
|
+
ctx.redirect(`/interaction/${interaction.uid}`);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const org = ctx.state.organization;
|
|
180
|
+
const locale = await resolveLocale(undefined, ctx.get('Accept-Language') || undefined, org.defaultLocale);
|
|
181
|
+
const t = getTranslationFunction(locale, org.slug);
|
|
182
|
+
const csrfToken = generateCsrfToken();
|
|
183
|
+
setCsrfCookie(ctx, csrfToken);
|
|
184
|
+
const context = {
|
|
185
|
+
...buildBaseContext(ctx, locale, csrfToken, org.slug),
|
|
186
|
+
t,
|
|
187
|
+
interaction: {
|
|
188
|
+
uid: interaction.uid,
|
|
189
|
+
prompt: 'two-factor',
|
|
190
|
+
params: {},
|
|
191
|
+
client: { clientName: '' },
|
|
192
|
+
},
|
|
193
|
+
method: pending.method,
|
|
194
|
+
maskedEmail: maskEmail(pending.email),
|
|
195
|
+
showResend: pending.method === 'email',
|
|
196
|
+
showRecoveryLink: true,
|
|
197
|
+
};
|
|
198
|
+
await renderAndRespond(ctx, 'two-factor-verify', context);
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
logger.error({ event: 'two-factor-page-failed' }, 'Two-factor page rendering failed');
|
|
202
|
+
ctx.status = 400;
|
|
203
|
+
ctx.body = 'Interaction expired';
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Verify a 2FA code submission.
|
|
208
|
+
*
|
|
209
|
+
* Supports OTP (email), TOTP (authenticator), and recovery codes.
|
|
210
|
+
* On success: records login and finishes the OIDC interaction.
|
|
211
|
+
* On failure: re-renders the verification page with an error.
|
|
212
|
+
*
|
|
213
|
+
* @param ctx - Koa context
|
|
214
|
+
* @param provider - OIDC provider instance
|
|
215
|
+
*/
|
|
216
|
+
async function verifyTwoFactor(ctx, provider) {
|
|
217
|
+
const body = ctx.request.body;
|
|
218
|
+
const code = (body.code ?? '').trim();
|
|
219
|
+
const codeType = body.codeType ?? 'otp'; // 'otp', 'totp', or 'recovery'
|
|
220
|
+
const submittedCsrf = body._csrf ?? '';
|
|
221
|
+
const storedCsrf = getCsrfFromCookie(ctx) ?? '';
|
|
222
|
+
try {
|
|
223
|
+
const interaction = await provider.interactionDetails(ctx.req, ctx.res);
|
|
224
|
+
// Resolve organization from the interaction's client_id.
|
|
225
|
+
// 2FA routes don't go through the tenant resolver middleware.
|
|
226
|
+
await resolveOrganizationForInteraction(ctx, interaction.params.client_id, interaction.uid);
|
|
227
|
+
const org = ctx.state.organization;
|
|
228
|
+
const pending = getPendingTwoFactor(interaction);
|
|
229
|
+
if (!pending) {
|
|
230
|
+
ctx.redirect(`/interaction/${interaction.uid}`);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const locale = await resolveLocale(undefined, ctx.get('Accept-Language') || undefined, org.defaultLocale);
|
|
234
|
+
const t = getTranslationFunction(locale, org.slug);
|
|
235
|
+
// Verify CSRF token (cookie vs form field)
|
|
236
|
+
if (!verifyCsrfToken(storedCsrf, submittedCsrf)) {
|
|
237
|
+
logger.warn({ event: 'two-factor-csrf-rejected' }, 'Two-factor CSRF validation failed');
|
|
238
|
+
await renderTwoFactorWithError(ctx, interaction.uid, pending, locale, t, t('errors.csrf_invalid'));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
// Rate limit check — prevent brute force
|
|
242
|
+
const rateLimitKey = buildRateLimitKey('2fa_verify', org.id, pending.pendingAccountId);
|
|
243
|
+
const rateLimitResult = await checkRateLimit(rateLimitKey, VERIFY_RATE_LIMIT);
|
|
244
|
+
if (!rateLimitResult.allowed) {
|
|
245
|
+
ctx.set('Retry-After', String(rateLimitResult.retryAfter));
|
|
246
|
+
writeAuditLog({
|
|
247
|
+
organizationId: org.id,
|
|
248
|
+
userId: pending.pendingAccountId,
|
|
249
|
+
eventType: 'rate_limit.2fa_verify',
|
|
250
|
+
eventCategory: 'security',
|
|
251
|
+
description: '2FA verification rate limit exceeded',
|
|
252
|
+
ipAddress: ctx.ip,
|
|
253
|
+
});
|
|
254
|
+
await renderTwoFactorWithError(ctx, interaction.uid, pending, locale, t, t('errors.rate_limit_exceeded'), 429);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
// Validate code is not empty
|
|
258
|
+
if (!code) {
|
|
259
|
+
await renderTwoFactorWithError(ctx, interaction.uid, pending, locale, t, t('two-factor.error_code_required'));
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
// Attempt verification based on code type
|
|
263
|
+
let verified = false;
|
|
264
|
+
try {
|
|
265
|
+
if (codeType === 'recovery') {
|
|
266
|
+
verified = await verifyRecoveryCodeService(pending.pendingAccountId, code);
|
|
267
|
+
}
|
|
268
|
+
else if (pending.method === 'totp') {
|
|
269
|
+
verified = await verifyTotp(pending.pendingAccountId, code);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
// Email OTP
|
|
273
|
+
verified = await verifyOtp(pending.pendingAccountId, code);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
// Verification service threw an error (invalid code, expired, exhausted, etc.)
|
|
278
|
+
logger.debug({ event: 'two-factor-code-rejected', codeType }, 'Two-factor code rejected');
|
|
279
|
+
verified = false;
|
|
280
|
+
}
|
|
281
|
+
if (!verified) {
|
|
282
|
+
writeAuditLog({
|
|
283
|
+
organizationId: org.id,
|
|
284
|
+
userId: pending.pendingAccountId,
|
|
285
|
+
eventType: '2fa.verify.failed',
|
|
286
|
+
eventCategory: 'security',
|
|
287
|
+
description: `2FA verification failed (${codeType})`,
|
|
288
|
+
ipAddress: ctx.ip,
|
|
289
|
+
});
|
|
290
|
+
await renderTwoFactorWithError(ctx, interaction.uid, pending, locale, t, t('two-factor.error_invalid_code'));
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
// 2FA verified successfully — complete login
|
|
294
|
+
await recordLogin(pending.pendingAccountId);
|
|
295
|
+
writeAuditLog({
|
|
296
|
+
organizationId: org.id,
|
|
297
|
+
userId: pending.pendingAccountId,
|
|
298
|
+
eventType: '2fa.verify.success',
|
|
299
|
+
eventCategory: 'authentication',
|
|
300
|
+
description: `2FA verification successful (${codeType})`,
|
|
301
|
+
ipAddress: ctx.ip,
|
|
302
|
+
});
|
|
303
|
+
// Finish the OIDC interaction with the verified user
|
|
304
|
+
await provider.interactionFinished(ctx.req, ctx.res, {
|
|
305
|
+
login: { accountId: pending.pendingAccountId },
|
|
306
|
+
}, { mergeWithLastSubmission: false });
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
logger.error({ event: 'two-factor-verification-failed' }, 'Two-factor verification failed');
|
|
310
|
+
ctx.status = 400;
|
|
311
|
+
ctx.body = 'Interaction expired';
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Resend an OTP code via email (rate-limited).
|
|
316
|
+
*
|
|
317
|
+
* Only available for the 'email' 2FA method. Generates a new code
|
|
318
|
+
* and sends it, then redirects back to the verification page.
|
|
319
|
+
*
|
|
320
|
+
* @param ctx - Koa context
|
|
321
|
+
* @param provider - OIDC provider instance
|
|
322
|
+
*/
|
|
323
|
+
async function resendOtpCode(ctx, provider) {
|
|
324
|
+
try {
|
|
325
|
+
const interaction = await provider.interactionDetails(ctx.req, ctx.res);
|
|
326
|
+
// Resolve organization from the interaction's client_id.
|
|
327
|
+
// 2FA routes don't go through the tenant resolver middleware.
|
|
328
|
+
await resolveOrganizationForInteraction(ctx, interaction.params.client_id, interaction.uid);
|
|
329
|
+
const org = ctx.state.organization;
|
|
330
|
+
const pending = getPendingTwoFactor(interaction);
|
|
331
|
+
if (!pending || pending.method !== 'email') {
|
|
332
|
+
ctx.redirect(`/interaction/${interaction.uid}/two-factor`);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
// Rate limit check for resend
|
|
336
|
+
const rateLimitKey = buildRateLimitKey('2fa_resend', org.id, pending.pendingAccountId);
|
|
337
|
+
const rateLimitResult = await checkRateLimit(rateLimitKey, RESEND_RATE_LIMIT);
|
|
338
|
+
if (!rateLimitResult.allowed) {
|
|
339
|
+
ctx.set('Retry-After', String(rateLimitResult.retryAfter));
|
|
340
|
+
// Redirect back — the page will show the rate limit naturally
|
|
341
|
+
ctx.redirect(`/interaction/${interaction.uid}/two-factor`);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
const locale = await resolveLocale(undefined, ctx.get('Accept-Language') || undefined, org.defaultLocale);
|
|
345
|
+
// Generate and send new OTP code
|
|
346
|
+
try {
|
|
347
|
+
const otpCode = await sendOtpCode(pending.pendingAccountId, pending.email, org.id);
|
|
348
|
+
const user = await findUserById(pending.pendingAccountId);
|
|
349
|
+
sendOtpCodeEmail({
|
|
350
|
+
id: pending.pendingAccountId,
|
|
351
|
+
email: pending.email,
|
|
352
|
+
givenName: user?.givenName,
|
|
353
|
+
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);
|
|
361
|
+
}
|
|
362
|
+
catch {
|
|
363
|
+
logger.warn({ event: 'two-factor-otp-resend-failed' }, 'OTP resend failed');
|
|
364
|
+
}
|
|
365
|
+
writeAuditLog({
|
|
366
|
+
organizationId: org.id,
|
|
367
|
+
userId: pending.pendingAccountId,
|
|
368
|
+
eventType: '2fa.otp.resent',
|
|
369
|
+
eventCategory: 'authentication',
|
|
370
|
+
description: 'OTP code resent',
|
|
371
|
+
ipAddress: ctx.ip,
|
|
372
|
+
});
|
|
373
|
+
ctx.redirect(`/interaction/${interaction.uid}/two-factor`);
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
logger.error({ event: 'two-factor-resend-failed' }, 'Two-factor resend failed');
|
|
377
|
+
ctx.status = 400;
|
|
378
|
+
ctx.body = 'Interaction expired';
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Show the 2FA setup page (for users who need to enroll).
|
|
383
|
+
*
|
|
384
|
+
* When an org requires 2FA but the user hasn't enrolled, this page
|
|
385
|
+
* shows the TOTP QR code or email OTP setup option.
|
|
386
|
+
*
|
|
387
|
+
* @param ctx - Koa context
|
|
388
|
+
* @param provider - OIDC provider instance
|
|
389
|
+
*/
|
|
390
|
+
async function showTwoFactorSetup(ctx, provider) {
|
|
391
|
+
try {
|
|
392
|
+
const interaction = await provider.interactionDetails(ctx.req, ctx.res);
|
|
393
|
+
// Resolve organization from the interaction's client_id.
|
|
394
|
+
// 2FA routes don't go through the tenant resolver middleware.
|
|
395
|
+
await resolveOrganizationForInteraction(ctx, interaction.params.client_id, interaction.uid);
|
|
396
|
+
const pending = getPendingTwoFactor(interaction);
|
|
397
|
+
if (!pending) {
|
|
398
|
+
ctx.redirect(`/interaction/${interaction.uid}`);
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
const org = ctx.state.organization;
|
|
402
|
+
const locale = await resolveLocale(undefined, ctx.get('Accept-Language') || undefined, org.defaultLocale);
|
|
403
|
+
const t = getTranslationFunction(locale, org.slug);
|
|
404
|
+
const csrfToken = generateCsrfToken();
|
|
405
|
+
setCsrfCookie(ctx, csrfToken);
|
|
406
|
+
// Check for existing pending TOTP setup (avoids regenerating on page reload/error retry)
|
|
407
|
+
const existingSetup = await getPendingTotpSetupInfo(pending.pendingAccountId, pending.email, org.slug);
|
|
408
|
+
let qrCodeDataUri;
|
|
409
|
+
let totpSecret;
|
|
410
|
+
let recoveryCodes;
|
|
411
|
+
if (existingSetup) {
|
|
412
|
+
// Reuse existing pending setup — don't regenerate the secret
|
|
413
|
+
qrCodeDataUri = existingSetup.qrCodeDataUri;
|
|
414
|
+
totpSecret = existingSetup.totpUri?.split('secret=')[1]?.split('&')[0] ?? '';
|
|
415
|
+
}
|
|
416
|
+
else {
|
|
417
|
+
// No pending setup — generate a fresh one
|
|
418
|
+
const setupResult = await setupTotp(pending.pendingAccountId, pending.email, org.slug);
|
|
419
|
+
qrCodeDataUri = setupResult.qrCodeDataUri;
|
|
420
|
+
totpSecret = setupResult.totpUri?.split('secret=')[1]?.split('&')[0] ?? '';
|
|
421
|
+
recoveryCodes = setupResult.recoveryCodes;
|
|
422
|
+
}
|
|
423
|
+
// Check for error indicator from failed verification redirect
|
|
424
|
+
const errorParam = ctx.query.error ?? '';
|
|
425
|
+
const context = {
|
|
426
|
+
...buildBaseContext(ctx, locale, csrfToken, org.slug),
|
|
427
|
+
t,
|
|
428
|
+
interaction: {
|
|
429
|
+
uid: interaction.uid,
|
|
430
|
+
prompt: 'two-factor-setup',
|
|
431
|
+
params: {},
|
|
432
|
+
client: { clientName: '' },
|
|
433
|
+
},
|
|
434
|
+
method: 'totp',
|
|
435
|
+
qrCodeDataUri,
|
|
436
|
+
totpSecret,
|
|
437
|
+
recoveryCodes,
|
|
438
|
+
flash: errorParam === 'invalid_code' ? { error: t('two-factor.error_invalid_code') } : undefined,
|
|
439
|
+
};
|
|
440
|
+
await renderAndRespond(ctx, 'two-factor-setup', context);
|
|
441
|
+
}
|
|
442
|
+
catch {
|
|
443
|
+
logger.error({ event: 'two-factor-setup-page-failed' }, 'Two-factor setup page failed');
|
|
444
|
+
ctx.status = 400;
|
|
445
|
+
ctx.body = 'Interaction expired';
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Process 2FA setup confirmation.
|
|
450
|
+
*
|
|
451
|
+
* Verifies the user's first TOTP code to confirm enrollment.
|
|
452
|
+
* On success: enables 2FA and completes the login.
|
|
453
|
+
* On failure: re-renders the setup page with an error.
|
|
454
|
+
*
|
|
455
|
+
* @param ctx - Koa context
|
|
456
|
+
* @param provider - OIDC provider instance
|
|
457
|
+
*/
|
|
458
|
+
async function processTwoFactorSetup(ctx, provider) {
|
|
459
|
+
const body = ctx.request.body;
|
|
460
|
+
const code = (body.code ?? '').trim();
|
|
461
|
+
const submittedCsrf = body._csrf ?? '';
|
|
462
|
+
const storedCsrf = getCsrfFromCookie(ctx) ?? '';
|
|
463
|
+
// setupMethod determines whether to use TOTP or email OTP for setup
|
|
464
|
+
const setupMethod = body.setupMethod ?? 'totp';
|
|
465
|
+
try {
|
|
466
|
+
const interaction = await provider.interactionDetails(ctx.req, ctx.res);
|
|
467
|
+
// Resolve organization from the interaction's client_id.
|
|
468
|
+
// 2FA routes don't go through the tenant resolver middleware.
|
|
469
|
+
await resolveOrganizationForInteraction(ctx, interaction.params.client_id, interaction.uid);
|
|
470
|
+
const org = ctx.state.organization;
|
|
471
|
+
const pending = getPendingTwoFactor(interaction);
|
|
472
|
+
if (!pending) {
|
|
473
|
+
ctx.redirect(`/interaction/${interaction.uid}`);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
const locale = await resolveLocale(undefined, ctx.get('Accept-Language') || undefined, org.defaultLocale);
|
|
477
|
+
// Verify CSRF token
|
|
478
|
+
if (!verifyCsrfToken(storedCsrf, submittedCsrf)) {
|
|
479
|
+
logger.warn({ event: 'two-factor-setup-csrf-rejected' }, 'Two-factor setup CSRF failed');
|
|
480
|
+
// Redirect back to setup to try again
|
|
481
|
+
ctx.redirect(`/interaction/${interaction.uid}/two-factor/setup`);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
if (setupMethod === 'email') {
|
|
485
|
+
// Email OTP setup — just enable it (no confirmation code needed)
|
|
486
|
+
await setupEmailOtp(pending.pendingAccountId, org.id);
|
|
487
|
+
writeAuditLog({
|
|
488
|
+
organizationId: org.id,
|
|
489
|
+
userId: pending.pendingAccountId,
|
|
490
|
+
eventType: '2fa.setup.email.complete',
|
|
491
|
+
eventCategory: 'authentication',
|
|
492
|
+
description: '2FA email OTP setup completed during login',
|
|
493
|
+
ipAddress: ctx.ip,
|
|
494
|
+
});
|
|
495
|
+
// Now send the first OTP and redirect to verification
|
|
496
|
+
try {
|
|
497
|
+
const otpCode = await sendOtpCode(pending.pendingAccountId, pending.email, org.id);
|
|
498
|
+
const user = await findUserById(pending.pendingAccountId);
|
|
499
|
+
sendOtpCodeEmail({
|
|
500
|
+
id: pending.pendingAccountId,
|
|
501
|
+
email: pending.email,
|
|
502
|
+
givenName: user?.givenName,
|
|
503
|
+
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);
|
|
511
|
+
}
|
|
512
|
+
catch {
|
|
513
|
+
logger.warn({ event: 'two-factor-setup-otp-failed' }, 'Setup OTP delivery failed');
|
|
514
|
+
}
|
|
515
|
+
// Update the interaction pending method to email
|
|
516
|
+
await provider.interactionResult(ctx.req, ctx.res, {
|
|
517
|
+
twoFactor: { ...pending, method: 'email' },
|
|
518
|
+
}, { mergeWithLastSubmission: true });
|
|
519
|
+
ctx.redirect(`/interaction/${interaction.uid}/two-factor`);
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
// TOTP setup confirmation — verify the code from authenticator app
|
|
523
|
+
if (!code) {
|
|
524
|
+
ctx.redirect(`/interaction/${interaction.uid}/two-factor/setup`);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
const confirmed = await confirmTotpSetup(pending.pendingAccountId, code);
|
|
528
|
+
if (!confirmed) {
|
|
529
|
+
writeAuditLog({
|
|
530
|
+
organizationId: org.id,
|
|
531
|
+
userId: pending.pendingAccountId,
|
|
532
|
+
eventType: '2fa.setup.totp.failed',
|
|
533
|
+
eventCategory: 'security',
|
|
534
|
+
description: 'TOTP setup confirmation failed — invalid code',
|
|
535
|
+
ipAddress: ctx.ip,
|
|
536
|
+
});
|
|
537
|
+
// Redirect back to setup with error indicator
|
|
538
|
+
ctx.redirect(`/interaction/${interaction.uid}/two-factor/setup?error=invalid_code`);
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
// TOTP setup confirmed — complete login
|
|
542
|
+
await recordLogin(pending.pendingAccountId);
|
|
543
|
+
writeAuditLog({
|
|
544
|
+
organizationId: org.id,
|
|
545
|
+
userId: pending.pendingAccountId,
|
|
546
|
+
eventType: '2fa.setup.totp.complete',
|
|
547
|
+
eventCategory: 'authentication',
|
|
548
|
+
description: '2FA TOTP setup and login completed',
|
|
549
|
+
ipAddress: ctx.ip,
|
|
550
|
+
});
|
|
551
|
+
await provider.interactionFinished(ctx.req, ctx.res, {
|
|
552
|
+
login: { accountId: pending.pendingAccountId },
|
|
553
|
+
}, { mergeWithLastSubmission: false });
|
|
554
|
+
}
|
|
555
|
+
catch {
|
|
556
|
+
logger.error({ event: 'two-factor-setup-failed' }, 'Two-factor setup failed');
|
|
557
|
+
ctx.status = 400;
|
|
558
|
+
ctx.body = 'Interaction expired';
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
// ---------------------------------------------------------------------------
|
|
562
|
+
// Helper: render 2FA verify page with error
|
|
563
|
+
// ---------------------------------------------------------------------------
|
|
564
|
+
/**
|
|
565
|
+
* Render the 2FA verification page with an error flash message.
|
|
566
|
+
*
|
|
567
|
+
* @param ctx - Koa context
|
|
568
|
+
* @param uid - Interaction UID
|
|
569
|
+
* @param pending - Pending 2FA state
|
|
570
|
+
* @param locale - Resolved locale
|
|
571
|
+
* @param t - Translation function
|
|
572
|
+
* @param errorMessage - Error to display
|
|
573
|
+
* @param statusCode - HTTP status (default: 200)
|
|
574
|
+
*/
|
|
575
|
+
async function renderTwoFactorWithError(ctx, uid, pending, locale, t, errorMessage, statusCode = 200) {
|
|
576
|
+
const csrfToken = generateCsrfToken();
|
|
577
|
+
setCsrfCookie(ctx, csrfToken);
|
|
578
|
+
const context = {
|
|
579
|
+
...buildBaseContext(ctx, locale, csrfToken, ctx.state.organization.slug),
|
|
580
|
+
t,
|
|
581
|
+
interaction: {
|
|
582
|
+
uid,
|
|
583
|
+
prompt: 'two-factor',
|
|
584
|
+
params: {},
|
|
585
|
+
client: { clientName: '' },
|
|
586
|
+
},
|
|
587
|
+
method: pending.method,
|
|
588
|
+
maskedEmail: maskEmail(pending.email),
|
|
589
|
+
showResend: pending.method === 'email',
|
|
590
|
+
showRecoveryLink: true,
|
|
591
|
+
flash: { error: errorMessage },
|
|
592
|
+
};
|
|
593
|
+
await renderAndRespond(ctx, 'two-factor-verify', context, statusCode);
|
|
594
|
+
}
|
|
595
|
+
//# sourceMappingURL=two-factor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"two-factor.js","sourceRoot":"","sources":["../../src/routes/two-factor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-role assignment API routes.
|
|
3
|
+
*
|
|
4
|
+
* All routes are under `/api/admin/organizations/:orgId/users/:userId/roles`
|
|
5
|
+
* and require admin authorization with granular permissions. Provides
|
|
6
|
+
* endpoints for managing role assignments on a per-user basis and
|
|
7
|
+
* resolving effective permissions.
|
|
8
|
+
*
|
|
9
|
+
* Route structure:
|
|
10
|
+
* GET / — List roles for a user
|
|
11
|
+
* PUT / — Assign roles to a user
|
|
12
|
+
* DELETE / — Remove roles from a user
|
|
13
|
+
* GET /permissions — List resolved permissions for a user
|
|
14
|
+
*
|
|
15
|
+
* Error mapping:
|
|
16
|
+
* RoleNotFoundError → 404
|
|
17
|
+
* RbacValidationError → 400
|
|
18
|
+
* ZodError → 400 with validation details
|
|
19
|
+
*/
|
|
20
|
+
import Router from '@koa/router';
|
|
21
|
+
/**
|
|
22
|
+
* Create the user-role assignment router.
|
|
23
|
+
*
|
|
24
|
+
* All routes require admin authorization with granular permissions.
|
|
25
|
+
* User-role assignments are scoped to a user within an organization
|
|
26
|
+
* via :orgId and :userId URL parameters.
|
|
27
|
+
*
|
|
28
|
+
* Prefix: /api/admin/organizations/:orgId/users/:userId/roles
|
|
29
|
+
*
|
|
30
|
+
* @returns Configured Koa Router
|
|
31
|
+
*/
|
|
32
|
+
export declare function createUserRoleRouter(): Router;
|
|
33
|
+
//# sourceMappingURL=user-roles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-roles.d.ts","sourceRoot":"","sources":["../../src/routes/user-roles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,MAAM,MAAM,aAAa,CAAC;AAiDjC;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CA+E7C"}
|