@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,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redis-based sliding window rate limiter.
|
|
3
|
+
*
|
|
4
|
+
* Uses INCR + EXPIRE for atomic counter management. Each action type
|
|
5
|
+
* (login, magic link, password reset) has its own key format and
|
|
6
|
+
* configurable limits loaded from system_config with sensible defaults.
|
|
7
|
+
*
|
|
8
|
+
* Graceful degradation: if Redis is unavailable, requests are ALLOWED
|
|
9
|
+
* with a warning log — we never block legitimate users due to Redis failure.
|
|
10
|
+
*
|
|
11
|
+
* Key format: ratelimit:{action}:{org_id}:{identifier_hash}
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const key = buildLoginRateLimitKey(orgId, ip, email);
|
|
15
|
+
* const config = await loadLoginRateLimitConfig();
|
|
16
|
+
* const result = await checkRateLimit(key, config);
|
|
17
|
+
* if (!result.allowed) {
|
|
18
|
+
* ctx.status = 429;
|
|
19
|
+
* ctx.set('Retry-After', String(result.retryAfter));
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
import crypto from 'node:crypto';
|
|
23
|
+
import { getRedis } from '../lib/redis.js';
|
|
24
|
+
import { getSystemConfigNumber } from '../lib/system-config.js';
|
|
25
|
+
import { logger } from '../lib/logger.js';
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Rate limit check
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
/**
|
|
30
|
+
* Check if a request is within the rate limit for the given key.
|
|
31
|
+
*
|
|
32
|
+
* Uses Redis INCR + conditional EXPIRE for atomic counter management:
|
|
33
|
+
* 1. INCR the key (creates it at 1 if new)
|
|
34
|
+
* 2. If TTL is -1 (no expiry), set EXPIRE to windowSeconds
|
|
35
|
+
* 3. Compare count against max — reject if exceeded
|
|
36
|
+
*
|
|
37
|
+
* On Redis failure, returns allowed: true with a warning log.
|
|
38
|
+
*
|
|
39
|
+
* @param key - Rate limit key (use a build*Key function to construct)
|
|
40
|
+
* @param config - Rate limit configuration (max requests + window)
|
|
41
|
+
* @returns Rate limit result with allowed status and metadata
|
|
42
|
+
*/
|
|
43
|
+
export async function checkRateLimit(key, config) {
|
|
44
|
+
try {
|
|
45
|
+
return await executeRateLimit(key, config);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
// Graceful degradation: allow request on Redis failure
|
|
49
|
+
logger.warn({ error, key }, 'Rate limiter Redis error — allowing request');
|
|
50
|
+
return {
|
|
51
|
+
allowed: true,
|
|
52
|
+
remaining: config.max,
|
|
53
|
+
resetAt: new Date(Date.now() + config.windowSeconds * 1000),
|
|
54
|
+
retryAfter: 0,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Check a security-critical limit without allowing Redis failure to bypass the boundary.
|
|
60
|
+
*
|
|
61
|
+
* @param key - Privacy-safe, domain-separated Redis key.
|
|
62
|
+
* @param config - Maximum attempts and fixed window.
|
|
63
|
+
* @returns Current limit decision.
|
|
64
|
+
* @throws When Redis cannot durably increment and expire the attempt counter.
|
|
65
|
+
*/
|
|
66
|
+
export async function checkRateLimitStrict(key, config) {
|
|
67
|
+
return executeRateLimit(key, config);
|
|
68
|
+
}
|
|
69
|
+
/** Execute the shared Redis counter algorithm without selecting a failure policy. */
|
|
70
|
+
async function executeRateLimit(key, config) {
|
|
71
|
+
const redis = getRedis();
|
|
72
|
+
const count = await redis.incr(key);
|
|
73
|
+
if (count === 1)
|
|
74
|
+
await redis.expire(key, config.windowSeconds);
|
|
75
|
+
const ttl = await redis.ttl(key);
|
|
76
|
+
if (ttl === -1)
|
|
77
|
+
await redis.expire(key, config.windowSeconds);
|
|
78
|
+
const effectiveTtl = ttl > 0 ? ttl : config.windowSeconds;
|
|
79
|
+
const resetAt = new Date(Date.now() + effectiveTtl * 1_000);
|
|
80
|
+
return count > config.max
|
|
81
|
+
? { allowed: false, remaining: 0, resetAt, retryAfter: effectiveTtl }
|
|
82
|
+
: { allowed: true, remaining: config.max - count, resetAt, retryAfter: 0 };
|
|
83
|
+
}
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
// Rate limit reset
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
/**
|
|
88
|
+
* Reset the rate limit counter for a key.
|
|
89
|
+
*
|
|
90
|
+
* Called after successful authentication to clear the counter,
|
|
91
|
+
* allowing the user to make fresh attempts if they log out and back in.
|
|
92
|
+
*
|
|
93
|
+
* @param key - Rate limit key to reset
|
|
94
|
+
*/
|
|
95
|
+
export async function resetRateLimit(key) {
|
|
96
|
+
try {
|
|
97
|
+
const redis = getRedis();
|
|
98
|
+
await redis.del(key);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
// Non-critical — log and continue
|
|
102
|
+
logger.warn({ error, key }, 'Failed to reset rate limit counter');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// Key builders
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
/**
|
|
109
|
+
* Hash an identifier for use in rate limit keys.
|
|
110
|
+
* Uses SHA-256 to normalize variable-length inputs into fixed-length keys
|
|
111
|
+
* and prevent PII from appearing in Redis key names.
|
|
112
|
+
*
|
|
113
|
+
* @param value - The raw identifier to hash
|
|
114
|
+
* @returns First 16 hex chars of SHA-256 (64-bit — enough for key uniqueness)
|
|
115
|
+
*/
|
|
116
|
+
function hashIdentifier(value) {
|
|
117
|
+
return crypto.createHash('sha256').update(value).digest('hex').slice(0, 16);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Build a rate limit key for login attempts.
|
|
121
|
+
* Combines IP + email to rate-limit per user per source IP.
|
|
122
|
+
*
|
|
123
|
+
* Format: ratelimit:login:{org_id}:{sha256(ip + email)[:16]}
|
|
124
|
+
*
|
|
125
|
+
* @param orgId - Organization UUID
|
|
126
|
+
* @param ip - Client IP address
|
|
127
|
+
* @param email - Email address being attempted
|
|
128
|
+
* @returns Rate limit key string
|
|
129
|
+
*/
|
|
130
|
+
export function buildLoginRateLimitKey(orgId, ip, email) {
|
|
131
|
+
return `ratelimit:login:${orgId}:${hashIdentifier(ip + email)}`;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Build a rate limit key for magic link requests.
|
|
135
|
+
* Rate-limits per email to prevent spam.
|
|
136
|
+
*
|
|
137
|
+
* Format: ratelimit:magic:{org_id}:{sha256(email)[:16]}
|
|
138
|
+
*
|
|
139
|
+
* @param orgId - Organization UUID
|
|
140
|
+
* @param email - Email address requesting magic link
|
|
141
|
+
* @returns Rate limit key string
|
|
142
|
+
*/
|
|
143
|
+
export function buildMagicLinkRateLimitKey(orgId, email) {
|
|
144
|
+
return `ratelimit:magic:${orgId}:${hashIdentifier(email)}`;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Build the callback-attempt key from tenant, direct socket peer, and protected artifact digest.
|
|
148
|
+
*
|
|
149
|
+
* @param orgId - Route organization UUID.
|
|
150
|
+
* @param socketPeer - Direct TCP peer rather than a caller-controlled forwarding header.
|
|
151
|
+
* @param artifactDigest - Domain-separated keyed digest of the presented artifact.
|
|
152
|
+
* @returns Privacy-safe Redis key with isolated tenant, peer, and artifact budgets.
|
|
153
|
+
*/
|
|
154
|
+
export function buildMagicLinkCallbackRateLimitKey(orgId, socketPeer, artifactDigest) {
|
|
155
|
+
return `ratelimit:magic-callback:${orgId}:${hashIdentifier(socketPeer)}:${artifactDigest}`;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Build a rate limit key for password reset requests.
|
|
159
|
+
* Rate-limits per email to prevent abuse.
|
|
160
|
+
*
|
|
161
|
+
* Format: ratelimit:reset:{org_id}:{sha256(email)[:16]}
|
|
162
|
+
*
|
|
163
|
+
* @param orgId - Organization UUID
|
|
164
|
+
* @param email - Email address requesting password reset
|
|
165
|
+
* @returns Rate limit key string
|
|
166
|
+
*/
|
|
167
|
+
/**
|
|
168
|
+
* Build a generic rate limit key for custom actions (e.g., 2FA verification, OTP resend).
|
|
169
|
+
*
|
|
170
|
+
* @param action - Action identifier (e.g., '2fa_verify', '2fa_resend')
|
|
171
|
+
* @param orgId - Organization UUID
|
|
172
|
+
* @param identifier - User-specific identifier (e.g., userId)
|
|
173
|
+
* @returns Redis key string
|
|
174
|
+
*/
|
|
175
|
+
export function buildRateLimitKey(action, orgId, identifier) {
|
|
176
|
+
return `ratelimit:${action}:${orgId}:${hashIdentifier(identifier)}`;
|
|
177
|
+
}
|
|
178
|
+
export function buildPasswordResetRateLimitKey(orgId, email) {
|
|
179
|
+
return `ratelimit:reset:${orgId}:${hashIdentifier(email)}`;
|
|
180
|
+
}
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
// Config loaders
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
/**
|
|
185
|
+
* Load login rate limit configuration from system_config.
|
|
186
|
+
*
|
|
187
|
+
* @returns Rate limit config with max attempts and window duration
|
|
188
|
+
*/
|
|
189
|
+
export async function loadLoginRateLimitConfig() {
|
|
190
|
+
const [max, windowSeconds] = await Promise.all([
|
|
191
|
+
getSystemConfigNumber('rate_limit_login_max', 10),
|
|
192
|
+
getSystemConfigNumber('rate_limit_login_window', 900),
|
|
193
|
+
]);
|
|
194
|
+
return { max, windowSeconds };
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Load magic link rate limit configuration from system_config.
|
|
198
|
+
*
|
|
199
|
+
* @returns Rate limit config with max requests and window duration
|
|
200
|
+
*/
|
|
201
|
+
export async function loadMagicLinkRateLimitConfig() {
|
|
202
|
+
const [max, windowSeconds] = await Promise.all([
|
|
203
|
+
getSystemConfigNumber('rate_limit_magic_link_max', 5),
|
|
204
|
+
getSystemConfigNumber('rate_limit_magic_link_window', 900),
|
|
205
|
+
]);
|
|
206
|
+
return { max, windowSeconds };
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Load password reset rate limit configuration from system_config.
|
|
210
|
+
*
|
|
211
|
+
* @returns Rate limit config with max requests and window duration
|
|
212
|
+
*/
|
|
213
|
+
export async function loadPasswordResetRateLimitConfig() {
|
|
214
|
+
const [max, windowSeconds] = await Promise.all([
|
|
215
|
+
getSystemConfigNumber('rate_limit_password_reset_max', 5),
|
|
216
|
+
getSystemConfigNumber('rate_limit_password_reset_window', 900),
|
|
217
|
+
]);
|
|
218
|
+
return { max, windowSeconds };
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/auth/rate-limiter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Cryptographic protection for durable account-recovery work. */
|
|
2
|
+
import type { ProtectedRecoveryAddress, RecoveryJobType } from './recovery-job-repository.js';
|
|
3
|
+
/** Public authority fields used to identify one recovery operation. */
|
|
4
|
+
export interface RecoveryRequestAuthority {
|
|
5
|
+
/** Resolved tenant UUID. */
|
|
6
|
+
readonly organizationId: string;
|
|
7
|
+
/** Closed recovery operation. */
|
|
8
|
+
readonly jobType: RecoveryJobType;
|
|
9
|
+
/** OIDC interaction binding for magic links. */
|
|
10
|
+
readonly interactionUid: string | null;
|
|
11
|
+
}
|
|
12
|
+
/** Durable authority fields authenticated with every protected address. */
|
|
13
|
+
export interface RecoveryAddressAuthority extends RecoveryRequestAuthority {
|
|
14
|
+
/** Keyed request identity persisted beside the encrypted address. */
|
|
15
|
+
readonly idempotencyDigest: string;
|
|
16
|
+
}
|
|
17
|
+
/** Normalize and validate a public recovery email address. */
|
|
18
|
+
export declare function normalizeRecoveryAddress(address: string): string;
|
|
19
|
+
/** Encrypt a normalized recovery address with the active rotating cookie key. */
|
|
20
|
+
export declare function protectRecoveryAddress(address: string, authority: RecoveryAddressAuthority): ProtectedRecoveryAddress;
|
|
21
|
+
/** Decrypt and authenticate a protected recovery address using the retained key ring. */
|
|
22
|
+
export declare function revealRecoveryAddress(protectedAddress: ProtectedRecoveryAddress, authority: RecoveryAddressAuthority): string;
|
|
23
|
+
/** Derive a non-reversible idempotency digest for one admitted public action. */
|
|
24
|
+
export declare function recoveryIdempotencyDigest(authority: RecoveryRequestAuthority, actionNonce: string): string;
|
|
25
|
+
/** Derive the stable unpredictable plaintext token owned by one durable job. */
|
|
26
|
+
export declare function recoveryArtifactToken(jobId: string, jobType: RecoveryJobType, addressKeyId: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Derive a non-reversible callback identity without retaining the presented bearer artifact.
|
|
29
|
+
*
|
|
30
|
+
* @param artifact - Plaintext callback artifact held only for the current request.
|
|
31
|
+
* @returns A short keyed digest safe for an ephemeral rate-limit key.
|
|
32
|
+
*/
|
|
33
|
+
export declare function magicLinkCallbackArtifactDigest(artifact: string): string;
|
|
34
|
+
//# sourceMappingURL=recovery-crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-crypto.d.ts","sourceRoot":"","sources":["../../src/auth/recovery-crypto.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAYlE,OAAO,KAAK,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAS9F,uEAAuE;AACvE,MAAM,WAAW,wBAAwB;IACvC,4BAA4B;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,iCAAiC;IACjC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,gDAAgD;IAChD,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED,2EAA2E;AAC3E,MAAM,WAAW,wBAAyB,SAAQ,wBAAwB;IACxE,qEAAqE;IACrE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACpC;AAED,8DAA8D;AAC9D,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEhE;AAsBD,iFAAiF;AACjF,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,wBAAwB,GAClC,wBAAwB,CAkB1B;AAED,yFAAyF;AACzF,wBAAgB,qBAAqB,CACnC,gBAAgB,EAAE,wBAAwB,EAC1C,SAAS,EAAE,wBAAwB,GAClC,MAAM,CAqBR;AAED,iFAAiF;AACjF,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,wBAAwB,EACnC,WAAW,EAAE,MAAM,GAClB,MAAM,CAOR;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,eAAe,EACxB,YAAY,EAAE,MAAM,GACnB,MAAM,CAQR;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGxE"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/** Cryptographic protection for durable account-recovery work. */
|
|
2
|
+
import { createCipheriv, createDecipheriv, createHash, createHmac, hkdfSync, randomBytes, } from 'node:crypto';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { config } from '../config/index.js';
|
|
5
|
+
const ADDRESS_CONTEXT = 'porta/recovery-address/v1';
|
|
6
|
+
const IDEMPOTENCY_CONTEXT = 'porta/recovery-idempotency/v1';
|
|
7
|
+
const TOKEN_CONTEXT = 'porta/recovery-token/v1';
|
|
8
|
+
const CALLBACK_CONTEXT = 'porta/magic-link-callback/v1';
|
|
9
|
+
const ALGORITHM = 'aes-256-gcm';
|
|
10
|
+
const addressSchema = z.string().trim().toLowerCase().email().max(255);
|
|
11
|
+
/** Normalize and validate a public recovery email address. */
|
|
12
|
+
export function normalizeRecoveryAddress(address) {
|
|
13
|
+
return addressSchema.parse(address);
|
|
14
|
+
}
|
|
15
|
+
function deriveKey(secret, context) {
|
|
16
|
+
return Buffer.from(hkdfSync('sha256', Buffer.from(secret), Buffer.alloc(0), context, 32));
|
|
17
|
+
}
|
|
18
|
+
function keyId(key) {
|
|
19
|
+
return createHash('sha256').update(key).digest('base64url').slice(0, 22);
|
|
20
|
+
}
|
|
21
|
+
function aad(authority) {
|
|
22
|
+
return Buffer.from(JSON.stringify([
|
|
23
|
+
ADDRESS_CONTEXT,
|
|
24
|
+
authority.organizationId,
|
|
25
|
+
authority.jobType,
|
|
26
|
+
authority.interactionUid,
|
|
27
|
+
authority.idempotencyDigest,
|
|
28
|
+
]));
|
|
29
|
+
}
|
|
30
|
+
/** Encrypt a normalized recovery address with the active rotating cookie key. */
|
|
31
|
+
export function protectRecoveryAddress(address, authority) {
|
|
32
|
+
const normalized = normalizeRecoveryAddress(address);
|
|
33
|
+
const key = deriveKey(config.cookieKeys[0], ADDRESS_CONTEXT);
|
|
34
|
+
const iv = randomBytes(12);
|
|
35
|
+
const cipher = createCipheriv(ALGORITHM, key, iv);
|
|
36
|
+
cipher.setAAD(aad(authority));
|
|
37
|
+
const encoded = Buffer.from(normalized, 'utf8');
|
|
38
|
+
if (encoded.length > 510)
|
|
39
|
+
throw new Error('Normalized recovery address is too large');
|
|
40
|
+
const padded = randomBytes(512);
|
|
41
|
+
padded.writeUInt16BE(encoded.length, 0);
|
|
42
|
+
encoded.copy(padded, 2);
|
|
43
|
+
const ciphertext = Buffer.concat([cipher.update(padded), cipher.final()]);
|
|
44
|
+
return {
|
|
45
|
+
ciphertext: ciphertext.toString('base64url'),
|
|
46
|
+
iv: iv.toString('base64url'),
|
|
47
|
+
tag: cipher.getAuthTag().toString('base64url'),
|
|
48
|
+
keyId: keyId(key),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/** Decrypt and authenticate a protected recovery address using the retained key ring. */
|
|
52
|
+
export function revealRecoveryAddress(protectedAddress, authority) {
|
|
53
|
+
for (const secret of config.cookieKeys) {
|
|
54
|
+
const key = deriveKey(secret, ADDRESS_CONTEXT);
|
|
55
|
+
if (keyId(key) !== protectedAddress.keyId)
|
|
56
|
+
continue;
|
|
57
|
+
const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(protectedAddress.iv, 'base64url'));
|
|
58
|
+
decipher.setAAD(aad(authority));
|
|
59
|
+
decipher.setAuthTag(Buffer.from(protectedAddress.tag, 'base64url'));
|
|
60
|
+
const padded = Buffer.concat([
|
|
61
|
+
decipher.update(Buffer.from(protectedAddress.ciphertext, 'base64url')),
|
|
62
|
+
decipher.final(),
|
|
63
|
+
]);
|
|
64
|
+
if (padded.length !== 512)
|
|
65
|
+
throw new Error('Protected recovery address has invalid length');
|
|
66
|
+
const length = padded.readUInt16BE(0);
|
|
67
|
+
if (length > 510)
|
|
68
|
+
throw new Error('Protected recovery address has invalid content');
|
|
69
|
+
return normalizeRecoveryAddress(padded.subarray(2, 2 + length).toString('utf8'));
|
|
70
|
+
}
|
|
71
|
+
throw new Error('Protected recovery address key is unavailable');
|
|
72
|
+
}
|
|
73
|
+
/** Derive a non-reversible idempotency digest for one admitted public action. */
|
|
74
|
+
export function recoveryIdempotencyDigest(authority, actionNonce) {
|
|
75
|
+
const key = deriveKey(config.cookieKeys[0], IDEMPOTENCY_CONTEXT);
|
|
76
|
+
return createHmac('sha256', key)
|
|
77
|
+
.update(JSON.stringify([authority.organizationId, authority.jobType, authority.interactionUid]))
|
|
78
|
+
.update('\0')
|
|
79
|
+
.update(actionNonce)
|
|
80
|
+
.digest('hex');
|
|
81
|
+
}
|
|
82
|
+
/** Derive the stable unpredictable plaintext token owned by one durable job. */
|
|
83
|
+
export function recoveryArtifactToken(jobId, jobType, addressKeyId) {
|
|
84
|
+
const secret = config.cookieKeys.find((candidate) => {
|
|
85
|
+
const addressKey = deriveKey(candidate, ADDRESS_CONTEXT);
|
|
86
|
+
return keyId(addressKey) === addressKeyId;
|
|
87
|
+
});
|
|
88
|
+
if (!secret)
|
|
89
|
+
throw new Error('Recovery artifact key is unavailable');
|
|
90
|
+
const key = deriveKey(secret, TOKEN_CONTEXT);
|
|
91
|
+
return createHmac('sha256', key).update(jobType).update('\0').update(jobId).digest('base64url');
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Derive a non-reversible callback identity without retaining the presented bearer artifact.
|
|
95
|
+
*
|
|
96
|
+
* @param artifact - Plaintext callback artifact held only for the current request.
|
|
97
|
+
* @returns A short keyed digest safe for an ephemeral rate-limit key.
|
|
98
|
+
*/
|
|
99
|
+
export function magicLinkCallbackArtifactDigest(artifact) {
|
|
100
|
+
const key = deriveKey(config.cookieKeys[0], CALLBACK_CONTEXT);
|
|
101
|
+
return createHmac('sha256', key).update(artifact).digest('base64url').slice(0, 22);
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=recovery-crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-crypto.js","sourceRoot":"","sources":["../../src/auth/recovery-crypto.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Account-specific processing for durable recovery jobs. */
|
|
2
|
+
import type { ClaimedRecoveryJob } from './recovery-job-repository.js';
|
|
3
|
+
import { type RecoveryJobProcessingResult, type RecoveryJobProcessor } from './recovery-worker.js';
|
|
4
|
+
import type { InteractionAuthorityResolver } from './interaction-authority.js';
|
|
5
|
+
/** Concrete tenant-scoped processor for magic-link and password-reset work. */
|
|
6
|
+
export declare class AccountRecoveryJobProcessor implements RecoveryJobProcessor {
|
|
7
|
+
protected readonly interactionAuthority?: InteractionAuthorityResolver | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Create a processor with the provider-owned interaction boundary used by magic-link work.
|
|
10
|
+
*
|
|
11
|
+
* @param interactionAuthority - Live interaction resolver. Password-reset jobs do not use it.
|
|
12
|
+
*/
|
|
13
|
+
constructor(interactionAuthority?: InteractionAuthorityResolver | undefined);
|
|
14
|
+
/** Resolve eligibility, create one artifact, and deliver its stable link. */
|
|
15
|
+
process(job: ClaimedRecoveryJob): Promise<RecoveryJobProcessingResult>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create the production account-recovery processor.
|
|
19
|
+
*
|
|
20
|
+
* @param interactionAuthority - Live provider authority for interaction-bound magic links.
|
|
21
|
+
* @returns The account-independent processor used by the durable worker.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createAccountRecoveryJobProcessor(interactionAuthority?: InteractionAuthorityResolver): RecoveryJobProcessor;
|
|
24
|
+
//# sourceMappingURL=recovery-job-processor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-job-processor.d.ts","sourceRoot":"","sources":["../../src/auth/recovery-job-processor.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAW7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,EAEL,KAAK,2BAA2B,EAChC,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAE/E,+EAA+E;AAC/E,qBAAa,2BAA4B,YAAW,oBAAoB;IAMnD,SAAS,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,4BAA4B;IALzF;;;;OAIG;IACH,YAAsC,oBAAoB,CAAC,EAAE,4BAA4B,YAAA,EAAI;IAE7F,6EAA6E;IAChE,OAAO,CAAC,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAAC,2BAA2B,CAAC,CA4FlF;CACF;AAED;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAC/C,oBAAoB,CAAC,EAAE,4BAA4B,GAClD,oBAAoB,CAEtB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/** Account-specific processing for durable recovery jobs. */
|
|
2
|
+
import { config } from '../config/index.js';
|
|
3
|
+
import { writeAuditLog } from '../lib/audit-log.js';
|
|
4
|
+
import { getSystemConfigNumber } from '../lib/system-config.js';
|
|
5
|
+
import { getOrganizationById } from '../organizations/service.js';
|
|
6
|
+
import { getUserByEmail } from '../users/service.js';
|
|
7
|
+
import { sendRecoveryEmailStrict } from './email-service.js';
|
|
8
|
+
import { recoveryArtifactToken, revealRecoveryAddress } from './recovery-crypto.js';
|
|
9
|
+
import { ensureRecoveryJobToken } from './token-repository.js';
|
|
10
|
+
import { hashToken } from './tokens.js';
|
|
11
|
+
import { RecoveryJobProcessingError, } from './recovery-worker.js';
|
|
12
|
+
/** Concrete tenant-scoped processor for magic-link and password-reset work. */
|
|
13
|
+
export class AccountRecoveryJobProcessor {
|
|
14
|
+
interactionAuthority;
|
|
15
|
+
/**
|
|
16
|
+
* Create a processor with the provider-owned interaction boundary used by magic-link work.
|
|
17
|
+
*
|
|
18
|
+
* @param interactionAuthority - Live interaction resolver. Password-reset jobs do not use it.
|
|
19
|
+
*/
|
|
20
|
+
constructor(interactionAuthority) {
|
|
21
|
+
this.interactionAuthority = interactionAuthority;
|
|
22
|
+
}
|
|
23
|
+
/** Resolve eligibility, create one artifact, and deliver its stable link. */
|
|
24
|
+
async process(job) {
|
|
25
|
+
let address;
|
|
26
|
+
try {
|
|
27
|
+
address = revealRecoveryAddress(job.protectedAddress, {
|
|
28
|
+
organizationId: job.organizationId,
|
|
29
|
+
jobType: job.jobType,
|
|
30
|
+
interactionUid: job.interactionUid,
|
|
31
|
+
idempotencyDigest: job.idempotencyDigest,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
throw new RecoveryJobProcessingError('invalid_protected_input', false);
|
|
36
|
+
}
|
|
37
|
+
let organization;
|
|
38
|
+
let user;
|
|
39
|
+
try {
|
|
40
|
+
organization = await getOrganizationById(job.organizationId);
|
|
41
|
+
user = await getUserByEmail(job.organizationId, address);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
throw new RecoveryJobProcessingError('database_unavailable', true);
|
|
45
|
+
}
|
|
46
|
+
if (!organization || organization.status !== 'active' || !user || user.status !== 'active') {
|
|
47
|
+
return 'no_op';
|
|
48
|
+
}
|
|
49
|
+
let plaintext;
|
|
50
|
+
try {
|
|
51
|
+
plaintext = recoveryArtifactToken(job.id, job.jobType, job.protectedAddress.keyId);
|
|
52
|
+
const ttlSeconds = await getSystemConfigNumber(job.jobType === 'magic_link' ? 'magic_link_ttl' : 'password_reset_ttl', job.jobType === 'magic_link' ? 900 : 3_600);
|
|
53
|
+
const artifactInput = {
|
|
54
|
+
recoveryJobId: job.id,
|
|
55
|
+
userId: user.id,
|
|
56
|
+
tokenHash: hashToken(plaintext),
|
|
57
|
+
expiresAt: new Date(Date.now() + ttlSeconds * 1_000),
|
|
58
|
+
};
|
|
59
|
+
let artifact;
|
|
60
|
+
if (job.jobType === 'magic_link') {
|
|
61
|
+
const liveAuthority = job.interactionUid
|
|
62
|
+
? await this.interactionAuthority?.resolve(job.interactionUid)
|
|
63
|
+
: null;
|
|
64
|
+
if (job.interactionUid && !liveAuthority)
|
|
65
|
+
return 'no_op';
|
|
66
|
+
artifact = await ensureRecoveryJobToken({
|
|
67
|
+
...artifactInput,
|
|
68
|
+
table: 'magic_link_tokens',
|
|
69
|
+
organizationId: job.organizationId,
|
|
70
|
+
interactionUid: job.interactionUid,
|
|
71
|
+
clientId: liveAuthority?.clientId ?? null,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
artifact = await ensureRecoveryJobToken({
|
|
76
|
+
...artifactInput,
|
|
77
|
+
table: 'password_reset_tokens',
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (artifact === 'superseded')
|
|
81
|
+
return 'no_op';
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
throw new RecoveryJobProcessingError('database_unavailable', true);
|
|
85
|
+
}
|
|
86
|
+
const base = `${config.issuerBaseUrl}/${organization.slug}/auth`;
|
|
87
|
+
const recoveryUrl = job.jobType === 'magic_link'
|
|
88
|
+
? `${base}/magic-link/${plaintext}${job.interactionUid ? `?interaction=${encodeURIComponent(job.interactionUid)}` : ''}`
|
|
89
|
+
: `${base}/reset-password/${plaintext}`;
|
|
90
|
+
try {
|
|
91
|
+
await sendRecoveryEmailStrict({
|
|
92
|
+
type: job.jobType,
|
|
93
|
+
user,
|
|
94
|
+
organization,
|
|
95
|
+
recoveryUrl,
|
|
96
|
+
locale: user.locale ?? organization.defaultLocale,
|
|
97
|
+
messageId: `<recovery-${job.id}@porta.invalid>`,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
throw new RecoveryJobProcessingError('smtp_outcome_unknown', true);
|
|
102
|
+
}
|
|
103
|
+
void writeAuditLog({
|
|
104
|
+
organizationId: organization.id,
|
|
105
|
+
userId: user.id,
|
|
106
|
+
eventType: job.jobType === 'magic_link' ? 'user.magic_link.sent' : 'user.password_reset.requested',
|
|
107
|
+
eventCategory: 'authentication',
|
|
108
|
+
description: 'Recovery message accepted for delivery',
|
|
109
|
+
metadata: { recoveryType: job.jobType },
|
|
110
|
+
});
|
|
111
|
+
return 'completed';
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Create the production account-recovery processor.
|
|
116
|
+
*
|
|
117
|
+
* @param interactionAuthority - Live provider authority for interaction-bound magic links.
|
|
118
|
+
* @returns The account-independent processor used by the durable worker.
|
|
119
|
+
*/
|
|
120
|
+
export function createAccountRecoveryJobProcessor(interactionAuthority) {
|
|
121
|
+
return new AccountRecoveryJobProcessor(interactionAuthority);
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=recovery-job-processor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-job-processor.js","sourceRoot":"","sources":["../../src/auth/recovery-job-processor.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAEpF,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EACL,0BAA0B,GAG3B,MAAM,sBAAsB,CAAC;AAG9B,+EAA+E;AAC/E,MAAM,OAAO,2BAA2B;IAMA,oBAAoB;IAL1D;;;;OAIG;IACH,YAAsC,oBAAmD;oCAAnD,oBAAoB;IAAkC,CAAC;IAE7F,6EAA6E;IACtE,KAAK,CAAC,OAAO,CAAC,GAAuB;QAC1C,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,qBAAqB,CAAC,GAAG,CAAC,gBAAgB,EAAE;gBACpD,cAAc,EAAE,GAAG,CAAC,cAAc;gBAClC,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,cAAc,EAAE,GAAG,CAAC,cAAc;gBAClC,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;aACzC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,0BAA0B,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;QACzE,CAAC;QAED,IAAI,YAAiC,CAAC;QACtC,IAAI,IAAiB,CAAC;QACtB,IAAI,CAAC;YACH,YAAY,GAAG,MAAM,mBAAmB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAC7D,IAAI,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;QAC3D,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,0BAA0B,CAAC,sBAAsB,EAAE,IAAI,CAAC,CAAC;QACrE,CAAC;QACD,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC3F,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,IAAI,SAAiB,CAAC;QACtB,IAAI,CAAC;YACH,SAAS,GAAG,qBAAqB,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;YACnF,MAAM,UAAU,GAAG,MAAM,qBAAqB,CAC5C,GAAG,CAAC,OAAO,KAAK,YAAY,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,oBAAoB,EACtE,GAAG,CAAC,OAAO,KAAK,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAC3C,CAAC;YACF,MAAM,aAAa,GAAG;gBACpB,aAAa,EAAE,GAAG,CAAC,EAAE;gBACrB,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC;gBAC/B,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,KAAK,CAAC;aACrD,CAAC;YACF,IAAI,QAAQ,CAAC;YACb,IAAI,GAAG,CAAC,OAAO,KAAK,YAAY,EAAE,CAAC;gBACjC,MAAM,aAAa,GAAG,GAAG,CAAC,cAAc;oBACtC,CAAC,CAAC,MAAM,IAAI,CAAC,oBAAoB,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;oBAC9D,CAAC,CAAC,IAAI,CAAC;gBACT,IAAI,GAAG,CAAC,cAAc,IAAI,CAAC,aAAa;oBAAE,OAAO,OAAO,CAAC;gBACzD,QAAQ,GAAG,MAAM,sBAAsB,CAAC;oBACtC,GAAG,aAAa;oBAChB,KAAK,EAAE,mBAAmB;oBAC1B,cAAc,EAAE,GAAG,CAAC,cAAc;oBAClC,cAAc,EAAE,GAAG,CAAC,cAAc;oBAClC,QAAQ,EAAE,aAAa,EAAE,QAAQ,IAAI,IAAI;iBAC1C,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,QAAQ,GAAG,MAAM,sBAAsB,CAAC;oBACtC,GAAG,aAAa;oBAChB,KAAK,EAAE,uBAAuB;iBAC/B,CAAC,CAAC;YACL,CAAC;YACD,IAAI,QAAQ,KAAK,YAAY;gBAAE,OAAO,OAAO,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,0BAA0B,CAAC,sBAAsB,EAAE,IAAI,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,aAAa,IAAI,YAAY,CAAC,IAAI,OAAO,CAAC;QACjE,MAAM,WAAW,GACf,GAAG,CAAC,OAAO,KAAK,YAAY;YAC1B,CAAC,CAAC,GAAG,IAAI,eAAe,SAAS,GAC7B,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,gBAAgB,kBAAkB,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,EAClF,EAAE;YACJ,CAAC,CAAC,GAAG,IAAI,mBAAmB,SAAS,EAAE,CAAC;QAC5C,IAAI,CAAC;YACH,MAAM,uBAAuB,CAAC;gBAC5B,IAAI,EAAE,GAAG,CAAC,OAAO;gBACjB,IAAI;gBACJ,YAAY;gBACZ,WAAW;gBACX,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,YAAY,CAAC,aAAa;gBACjD,SAAS,EAAE,aAAa,GAAG,CAAC,EAAE,iBAAiB;aAChD,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,0BAA0B,CAAC,sBAAsB,EAAE,IAAI,CAAC,CAAC;QACrE,CAAC;QAED,KAAK,aAAa,CAAC;YACjB,cAAc,EAAE,YAAY,CAAC,EAAE;YAC/B,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,SAAS,EACP,GAAG,CAAC,OAAO,KAAK,YAAY,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,+BAA+B;YACzF,aAAa,EAAE,gBAAgB;YAC/B,WAAW,EAAE,wCAAwC;YACrD,QAAQ,EAAE,EAAE,YAAY,EAAE,GAAG,CAAC,OAAO,EAAE;SACxC,CAAC,CAAC;QACH,OAAO,WAAW,CAAC;IACrB,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,UAAU,iCAAiC,CAC/C,oBAAmD;IAEnD,OAAO,IAAI,2BAA2B,CAAC,oBAAoB,CAAC,CAAC;AAC/D,CAAC"}
|