@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,475 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token repository — PostgreSQL CRUD for all three token tables.
|
|
3
|
+
*
|
|
4
|
+
* Password-reset and invitation tokens use shared allowlisted helpers. Magic-link issuance and
|
|
5
|
+
* consumption use dedicated authority-aware transactions so callers cannot omit tenant, live
|
|
6
|
+
* client, or interaction validation.
|
|
7
|
+
*
|
|
8
|
+
* Token lifecycle:
|
|
9
|
+
* 1. insertToken() → store hash + expiry for a user
|
|
10
|
+
* 2. findValidToken() → look up unused, non-expired token by hash
|
|
11
|
+
* 3. markTokenUsed() → set used_at = NOW() after successful verification
|
|
12
|
+
* 4. invalidateUserTokens() → expire all active tokens for a user (when new token issued)
|
|
13
|
+
* 5. deleteExpiredTokens() → cleanup old rows (housekeeping)
|
|
14
|
+
*/
|
|
15
|
+
import { getPool } from '../lib/database.js';
|
|
16
|
+
import { logger } from '../lib/logger.js';
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Allowlist validation
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
/** Set of valid token table names for runtime validation */
|
|
21
|
+
const VALID_TABLES = new Set([
|
|
22
|
+
'magic_link_tokens',
|
|
23
|
+
'password_reset_tokens',
|
|
24
|
+
'invitation_tokens',
|
|
25
|
+
]);
|
|
26
|
+
/**
|
|
27
|
+
* Validate that the table name is in the allowlist.
|
|
28
|
+
* Throws immediately on invalid names — this is a programming error, not a user error.
|
|
29
|
+
*
|
|
30
|
+
* @param table - Table name to validate
|
|
31
|
+
* @throws Error if table name is not in the allowlist
|
|
32
|
+
*/
|
|
33
|
+
function assertValidTable(table) {
|
|
34
|
+
if (!VALID_TABLES.has(table)) {
|
|
35
|
+
throw new Error(`Invalid token table: "${table}". Must be one of: ${[...VALID_TABLES].join(', ')}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Row mapping
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
/**
|
|
42
|
+
* Map a snake_case database row to a camelCase TokenRecord.
|
|
43
|
+
*
|
|
44
|
+
* @param row - Raw database row
|
|
45
|
+
* @returns Mapped TokenRecord with camelCase properties
|
|
46
|
+
*/
|
|
47
|
+
function mapRowToToken(row) {
|
|
48
|
+
return {
|
|
49
|
+
id: row.id,
|
|
50
|
+
userId: row.user_id,
|
|
51
|
+
tokenHash: row.token_hash,
|
|
52
|
+
expiresAt: row.expires_at,
|
|
53
|
+
usedAt: row.used_at,
|
|
54
|
+
createdAt: row.created_at,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// CRUD operations
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
/**
|
|
61
|
+
* Insert a new token into the specified table.
|
|
62
|
+
*
|
|
63
|
+
* @param table - Target token table (magic_link_tokens | password_reset_tokens | invitation_tokens)
|
|
64
|
+
* @param userId - UUID of the user this token belongs to
|
|
65
|
+
* @param tokenHash - SHA-256 hex hash of the plaintext token
|
|
66
|
+
* @param expiresAt - When this token expires
|
|
67
|
+
*/
|
|
68
|
+
export async function insertToken(table, userId, tokenHash, expiresAt) {
|
|
69
|
+
assertValidTable(table);
|
|
70
|
+
const pool = getPool();
|
|
71
|
+
await pool.query(`INSERT INTO ${table} (user_id, token_hash, expires_at)
|
|
72
|
+
VALUES ($1, $2, $3)`, [userId, tokenHash, expiresAt]);
|
|
73
|
+
logger.debug({ table, userId }, 'Token inserted');
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Create or observe the single token artifact owned by a recovery job.
|
|
77
|
+
*
|
|
78
|
+
* A transaction locks the user row as the shared serialization authority, reuses an existing job
|
|
79
|
+
* artifact, or invalidates an older artifact and inserts exactly one new row. A retry from an older
|
|
80
|
+
* job cannot replace authority created by any newer job, even after that authority is consumed or
|
|
81
|
+
* expires. SQL identifiers come exclusively from the closed table union.
|
|
82
|
+
*
|
|
83
|
+
* @param input - Recovery-job token authority and deterministic token facts.
|
|
84
|
+
*/
|
|
85
|
+
export async function ensureRecoveryJobToken(input) {
|
|
86
|
+
assertValidTable(input.table);
|
|
87
|
+
const pool = getPool();
|
|
88
|
+
const client = await pool.connect();
|
|
89
|
+
try {
|
|
90
|
+
await client.query('BEGIN');
|
|
91
|
+
const lockedUser = await client.query('SELECT id FROM users WHERE id = $1 FOR UPDATE', [
|
|
92
|
+
input.userId,
|
|
93
|
+
]);
|
|
94
|
+
if (lockedUser.rowCount !== 1) {
|
|
95
|
+
throw new Error('Recovery artifact user disappeared before issuance');
|
|
96
|
+
}
|
|
97
|
+
const jobOrder = await client.query('SELECT created_at FROM auth_recovery_jobs WHERE id = $1', [input.recoveryJobId]);
|
|
98
|
+
const currentJob = jobOrder.rows[0];
|
|
99
|
+
if (!currentJob) {
|
|
100
|
+
throw new Error('Recovery job disappeared before artifact issuance');
|
|
101
|
+
}
|
|
102
|
+
if (input.table === 'magic_link_tokens') {
|
|
103
|
+
const clientMatches = input.interactionUid === null && input.clientId === null
|
|
104
|
+
? true
|
|
105
|
+
: input.interactionUid !== null &&
|
|
106
|
+
input.clientId !== null &&
|
|
107
|
+
(await lockActiveClientAuthority(client, input.clientId, input.organizationId));
|
|
108
|
+
if (!clientMatches) {
|
|
109
|
+
await client.query('COMMIT');
|
|
110
|
+
return 'superseded';
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const existing = await client.query(`SELECT used_at IS NULL AND expires_at > NOW() AS active
|
|
114
|
+
FROM ${input.table}
|
|
115
|
+
WHERE recovery_job_id = $1`, [input.recoveryJobId]);
|
|
116
|
+
if (existing.rows[0]) {
|
|
117
|
+
await client.query('COMMIT');
|
|
118
|
+
return existing.rows[0].active ? 'active' : 'superseded';
|
|
119
|
+
}
|
|
120
|
+
const newestArtifact = await client.query(`SELECT token.recovery_job_id, job.created_at
|
|
121
|
+
FROM ${input.table} AS token
|
|
122
|
+
JOIN auth_recovery_jobs AS job ON job.id = token.recovery_job_id
|
|
123
|
+
WHERE token.user_id = $1
|
|
124
|
+
AND token.recovery_job_id IS NOT NULL
|
|
125
|
+
ORDER BY job.created_at DESC, job.id DESC
|
|
126
|
+
LIMIT 1`, [input.userId]);
|
|
127
|
+
const newest = newestArtifact.rows[0];
|
|
128
|
+
const currentCreatedAt = currentJob.created_at.getTime();
|
|
129
|
+
const newerArtifactExists = newest !== undefined &&
|
|
130
|
+
(newest.created_at.getTime() > currentCreatedAt ||
|
|
131
|
+
(newest.created_at.getTime() === currentCreatedAt &&
|
|
132
|
+
newest.recovery_job_id > input.recoveryJobId));
|
|
133
|
+
if (newerArtifactExists) {
|
|
134
|
+
await client.query('COMMIT');
|
|
135
|
+
return 'superseded';
|
|
136
|
+
}
|
|
137
|
+
await client.query(`UPDATE ${input.table}
|
|
138
|
+
SET used_at = NOW()
|
|
139
|
+
WHERE user_id = $1 AND used_at IS NULL AND expires_at > NOW()`, [input.userId]);
|
|
140
|
+
if (input.table === 'magic_link_tokens') {
|
|
141
|
+
await client.query(`INSERT INTO magic_link_tokens
|
|
142
|
+
(user_id, token_hash, expires_at, recovery_job_id, organization_id, interaction_uid)
|
|
143
|
+
VALUES ($1, $2, $3, $4, $5, $6)`, [
|
|
144
|
+
input.userId,
|
|
145
|
+
input.tokenHash,
|
|
146
|
+
input.expiresAt,
|
|
147
|
+
input.recoveryJobId,
|
|
148
|
+
input.organizationId,
|
|
149
|
+
input.interactionUid,
|
|
150
|
+
]);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
await client.query(`INSERT INTO password_reset_tokens (user_id, token_hash, expires_at, recovery_job_id)
|
|
154
|
+
VALUES ($1, $2, $3, $4)`, [input.userId, input.tokenHash, input.expiresAt, input.recoveryJobId]);
|
|
155
|
+
}
|
|
156
|
+
await client.query('COMMIT');
|
|
157
|
+
return 'active';
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
await client.query('ROLLBACK');
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
client.release();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Lock and validate the current client tenant inside an artifact transaction.
|
|
169
|
+
*
|
|
170
|
+
* Client ownership is checked in the same transaction that inserts or consumes the artifact so a
|
|
171
|
+
* concurrent revocation cannot pass an earlier route-only check and then gain authority.
|
|
172
|
+
*
|
|
173
|
+
* @param client - Active PostgreSQL transaction.
|
|
174
|
+
* @param clientId - Public OIDC client identifier resolved from the live interaction.
|
|
175
|
+
* @param organizationId - Tenant which must currently own the active client.
|
|
176
|
+
* @returns True only when one current active client row is locked.
|
|
177
|
+
*/
|
|
178
|
+
async function lockActiveClientAuthority(client, clientId, organizationId) {
|
|
179
|
+
const result = await client.query(`SELECT id
|
|
180
|
+
FROM clients
|
|
181
|
+
WHERE client_id = $1
|
|
182
|
+
AND organization_id = $2
|
|
183
|
+
AND status = 'active'
|
|
184
|
+
FOR SHARE`, [clientId, organizationId]);
|
|
185
|
+
return result.rowCount === 1;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Find a valid (unused, not expired) token by its hash.
|
|
189
|
+
*
|
|
190
|
+
* Checks both `used_at IS NULL` and `expires_at > NOW()` in a single query
|
|
191
|
+
* for efficiency. Returns null if no matching valid token exists.
|
|
192
|
+
*
|
|
193
|
+
* @param table - Target token table
|
|
194
|
+
* @param tokenHash - SHA-256 hex hash to look up
|
|
195
|
+
* @returns The token record if valid, or null if not found/expired/used
|
|
196
|
+
*/
|
|
197
|
+
export async function findValidToken(table, tokenHash) {
|
|
198
|
+
assertValidTable(table);
|
|
199
|
+
const pool = getPool();
|
|
200
|
+
const result = await pool.query(`SELECT id, user_id, token_hash, expires_at, used_at, created_at
|
|
201
|
+
FROM ${table}
|
|
202
|
+
WHERE token_hash = $1
|
|
203
|
+
AND used_at IS NULL
|
|
204
|
+
AND expires_at > NOW()`, [tokenHash]);
|
|
205
|
+
if (result.rows.length === 0) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
return mapRowToToken(result.rows[0]);
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Find a valid token only when its user belongs to the resolved organization.
|
|
212
|
+
*
|
|
213
|
+
* Tenant binding is enforced in the lookup itself so a valid token presented under another
|
|
214
|
+
* tenant is indistinguishable from an invalid token and cannot reach account mutation.
|
|
215
|
+
*
|
|
216
|
+
* @param table - Target token table.
|
|
217
|
+
* @param tokenHash - SHA-256 token digest.
|
|
218
|
+
* @param organizationId - Tenant authority resolved from the public route.
|
|
219
|
+
* @returns The valid tenant-owned token, or null.
|
|
220
|
+
*/
|
|
221
|
+
export async function findValidTokenForOrganization(table, tokenHash, organizationId) {
|
|
222
|
+
assertValidTable(table);
|
|
223
|
+
const pool = getPool();
|
|
224
|
+
const result = await pool.query(`SELECT token.id, token.user_id, token.token_hash,
|
|
225
|
+
token.expires_at, token.used_at, token.created_at
|
|
226
|
+
FROM ${table} AS token
|
|
227
|
+
JOIN users AS account ON account.id = token.user_id
|
|
228
|
+
WHERE token.token_hash = $1
|
|
229
|
+
AND account.organization_id = $2
|
|
230
|
+
AND token.used_at IS NULL
|
|
231
|
+
AND token.expires_at > NOW()`, [tokenHash, organizationId]);
|
|
232
|
+
return result.rows[0] ? mapRowToToken(result.rows[0]) : null;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Lock one valid magic-link artifact together with its tenant-owned user.
|
|
236
|
+
*
|
|
237
|
+
* Legacy rows without persisted organization authority do not match. The caller must keep the
|
|
238
|
+
* supplied client transaction open while validating interaction authority and applying all
|
|
239
|
+
* successful state changes.
|
|
240
|
+
*
|
|
241
|
+
* @param client - Active PostgreSQL transaction client.
|
|
242
|
+
* @param tokenHash - SHA-256 digest of the presented artifact.
|
|
243
|
+
* @param organizationId - Organization resolved from the public route.
|
|
244
|
+
* @returns The locked authority record, or null for every invalid authority state.
|
|
245
|
+
*/
|
|
246
|
+
export async function findAndLockMagicLinkToken(client, tokenHash, organizationId) {
|
|
247
|
+
const result = await client.query(`SELECT token.id, token.user_id, token.token_hash, token.expires_at, token.used_at,
|
|
248
|
+
token.created_at, token.organization_id, token.interaction_uid,
|
|
249
|
+
account.status AS account_status
|
|
250
|
+
FROM magic_link_tokens AS token
|
|
251
|
+
JOIN users AS account
|
|
252
|
+
ON account.id = token.user_id
|
|
253
|
+
AND account.organization_id = token.organization_id
|
|
254
|
+
WHERE token.token_hash = $1
|
|
255
|
+
AND token.organization_id = $2
|
|
256
|
+
AND token.authority_bound = TRUE
|
|
257
|
+
AND token.used_at IS NULL
|
|
258
|
+
AND token.expires_at > NOW()
|
|
259
|
+
FOR UPDATE OF token, account`, [tokenHash, organizationId]);
|
|
260
|
+
const row = result.rows[0];
|
|
261
|
+
if (!row)
|
|
262
|
+
return null;
|
|
263
|
+
return {
|
|
264
|
+
...mapRowToToken(row),
|
|
265
|
+
organizationId: row.organization_id,
|
|
266
|
+
interactionUid: row.interaction_uid,
|
|
267
|
+
accountStatus: row.account_status,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Conditionally consume a previously locked magic-link artifact.
|
|
272
|
+
*
|
|
273
|
+
* The predicates are repeated at mutation time so expiry or accidental prior consumption cannot
|
|
274
|
+
* be converted into a successful use. The caller must roll back when this function returns false.
|
|
275
|
+
*
|
|
276
|
+
* @param client - Active PostgreSQL transaction client that owns the artifact lock.
|
|
277
|
+
* @param tokenId - UUID of the locked magic-link artifact.
|
|
278
|
+
* @returns True only when exactly one still-valid row was consumed.
|
|
279
|
+
*/
|
|
280
|
+
export async function consumeLockedMagicLinkToken(client, tokenId) {
|
|
281
|
+
const result = await client.query(`UPDATE magic_link_tokens
|
|
282
|
+
SET used_at = NOW()
|
|
283
|
+
WHERE id = $1
|
|
284
|
+
AND used_at IS NULL
|
|
285
|
+
AND expires_at > NOW()
|
|
286
|
+
RETURNING id`, [tokenId]);
|
|
287
|
+
return result.rowCount === 1;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Validate all durable authority and apply one magic-link login in a single transaction.
|
|
291
|
+
*
|
|
292
|
+
* The artifact and account rows remain locked from lookup through consumption, account update,
|
|
293
|
+
* and audit insertion. Every authority mismatch rolls back before mutation, including a missing,
|
|
294
|
+
* changed, or unexpectedly supplied interaction identifier. Cache and Redis continuation work
|
|
295
|
+
* deliberately happen after this durable transaction because they are separate stores.
|
|
296
|
+
*
|
|
297
|
+
* @param input - Route tenant, presented interaction, artifact digest, and safe request metadata.
|
|
298
|
+
* @returns The committed account authority, or null for every public rejection condition.
|
|
299
|
+
*/
|
|
300
|
+
export async function consumeAuthorizedMagicLink(input) {
|
|
301
|
+
const client = await getPool().connect();
|
|
302
|
+
try {
|
|
303
|
+
await client.query('BEGIN');
|
|
304
|
+
const clientMatches = input.interactionUid === null && input.clientId === null
|
|
305
|
+
? true
|
|
306
|
+
: input.interactionUid !== null &&
|
|
307
|
+
input.clientId !== null &&
|
|
308
|
+
(await lockActiveClientAuthority(client, input.clientId, input.organizationId));
|
|
309
|
+
if (!clientMatches) {
|
|
310
|
+
await client.query('ROLLBACK');
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
const token = await findAndLockMagicLinkToken(client, input.tokenHash, input.organizationId);
|
|
314
|
+
const authorityMatches = token !== null &&
|
|
315
|
+
token.accountStatus === 'active' &&
|
|
316
|
+
token.interactionUid === input.interactionUid;
|
|
317
|
+
if (!authorityMatches) {
|
|
318
|
+
await client.query('ROLLBACK');
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
const consumed = await consumeLockedMagicLinkToken(client, token.id);
|
|
322
|
+
if (!consumed) {
|
|
323
|
+
await client.query('ROLLBACK');
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
const accountUpdate = await client.query(`UPDATE users
|
|
327
|
+
SET email_verified = TRUE,
|
|
328
|
+
last_login_at = NOW(),
|
|
329
|
+
login_count = login_count + 1,
|
|
330
|
+
failed_login_count = 0,
|
|
331
|
+
last_failed_login_at = NULL
|
|
332
|
+
WHERE id = $1
|
|
333
|
+
AND organization_id = $2
|
|
334
|
+
AND status = 'active'
|
|
335
|
+
RETURNING id`, [token.userId, input.organizationId]);
|
|
336
|
+
if (accountUpdate.rowCount !== 1) {
|
|
337
|
+
await client.query('ROLLBACK');
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
await client.query(`INSERT INTO audit_log (
|
|
341
|
+
organization_id, user_id, event_type, event_category, description,
|
|
342
|
+
metadata, ip_address
|
|
343
|
+
)
|
|
344
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)`, [
|
|
345
|
+
input.organizationId,
|
|
346
|
+
token.userId,
|
|
347
|
+
'user.login.magic_link',
|
|
348
|
+
'authentication',
|
|
349
|
+
'Magic link login successful',
|
|
350
|
+
'{}',
|
|
351
|
+
input.ipAddress ?? null,
|
|
352
|
+
]);
|
|
353
|
+
await client.query('COMMIT');
|
|
354
|
+
return { userId: token.userId, interactionUid: token.interactionUid };
|
|
355
|
+
}
|
|
356
|
+
catch (error) {
|
|
357
|
+
await client.query('ROLLBACK');
|
|
358
|
+
throw error;
|
|
359
|
+
}
|
|
360
|
+
finally {
|
|
361
|
+
client.release();
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Mark a token as used by setting used_at = NOW().
|
|
366
|
+
*
|
|
367
|
+
* Called after successful token verification to prevent reuse.
|
|
368
|
+
* This is a single-use pattern — once marked, the token cannot be found by findValidToken.
|
|
369
|
+
*
|
|
370
|
+
* @param table - Target token table
|
|
371
|
+
* @param tokenId - UUID of the token row to mark
|
|
372
|
+
*/
|
|
373
|
+
export async function markTokenUsed(table, tokenId) {
|
|
374
|
+
assertValidTable(table);
|
|
375
|
+
const pool = getPool();
|
|
376
|
+
await pool.query(`UPDATE ${table} SET used_at = NOW() WHERE id = $1`, [tokenId]);
|
|
377
|
+
logger.debug({ table, tokenId }, 'Token marked as used');
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Delete expired or used tokens older than a given cutoff date.
|
|
381
|
+
*
|
|
382
|
+
* Housekeeping function to prevent token tables from growing indefinitely.
|
|
383
|
+
* Removes tokens where expires_at < cutoff OR (used_at IS NOT NULL AND used_at < cutoff).
|
|
384
|
+
*
|
|
385
|
+
* @param table - Target token table
|
|
386
|
+
* @param olderThan - Cutoff date — tokens expired/used before this are deleted
|
|
387
|
+
* @returns Number of rows deleted
|
|
388
|
+
*/
|
|
389
|
+
export async function deleteExpiredTokens(table, olderThan) {
|
|
390
|
+
assertValidTable(table);
|
|
391
|
+
const pool = getPool();
|
|
392
|
+
const result = await pool.query(`DELETE FROM ${table}
|
|
393
|
+
WHERE expires_at < $1
|
|
394
|
+
OR (used_at IS NOT NULL AND used_at < $1)`, [olderThan]);
|
|
395
|
+
const count = result.rowCount ?? 0;
|
|
396
|
+
if (count > 0) {
|
|
397
|
+
logger.info({ table, count, olderThan: olderThan.toISOString() }, 'Expired tokens cleaned up');
|
|
398
|
+
}
|
|
399
|
+
return count;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Invalidate all unused tokens for a user in a table.
|
|
403
|
+
*
|
|
404
|
+
* Sets used_at = NOW() on all active (unused, non-expired) tokens.
|
|
405
|
+
* Called when a new token is issued to ensure only the latest token is valid.
|
|
406
|
+
* This prevents token accumulation and confusion from multiple active tokens.
|
|
407
|
+
*
|
|
408
|
+
* @param table - Target token table
|
|
409
|
+
* @param userId - UUID of the user whose tokens should be invalidated
|
|
410
|
+
*/
|
|
411
|
+
export async function invalidateUserTokens(table, userId) {
|
|
412
|
+
assertValidTable(table);
|
|
413
|
+
const pool = getPool();
|
|
414
|
+
const result = await pool.query(`UPDATE ${table}
|
|
415
|
+
SET used_at = NOW()
|
|
416
|
+
WHERE user_id = $1
|
|
417
|
+
AND used_at IS NULL`, [userId]);
|
|
418
|
+
const count = result.rowCount ?? 0;
|
|
419
|
+
if (count > 0) {
|
|
420
|
+
logger.debug({ table, userId, count }, 'User tokens invalidated');
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
// ---------------------------------------------------------------------------
|
|
424
|
+
// Invitation-specific operations
|
|
425
|
+
// ---------------------------------------------------------------------------
|
|
426
|
+
/**
|
|
427
|
+
* Insert an invitation token with optional details and inviter metadata.
|
|
428
|
+
*
|
|
429
|
+
* Unlike the generic insertToken(), this stores additional JSONB details
|
|
430
|
+
* (pre-assigned roles, claims, personal message) and tracks who sent the invite.
|
|
431
|
+
*
|
|
432
|
+
* @param userId - UUID of the invited user
|
|
433
|
+
* @param tokenHash - SHA-256 hex hash of the plaintext token
|
|
434
|
+
* @param expiresAt - When this invitation expires
|
|
435
|
+
* @param details - Optional JSONB details (roles, claims, personalMessage, inviterName)
|
|
436
|
+
* @param invitedBy - Optional UUID of the admin who created this invitation
|
|
437
|
+
*/
|
|
438
|
+
export async function insertInvitationToken(userId, tokenHash, expiresAt, details, invitedBy) {
|
|
439
|
+
const pool = getPool();
|
|
440
|
+
await pool.query(`INSERT INTO invitation_tokens (user_id, token_hash, expires_at, details, invited_by)
|
|
441
|
+
VALUES ($1, $2, $3, $4, $5)`, [userId, tokenHash, expiresAt, details ? JSON.stringify(details) : null, invitedBy ?? null]);
|
|
442
|
+
logger.debug({ userId, hasDetails: !!details }, 'Invitation token inserted');
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Find a valid invitation token with its details metadata.
|
|
446
|
+
*
|
|
447
|
+
* Returns the full InvitationTokenRecord including the details JSONB
|
|
448
|
+
* column, which stores pre-assignment metadata for roles, claims, etc.
|
|
449
|
+
*
|
|
450
|
+
* @param tokenHash - SHA-256 hex hash to look up
|
|
451
|
+
* @returns The invitation token record with details, or null if not found/expired/used
|
|
452
|
+
*/
|
|
453
|
+
export async function findValidInvitationToken(tokenHash) {
|
|
454
|
+
const pool = getPool();
|
|
455
|
+
const result = await pool.query(`SELECT id, user_id, token_hash, expires_at, used_at, created_at, details, invited_by
|
|
456
|
+
FROM invitation_tokens
|
|
457
|
+
WHERE token_hash = $1
|
|
458
|
+
AND used_at IS NULL
|
|
459
|
+
AND expires_at > NOW()`, [tokenHash]);
|
|
460
|
+
if (result.rows.length === 0) {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
const row = result.rows[0];
|
|
464
|
+
return {
|
|
465
|
+
id: row.id,
|
|
466
|
+
userId: row.user_id,
|
|
467
|
+
tokenHash: row.token_hash,
|
|
468
|
+
expiresAt: row.expires_at,
|
|
469
|
+
usedAt: row.used_at,
|
|
470
|
+
createdAt: row.created_at,
|
|
471
|
+
details: row.details,
|
|
472
|
+
invitedBy: row.invited_by,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
//# sourceMappingURL=token-repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-repository.js","sourceRoot":"","sources":["../../src/auth/token-repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token generation and hashing utilities.
|
|
3
|
+
*
|
|
4
|
+
* Used by all token-based auth flows: magic links, password resets, and invitations.
|
|
5
|
+
* Tokens are generated as cryptographically secure random bytes, then hashed with
|
|
6
|
+
* SHA-256 for storage. The plaintext goes in the email/URL; only the hash is stored
|
|
7
|
+
* in the database — so a DB breach never leaks usable tokens.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* const { plaintext, hash } = generateToken();
|
|
11
|
+
* // plaintext → email link
|
|
12
|
+
* // hash → INSERT INTO magic_link_tokens (token_hash, ...)
|
|
13
|
+
*
|
|
14
|
+
* // Later, when verifying:
|
|
15
|
+
* const lookupHash = hashToken(plaintextFromUrl);
|
|
16
|
+
* // SELECT ... WHERE token_hash = lookupHash
|
|
17
|
+
*/
|
|
18
|
+
/** Result of generating a new token — plaintext for the URL, hash for the DB */
|
|
19
|
+
export interface GeneratedToken {
|
|
20
|
+
/** Base64url-encoded plaintext — included in the email/URL sent to the user */
|
|
21
|
+
plaintext: string;
|
|
22
|
+
/** SHA-256 hex digest — stored in the database for lookup */
|
|
23
|
+
hash: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Generate a cryptographically secure token.
|
|
27
|
+
*
|
|
28
|
+
* Returns both the plaintext (for the email/URL) and the SHA-256 hash (for DB storage).
|
|
29
|
+
* Uses 32 bytes of randomness (256 bits) which provides ample collision resistance
|
|
30
|
+
* and brute-force protection.
|
|
31
|
+
*
|
|
32
|
+
* @returns Object with `plaintext` (base64url) and `hash` (hex SHA-256)
|
|
33
|
+
*/
|
|
34
|
+
export declare function generateToken(): GeneratedToken;
|
|
35
|
+
/**
|
|
36
|
+
* Hash a plaintext token for database lookup.
|
|
37
|
+
*
|
|
38
|
+
* Used during verification — the user provides the plaintext via URL, we hash it
|
|
39
|
+
* and look up the matching row in the token table.
|
|
40
|
+
*
|
|
41
|
+
* @param plaintext - The base64url token string from the URL
|
|
42
|
+
* @returns SHA-256 hex digest for database lookup
|
|
43
|
+
*/
|
|
44
|
+
export declare function hashToken(plaintext: string): string;
|
|
45
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/auth/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAQH,gFAAgF;AAChF,MAAM,WAAW,cAAc;IAC7B,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;IAClB,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;CACd;AAMD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,IAAI,cAAc,CAI9C;AAMD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token generation and hashing utilities.
|
|
3
|
+
*
|
|
4
|
+
* Used by all token-based auth flows: magic links, password resets, and invitations.
|
|
5
|
+
* Tokens are generated as cryptographically secure random bytes, then hashed with
|
|
6
|
+
* SHA-256 for storage. The plaintext goes in the email/URL; only the hash is stored
|
|
7
|
+
* in the database — so a DB breach never leaks usable tokens.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* const { plaintext, hash } = generateToken();
|
|
11
|
+
* // plaintext → email link
|
|
12
|
+
* // hash → INSERT INTO magic_link_tokens (token_hash, ...)
|
|
13
|
+
*
|
|
14
|
+
* // Later, when verifying:
|
|
15
|
+
* const lookupHash = hashToken(plaintextFromUrl);
|
|
16
|
+
* // SELECT ... WHERE token_hash = lookupHash
|
|
17
|
+
*/
|
|
18
|
+
import crypto from 'node:crypto';
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Token generation
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
/**
|
|
23
|
+
* Generate a cryptographically secure token.
|
|
24
|
+
*
|
|
25
|
+
* Returns both the plaintext (for the email/URL) and the SHA-256 hash (for DB storage).
|
|
26
|
+
* Uses 32 bytes of randomness (256 bits) which provides ample collision resistance
|
|
27
|
+
* and brute-force protection.
|
|
28
|
+
*
|
|
29
|
+
* @returns Object with `plaintext` (base64url) and `hash` (hex SHA-256)
|
|
30
|
+
*/
|
|
31
|
+
export function generateToken() {
|
|
32
|
+
const plaintext = crypto.randomBytes(32).toString('base64url');
|
|
33
|
+
const hash = crypto.createHash('sha256').update(plaintext).digest('hex');
|
|
34
|
+
return { plaintext, hash };
|
|
35
|
+
}
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Token hashing
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
/**
|
|
40
|
+
* Hash a plaintext token for database lookup.
|
|
41
|
+
*
|
|
42
|
+
* Used during verification — the user provides the plaintext via URL, we hash it
|
|
43
|
+
* and look up the matching row in the token table.
|
|
44
|
+
*
|
|
45
|
+
* @param plaintext - The base64url token string from the URL
|
|
46
|
+
* @returns SHA-256 hex digest for database lookup
|
|
47
|
+
*/
|
|
48
|
+
export function hashToken(plaintext) {
|
|
49
|
+
return crypto.createHash('sha256').update(plaintext).digest('hex');
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/auth/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,MAAM,MAAM,aAAa,CAAC;AAcjC,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC/D,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACzE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAC7B,CAAC;AAED,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CAAC,SAAiB;IACzC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI bootstrap — direct-DB execution mode for infrastructure commands.
|
|
3
|
+
*
|
|
4
|
+
* Provides `withBootstrap()` for commands that need direct database/Redis
|
|
5
|
+
* access (init, migrate, seed, health --direct, user 2fa --direct).
|
|
6
|
+
*
|
|
7
|
+
* These commands run before or without the HTTP server, so they connect
|
|
8
|
+
* directly to PostgreSQL + Redis. The HTTP-based admin commands have been
|
|
9
|
+
* extracted to the standalone `@portaidentity/cli` package.
|
|
10
|
+
*
|
|
11
|
+
* Uses dynamic imports so that the config module (which validates env vars
|
|
12
|
+
* at load time) isn't triggered until bootstrap() is called. This allows
|
|
13
|
+
* CLI flag overrides (--database-url, --redis-url) to set process.env
|
|
14
|
+
* BEFORE config parses, making the overrides effective.
|
|
15
|
+
*
|
|
16
|
+
* @module cli/bootstrap
|
|
17
|
+
*/
|
|
18
|
+
import 'dotenv/config';
|
|
19
|
+
import type { GlobalOptions } from './index.js';
|
|
20
|
+
/**
|
|
21
|
+
* Bootstrap the CLI environment: load dotenv, connect DB + Redis.
|
|
22
|
+
*
|
|
23
|
+
* CLI flags (--database-url, --redis-url) override env vars if provided.
|
|
24
|
+
* The overrides are applied to process.env BEFORE the config module loads,
|
|
25
|
+
* so they propagate through to connectDatabase() and connectRedis().
|
|
26
|
+
*
|
|
27
|
+
* @param argv - Parsed CLI global options from yargs
|
|
28
|
+
*/
|
|
29
|
+
export declare function bootstrap(argv: GlobalOptions): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Clean shutdown: disconnect Redis then DB.
|
|
32
|
+
*
|
|
33
|
+
* Redis is disconnected first because some operations may flush
|
|
34
|
+
* cache entries to the database during shutdown.
|
|
35
|
+
*/
|
|
36
|
+
export declare function shutdown(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Convenience wrapper: bootstrap → run command → shutdown.
|
|
39
|
+
*
|
|
40
|
+
* Ensures cleanup happens even if the command throws an error.
|
|
41
|
+
* This is the recommended way for command handlers to use bootstrap:
|
|
42
|
+
*
|
|
43
|
+
* ```typescript
|
|
44
|
+
* await withBootstrap(argv, async () => {
|
|
45
|
+
* const orgs = await listOrganizations(pool);
|
|
46
|
+
* printTable(headers, rows);
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @param argv - Parsed CLI global options from yargs
|
|
51
|
+
* @param fn - The command handler function to execute
|
|
52
|
+
* @returns The return value of the command handler
|
|
53
|
+
*/
|
|
54
|
+
export declare function withBootstrap<T>(argv: GlobalOptions, fn: () => Promise<T>): Promise<T>;
|
|
55
|
+
//# sourceMappingURL=bootstrap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/cli/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BlE;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAM9C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,aAAa,CAAC,CAAC,EACnC,IAAI,EAAE,aAAa,EACnB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACnB,OAAO,CAAC,CAAC,CAAC,CAOZ"}
|