@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,39 @@
|
|
|
1
|
+
/** Live OIDC interaction authority used by delayed recovery work and public callbacks. */
|
|
2
|
+
/** Minimal interaction record returned by the provider-owned model. */
|
|
3
|
+
export interface ProviderInteractionRecord {
|
|
4
|
+
/** Exact public interaction identifier. */
|
|
5
|
+
readonly uid: string;
|
|
6
|
+
/** Protocol parameters persisted by the provider. */
|
|
7
|
+
readonly params: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
/** Minimal provider model needed to resolve current interaction authority. */
|
|
10
|
+
export interface InteractionAuthorityProvider {
|
|
11
|
+
/** Provider-owned short-lived interaction model. */
|
|
12
|
+
readonly Interaction: {
|
|
13
|
+
/** Find one unexpired interaction by its exact identifier. */
|
|
14
|
+
find(uid: string): Promise<ProviderInteractionRecord | undefined>;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** Validated live interaction and client identity. */
|
|
18
|
+
export interface LiveInteractionAuthority {
|
|
19
|
+
/** Exact identifier resolved by the provider. */
|
|
20
|
+
readonly interactionUid: string;
|
|
21
|
+
/** Current client identifier persisted in the interaction parameters. */
|
|
22
|
+
readonly clientId: string;
|
|
23
|
+
}
|
|
24
|
+
/** Resolver shared by artifact issuance and callback verification. */
|
|
25
|
+
export interface InteractionAuthorityResolver {
|
|
26
|
+
/** Resolve one exact unexpired interaction without trusting transport metadata. */
|
|
27
|
+
resolve(interactionUid: string): Promise<LiveInteractionAuthority | null>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build a fail-closed resolver over the provider's own interaction model.
|
|
31
|
+
*
|
|
32
|
+
* The resolver validates both the requested identifier and the identifier returned by storage.
|
|
33
|
+
* This prevents malformed or stale transport input from being treated as durable authority.
|
|
34
|
+
*
|
|
35
|
+
* @param provider - Provider model which owns interaction lifetime and parameters.
|
|
36
|
+
* @returns Resolver suitable for both delayed recovery work and public callbacks.
|
|
37
|
+
*/
|
|
38
|
+
export declare function createInteractionAuthorityResolver(provider: InteractionAuthorityProvider): InteractionAuthorityResolver;
|
|
39
|
+
//# sourceMappingURL=interaction-authority.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interaction-authority.d.ts","sourceRoot":"","sources":["../../src/auth/interaction-authority.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAO1F,uEAAuE;AACvE,MAAM,WAAW,yBAAyB;IACxC,2CAA2C;IAC3C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C;AAED,8EAA8E;AAC9E,MAAM,WAAW,4BAA4B;IAC3C,oDAAoD;IACpD,QAAQ,CAAC,WAAW,EAAE;QACpB,8DAA8D;QAC9D,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,GAAG,SAAS,CAAC,CAAC;KACnE,CAAC;CACH;AAED,sDAAsD;AACtD,MAAM,WAAW,wBAAwB;IACvC,iDAAiD;IACjD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,sEAAsE;AACtE,MAAM,WAAW,4BAA4B;IAC3C,mFAAmF;IACnF,OAAO,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAAC;CAC3E;AAED;;;;;;;;GAQG;AACH,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,4BAA4B,GACrC,4BAA4B,CAY9B"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Live OIDC interaction authority used by delayed recovery work and public callbacks. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
const interactionUidSchema = z.string().min(1).max(128);
|
|
4
|
+
const clientIdSchema = z.string().min(1).max(255);
|
|
5
|
+
/**
|
|
6
|
+
* Build a fail-closed resolver over the provider's own interaction model.
|
|
7
|
+
*
|
|
8
|
+
* The resolver validates both the requested identifier and the identifier returned by storage.
|
|
9
|
+
* This prevents malformed or stale transport input from being treated as durable authority.
|
|
10
|
+
*
|
|
11
|
+
* @param provider - Provider model which owns interaction lifetime and parameters.
|
|
12
|
+
* @returns Resolver suitable for both delayed recovery work and public callbacks.
|
|
13
|
+
*/
|
|
14
|
+
export function createInteractionAuthorityResolver(provider) {
|
|
15
|
+
return {
|
|
16
|
+
async resolve(interactionUid) {
|
|
17
|
+
const parsedUid = interactionUidSchema.safeParse(interactionUid);
|
|
18
|
+
if (!parsedUid.success)
|
|
19
|
+
return null;
|
|
20
|
+
const interaction = await provider.Interaction.find(parsedUid.data);
|
|
21
|
+
if (!interaction || interaction.uid !== parsedUid.data)
|
|
22
|
+
return null;
|
|
23
|
+
const clientId = clientIdSchema.safeParse(interaction.params.client_id);
|
|
24
|
+
if (!clientId.success)
|
|
25
|
+
return null;
|
|
26
|
+
return { interactionUid: parsedUid.data, clientId: clientId.data };
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=interaction-authority.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interaction-authority.js","sourceRoot":"","sources":["../../src/auth/interaction-authority.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAE1F,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACxD,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAiClD;;;;;;;;GAQG;AACH,MAAM,UAAU,kCAAkC,CAChD,QAAsC;IAEtC,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,cAAc;YAC1B,MAAM,SAAS,GAAG,oBAAoB,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;YACjE,IAAI,CAAC,SAAS,CAAC,OAAO;gBAAE,OAAO,IAAI,CAAC;YACpC,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACpE,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,GAAG,KAAK,SAAS,CAAC,IAAI;gBAAE,OAAO,IAAI,CAAC;YACpE,MAAM,QAAQ,GAAG,cAAc,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACxE,IAAI,CAAC,QAAQ,CAAC,OAAO;gBAAE,OAAO,IAAI,CAAC;YACnC,OAAO,EAAE,cAAc,EAAE,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;QACrE,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Magic link session management — cookie + Redis backing store.
|
|
3
|
+
*
|
|
4
|
+
* When a magic link is clicked, the handler creates a `_ml_session` cookie
|
|
5
|
+
* backed by a Redis key containing the authenticated user's ID, the OIDC
|
|
6
|
+
* interaction UID, and the organization ID. The user is then redirected to
|
|
7
|
+
* `/interaction/:uid` where `showLogin()` detects the session cookie and
|
|
8
|
+
* either:
|
|
9
|
+
* - **Same browser**: completes the OIDC flow via `interactionFinished()`
|
|
10
|
+
* - **Different browser**: shows a "return to original browser" success page
|
|
11
|
+
*
|
|
12
|
+
* Properties:
|
|
13
|
+
* - **Opaque tokens** — random 32-byte hex strings, no data to decode/forge
|
|
14
|
+
* - **Single-use** — Redis keys deleted after first consumption
|
|
15
|
+
* - **Short-lived** — 5-minute TTL in Redis
|
|
16
|
+
* - **HttpOnly cookies** — prevents JavaScript access (XSS-safe)
|
|
17
|
+
* - **SameSite=Lax** — blocks cross-site POST but allows navigational GET
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // In magic link handler (after token validation):
|
|
21
|
+
* await createMagicLinkSession(ctx, { userId, interactionUid, organizationId });
|
|
22
|
+
* ctx.redirect(`/interaction/${interactionUid}`);
|
|
23
|
+
*
|
|
24
|
+
* // In login handler (detecting session):
|
|
25
|
+
* const session = await consumeMagicLinkSession(ctx, { organizationId, interactionUid });
|
|
26
|
+
* if (session) { interactionFinished(ctx, { login: { accountId: session.userId } }); }
|
|
27
|
+
*/
|
|
28
|
+
import type { Context } from 'koa';
|
|
29
|
+
/** Data stored in a magic link session */
|
|
30
|
+
export interface MagicLinkSessionData {
|
|
31
|
+
/** Authenticated user ID */
|
|
32
|
+
userId: string;
|
|
33
|
+
/** OIDC interaction UID (for flow completion) */
|
|
34
|
+
interactionUid: string;
|
|
35
|
+
/** Organization ID (for branding on success page) */
|
|
36
|
+
organizationId: string;
|
|
37
|
+
}
|
|
38
|
+
/** Independently derived authority required to consume one continuation. */
|
|
39
|
+
export interface MagicLinkSessionAuthority {
|
|
40
|
+
/** Organization recorded by the validated OIDC interaction. */
|
|
41
|
+
readonly organizationId: string;
|
|
42
|
+
/** Exact interaction identifier selected by the public route. */
|
|
43
|
+
readonly interactionUid: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create a magic link session in Redis and set the `_ml_session` cookie.
|
|
47
|
+
*
|
|
48
|
+
* Generates a random session token, stores session data in Redis with a
|
|
49
|
+
* 5-minute TTL, and sets the token as an HttpOnly cookie.
|
|
50
|
+
*
|
|
51
|
+
* @param ctx - Koa context (for cookie setting)
|
|
52
|
+
* @param data - Session data to store (userId, interactionUid, organizationId)
|
|
53
|
+
*/
|
|
54
|
+
export declare function createMagicLinkSession(ctx: Context, data: MagicLinkSessionData): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Consume a magic link session — read and delete in one atomic operation.
|
|
57
|
+
*
|
|
58
|
+
* Reads the `_ml_session` cookie and asks Redis to compare the stored tenant and interaction before
|
|
59
|
+
* deleting the key. The Lua operation makes the compare-and-delete decision single-use under
|
|
60
|
+
* concurrency. A mismatch preserves both the Redis value and cookie for one legitimate retry.
|
|
61
|
+
*
|
|
62
|
+
* @param ctx - Koa context (for cookie reading/clearing)
|
|
63
|
+
* @param authority - Tenant and interaction independently derived from the live OIDC interaction.
|
|
64
|
+
* @returns Session data if valid, null otherwise
|
|
65
|
+
*/
|
|
66
|
+
export declare function consumeMagicLinkSession(ctx: Context, authority: MagicLinkSessionAuthority): Promise<MagicLinkSessionData | null>;
|
|
67
|
+
/**
|
|
68
|
+
* Check if a magic link session cookie is present (without consuming it).
|
|
69
|
+
* Use this for quick checks before committing to the session flow.
|
|
70
|
+
*
|
|
71
|
+
* @param ctx - Koa context
|
|
72
|
+
* @returns true if the `_ml_session` cookie exists
|
|
73
|
+
*/
|
|
74
|
+
export declare function hasMagicLinkSession(ctx: Context): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Clear the magic link session cookie.
|
|
77
|
+
*
|
|
78
|
+
* @param ctx - Koa context
|
|
79
|
+
*/
|
|
80
|
+
export declare function clearMagicLinkSessionCookie(ctx: Context): void;
|
|
81
|
+
//# sourceMappingURL=magic-link-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"magic-link-session.d.ts","sourceRoot":"","sources":["../../src/auth/magic-link-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAuDnC,0CAA0C;AAC1C,MAAM,WAAW,oBAAoB;IACnC,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,cAAc,EAAE,MAAM,CAAC;IACvB,qDAAqD;IACrD,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,4EAA4E;AAC5E,MAAM,WAAW,yBAAyB;IACxC,+DAA+D;IAC/D,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,iEAAiE;IACjE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAMD;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,IAAI,CAAC,CAmBf;AAMD;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,yBAAyB,GACnC,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAgDtC;AAMD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAQ9D"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Magic link session management — cookie + Redis backing store.
|
|
3
|
+
*
|
|
4
|
+
* When a magic link is clicked, the handler creates a `_ml_session` cookie
|
|
5
|
+
* backed by a Redis key containing the authenticated user's ID, the OIDC
|
|
6
|
+
* interaction UID, and the organization ID. The user is then redirected to
|
|
7
|
+
* `/interaction/:uid` where `showLogin()` detects the session cookie and
|
|
8
|
+
* either:
|
|
9
|
+
* - **Same browser**: completes the OIDC flow via `interactionFinished()`
|
|
10
|
+
* - **Different browser**: shows a "return to original browser" success page
|
|
11
|
+
*
|
|
12
|
+
* Properties:
|
|
13
|
+
* - **Opaque tokens** — random 32-byte hex strings, no data to decode/forge
|
|
14
|
+
* - **Single-use** — Redis keys deleted after first consumption
|
|
15
|
+
* - **Short-lived** — 5-minute TTL in Redis
|
|
16
|
+
* - **HttpOnly cookies** — prevents JavaScript access (XSS-safe)
|
|
17
|
+
* - **SameSite=Lax** — blocks cross-site POST but allows navigational GET
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // In magic link handler (after token validation):
|
|
21
|
+
* await createMagicLinkSession(ctx, { userId, interactionUid, organizationId });
|
|
22
|
+
* ctx.redirect(`/interaction/${interactionUid}`);
|
|
23
|
+
*
|
|
24
|
+
* // In login handler (detecting session):
|
|
25
|
+
* const session = await consumeMagicLinkSession(ctx, { organizationId, interactionUid });
|
|
26
|
+
* if (session) { interactionFinished(ctx, { login: { accountId: session.userId } }); }
|
|
27
|
+
*/
|
|
28
|
+
import crypto from 'node:crypto';
|
|
29
|
+
import { getRedis } from '../lib/redis.js';
|
|
30
|
+
import { logger } from '../lib/logger.js';
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Constants
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
/** Cookie name for magic link session token */
|
|
35
|
+
const ML_SESSION_COOKIE = '_ml_session';
|
|
36
|
+
/** Redis key prefix for magic link sessions */
|
|
37
|
+
const ML_SESSION_PREFIX = 'ml_session:';
|
|
38
|
+
/** Session TTL in seconds (5 minutes) */
|
|
39
|
+
const ML_SESSION_TTL = 300;
|
|
40
|
+
/** Session token length in bytes (32 bytes = 64 hex chars) */
|
|
41
|
+
const SESSION_TOKEN_BYTES = 32;
|
|
42
|
+
/**
|
|
43
|
+
* Atomically compare continuation authority and consume exactly one matching Redis value.
|
|
44
|
+
*
|
|
45
|
+
* Mismatches deliberately preserve the key so the legitimate tenant and interaction can retry.
|
|
46
|
+
* Invalid stored data is not returned and remains bounded by the original five-minute TTL.
|
|
47
|
+
*/
|
|
48
|
+
const CONSUME_MATCHING_SESSION_SCRIPT = `
|
|
49
|
+
local raw = redis.call('GET', KEYS[1])
|
|
50
|
+
if not raw then
|
|
51
|
+
return -2
|
|
52
|
+
end
|
|
53
|
+
local interactionOrganizationId = redis.call('GET', KEYS[2])
|
|
54
|
+
if not interactionOrganizationId or interactionOrganizationId ~= ARGV[1] then
|
|
55
|
+
return 0
|
|
56
|
+
end
|
|
57
|
+
local decoded, session = pcall(cjson.decode, raw)
|
|
58
|
+
if not decoded or type(session) ~= 'table' then
|
|
59
|
+
return -1
|
|
60
|
+
end
|
|
61
|
+
if type(session.userId) ~= 'string' or session.userId == '' or
|
|
62
|
+
type(session.interactionUid) ~= 'string' or session.interactionUid == '' or
|
|
63
|
+
type(session.organizationId) ~= 'string' or session.organizationId == '' then
|
|
64
|
+
return -1
|
|
65
|
+
end
|
|
66
|
+
if session.organizationId ~= ARGV[1] or session.interactionUid ~= ARGV[2] then
|
|
67
|
+
return 0
|
|
68
|
+
end
|
|
69
|
+
redis.call('DEL', KEYS[1])
|
|
70
|
+
return raw
|
|
71
|
+
`;
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Creation
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
/**
|
|
76
|
+
* Create a magic link session in Redis and set the `_ml_session` cookie.
|
|
77
|
+
*
|
|
78
|
+
* Generates a random session token, stores session data in Redis with a
|
|
79
|
+
* 5-minute TTL, and sets the token as an HttpOnly cookie.
|
|
80
|
+
*
|
|
81
|
+
* @param ctx - Koa context (for cookie setting)
|
|
82
|
+
* @param data - Session data to store (userId, interactionUid, organizationId)
|
|
83
|
+
*/
|
|
84
|
+
export async function createMagicLinkSession(ctx, data) {
|
|
85
|
+
const redis = getRedis();
|
|
86
|
+
const token = crypto.randomBytes(SESSION_TOKEN_BYTES).toString('hex');
|
|
87
|
+
const key = `${ML_SESSION_PREFIX}${token}`;
|
|
88
|
+
// Store session data in Redis with TTL
|
|
89
|
+
await redis.set(key, JSON.stringify(data), 'EX', ML_SESSION_TTL);
|
|
90
|
+
// Set the cookie — HttpOnly, SameSite=Lax, path=/
|
|
91
|
+
ctx.cookies.set(ML_SESSION_COOKIE, token, {
|
|
92
|
+
httpOnly: true,
|
|
93
|
+
sameSite: 'lax',
|
|
94
|
+
path: '/',
|
|
95
|
+
secure: ctx.secure,
|
|
96
|
+
maxAge: ML_SESSION_TTL * 1000, // milliseconds
|
|
97
|
+
overwrite: true,
|
|
98
|
+
});
|
|
99
|
+
logger.debug('Created tenant-bound magic link session');
|
|
100
|
+
}
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
// Consumption
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
/**
|
|
105
|
+
* Consume a magic link session — read and delete in one atomic operation.
|
|
106
|
+
*
|
|
107
|
+
* Reads the `_ml_session` cookie and asks Redis to compare the stored tenant and interaction before
|
|
108
|
+
* deleting the key. The Lua operation makes the compare-and-delete decision single-use under
|
|
109
|
+
* concurrency. A mismatch preserves both the Redis value and cookie for one legitimate retry.
|
|
110
|
+
*
|
|
111
|
+
* @param ctx - Koa context (for cookie reading/clearing)
|
|
112
|
+
* @param authority - Tenant and interaction independently derived from the live OIDC interaction.
|
|
113
|
+
* @returns Session data if valid, null otherwise
|
|
114
|
+
*/
|
|
115
|
+
export async function consumeMagicLinkSession(ctx, authority) {
|
|
116
|
+
const token = ctx.cookies.get(ML_SESSION_COOKIE);
|
|
117
|
+
if (!token)
|
|
118
|
+
return null;
|
|
119
|
+
if (!authority.organizationId || !authority.interactionUid)
|
|
120
|
+
return null;
|
|
121
|
+
const redis = getRedis();
|
|
122
|
+
const key = `${ML_SESSION_PREFIX}${token}`;
|
|
123
|
+
const interactionAuthorityKey = `interaction:org:${authority.interactionUid}`;
|
|
124
|
+
const result = await redis.eval(CONSUME_MATCHING_SESSION_SCRIPT, 2, key, interactionAuthorityKey, authority.organizationId, authority.interactionUid);
|
|
125
|
+
if (result === 0)
|
|
126
|
+
return null;
|
|
127
|
+
if (typeof result !== 'string') {
|
|
128
|
+
clearMagicLinkSessionCookie(ctx);
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
clearMagicLinkSessionCookie(ctx);
|
|
132
|
+
try {
|
|
133
|
+
const parsed = JSON.parse(result);
|
|
134
|
+
if (typeof parsed !== 'object' ||
|
|
135
|
+
parsed === null ||
|
|
136
|
+
Array.isArray(parsed) ||
|
|
137
|
+
typeof Reflect.get(parsed, 'userId') !== 'string' ||
|
|
138
|
+
typeof Reflect.get(parsed, 'interactionUid') !== 'string' ||
|
|
139
|
+
typeof Reflect.get(parsed, 'organizationId') !== 'string') {
|
|
140
|
+
logger.warn('Invalid magic link session data');
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
const data = {
|
|
144
|
+
userId: Reflect.get(parsed, 'userId'),
|
|
145
|
+
interactionUid: Reflect.get(parsed, 'interactionUid'),
|
|
146
|
+
organizationId: Reflect.get(parsed, 'organizationId'),
|
|
147
|
+
};
|
|
148
|
+
logger.debug('Consumed tenant-bound magic link session');
|
|
149
|
+
return data;
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
logger.warn('Failed to parse magic link session data');
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
// Cookie Helpers
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
/**
|
|
160
|
+
* Check if a magic link session cookie is present (without consuming it).
|
|
161
|
+
* Use this for quick checks before committing to the session flow.
|
|
162
|
+
*
|
|
163
|
+
* @param ctx - Koa context
|
|
164
|
+
* @returns true if the `_ml_session` cookie exists
|
|
165
|
+
*/
|
|
166
|
+
export function hasMagicLinkSession(ctx) {
|
|
167
|
+
return !!ctx.cookies.get(ML_SESSION_COOKIE);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Clear the magic link session cookie.
|
|
171
|
+
*
|
|
172
|
+
* @param ctx - Koa context
|
|
173
|
+
*/
|
|
174
|
+
export function clearMagicLinkSessionCookie(ctx) {
|
|
175
|
+
ctx.cookies.set(ML_SESSION_COOKIE, '', {
|
|
176
|
+
httpOnly: true,
|
|
177
|
+
sameSite: 'lax',
|
|
178
|
+
path: '/',
|
|
179
|
+
maxAge: 0,
|
|
180
|
+
overwrite: true,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=magic-link-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"magic-link-session.js","sourceRoot":"","sources":["../../src/auth/magic-link-session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,143 @@
|
|
|
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
|
+
/** Result of a rate limit check */
|
|
23
|
+
export interface RateLimitResult {
|
|
24
|
+
/** Whether the request is allowed (within limit) */
|
|
25
|
+
allowed: boolean;
|
|
26
|
+
/** Number of remaining requests in this window */
|
|
27
|
+
remaining: number;
|
|
28
|
+
/** When the current window expires */
|
|
29
|
+
resetAt: Date;
|
|
30
|
+
/** Seconds until the client can retry (0 if allowed) */
|
|
31
|
+
retryAfter: number;
|
|
32
|
+
}
|
|
33
|
+
/** Configuration for a rate limit rule */
|
|
34
|
+
export interface RateLimitConfig {
|
|
35
|
+
/** Maximum number of requests allowed in the window */
|
|
36
|
+
max: number;
|
|
37
|
+
/** Window duration in seconds */
|
|
38
|
+
windowSeconds: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Check if a request is within the rate limit for the given key.
|
|
42
|
+
*
|
|
43
|
+
* Uses Redis INCR + conditional EXPIRE for atomic counter management:
|
|
44
|
+
* 1. INCR the key (creates it at 1 if new)
|
|
45
|
+
* 2. If TTL is -1 (no expiry), set EXPIRE to windowSeconds
|
|
46
|
+
* 3. Compare count against max — reject if exceeded
|
|
47
|
+
*
|
|
48
|
+
* On Redis failure, returns allowed: true with a warning log.
|
|
49
|
+
*
|
|
50
|
+
* @param key - Rate limit key (use a build*Key function to construct)
|
|
51
|
+
* @param config - Rate limit configuration (max requests + window)
|
|
52
|
+
* @returns Rate limit result with allowed status and metadata
|
|
53
|
+
*/
|
|
54
|
+
export declare function checkRateLimit(key: string, config: RateLimitConfig): Promise<RateLimitResult>;
|
|
55
|
+
/**
|
|
56
|
+
* Check a security-critical limit without allowing Redis failure to bypass the boundary.
|
|
57
|
+
*
|
|
58
|
+
* @param key - Privacy-safe, domain-separated Redis key.
|
|
59
|
+
* @param config - Maximum attempts and fixed window.
|
|
60
|
+
* @returns Current limit decision.
|
|
61
|
+
* @throws When Redis cannot durably increment and expire the attempt counter.
|
|
62
|
+
*/
|
|
63
|
+
export declare function checkRateLimitStrict(key: string, config: RateLimitConfig): Promise<RateLimitResult>;
|
|
64
|
+
/**
|
|
65
|
+
* Reset the rate limit counter for a key.
|
|
66
|
+
*
|
|
67
|
+
* Called after successful authentication to clear the counter,
|
|
68
|
+
* allowing the user to make fresh attempts if they log out and back in.
|
|
69
|
+
*
|
|
70
|
+
* @param key - Rate limit key to reset
|
|
71
|
+
*/
|
|
72
|
+
export declare function resetRateLimit(key: string): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Build a rate limit key for login attempts.
|
|
75
|
+
* Combines IP + email to rate-limit per user per source IP.
|
|
76
|
+
*
|
|
77
|
+
* Format: ratelimit:login:{org_id}:{sha256(ip + email)[:16]}
|
|
78
|
+
*
|
|
79
|
+
* @param orgId - Organization UUID
|
|
80
|
+
* @param ip - Client IP address
|
|
81
|
+
* @param email - Email address being attempted
|
|
82
|
+
* @returns Rate limit key string
|
|
83
|
+
*/
|
|
84
|
+
export declare function buildLoginRateLimitKey(orgId: string, ip: string, email: string): string;
|
|
85
|
+
/**
|
|
86
|
+
* Build a rate limit key for magic link requests.
|
|
87
|
+
* Rate-limits per email to prevent spam.
|
|
88
|
+
*
|
|
89
|
+
* Format: ratelimit:magic:{org_id}:{sha256(email)[:16]}
|
|
90
|
+
*
|
|
91
|
+
* @param orgId - Organization UUID
|
|
92
|
+
* @param email - Email address requesting magic link
|
|
93
|
+
* @returns Rate limit key string
|
|
94
|
+
*/
|
|
95
|
+
export declare function buildMagicLinkRateLimitKey(orgId: string, email: string): string;
|
|
96
|
+
/**
|
|
97
|
+
* Build the callback-attempt key from tenant, direct socket peer, and protected artifact digest.
|
|
98
|
+
*
|
|
99
|
+
* @param orgId - Route organization UUID.
|
|
100
|
+
* @param socketPeer - Direct TCP peer rather than a caller-controlled forwarding header.
|
|
101
|
+
* @param artifactDigest - Domain-separated keyed digest of the presented artifact.
|
|
102
|
+
* @returns Privacy-safe Redis key with isolated tenant, peer, and artifact budgets.
|
|
103
|
+
*/
|
|
104
|
+
export declare function buildMagicLinkCallbackRateLimitKey(orgId: string, socketPeer: string, artifactDigest: string): string;
|
|
105
|
+
/**
|
|
106
|
+
* Build a rate limit key for password reset requests.
|
|
107
|
+
* Rate-limits per email to prevent abuse.
|
|
108
|
+
*
|
|
109
|
+
* Format: ratelimit:reset:{org_id}:{sha256(email)[:16]}
|
|
110
|
+
*
|
|
111
|
+
* @param orgId - Organization UUID
|
|
112
|
+
* @param email - Email address requesting password reset
|
|
113
|
+
* @returns Rate limit key string
|
|
114
|
+
*/
|
|
115
|
+
/**
|
|
116
|
+
* Build a generic rate limit key for custom actions (e.g., 2FA verification, OTP resend).
|
|
117
|
+
*
|
|
118
|
+
* @param action - Action identifier (e.g., '2fa_verify', '2fa_resend')
|
|
119
|
+
* @param orgId - Organization UUID
|
|
120
|
+
* @param identifier - User-specific identifier (e.g., userId)
|
|
121
|
+
* @returns Redis key string
|
|
122
|
+
*/
|
|
123
|
+
export declare function buildRateLimitKey(action: string, orgId: string, identifier: string): string;
|
|
124
|
+
export declare function buildPasswordResetRateLimitKey(orgId: string, email: string): string;
|
|
125
|
+
/**
|
|
126
|
+
* Load login rate limit configuration from system_config.
|
|
127
|
+
*
|
|
128
|
+
* @returns Rate limit config with max attempts and window duration
|
|
129
|
+
*/
|
|
130
|
+
export declare function loadLoginRateLimitConfig(): Promise<RateLimitConfig>;
|
|
131
|
+
/**
|
|
132
|
+
* Load magic link rate limit configuration from system_config.
|
|
133
|
+
*
|
|
134
|
+
* @returns Rate limit config with max requests and window duration
|
|
135
|
+
*/
|
|
136
|
+
export declare function loadMagicLinkRateLimitConfig(): Promise<RateLimitConfig>;
|
|
137
|
+
/**
|
|
138
|
+
* Load password reset rate limit configuration from system_config.
|
|
139
|
+
*
|
|
140
|
+
* @returns Rate limit config with max requests and window duration
|
|
141
|
+
*/
|
|
142
|
+
export declare function loadPasswordResetRateLimitConfig(): Promise<RateLimitConfig>;
|
|
143
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/auth/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAWH,mCAAmC;AACnC,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;IACjB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,OAAO,EAAE,IAAI,CAAC;IACd,wDAAwD;IACxD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,0CAA0C;AAC1C,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;IACZ,iCAAiC;IACjC,aAAa,EAAE,MAAM,CAAC;CACvB;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,eAAe,CAAC,CAa1B;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,eAAe,CAAC,CAE1B;AAoBD;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ/D;AAkBD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvF;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/E;AAED;;;;;;;GAOG;AACH,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,GACrB,MAAM,CAER;AAED;;;;;;;;;GASG;AACH;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE3F;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnF;AAMD;;;;GAIG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,eAAe,CAAC,CAMzE;AAED;;;;GAIG;AACH,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,eAAe,CAAC,CAM7E;AAED;;;;GAIG;AACH,wBAAsB,gCAAgC,IAAI,OAAO,CAAC,eAAe,CAAC,CAMjF"}
|