@lastshotlabs/bunshot 0.0.27 → 0.0.28
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/.oclif.manifest.json +39 -0
- package/README.md +8282 -2147
- package/dist/cli/commands/init.js +690 -0
- package/dist/cli/index.js +6 -0
- package/dist/cli.js +4 -4
- package/dist/packages/bunshot-admin/src/index.d.ts +15 -0
- package/dist/packages/bunshot-admin/src/index.js +11 -0
- package/dist/packages/bunshot-admin/src/lib/resourceTypes.d.ts +8 -0
- package/dist/packages/bunshot-admin/src/lib/resourceTypes.js +33 -0
- package/dist/packages/bunshot-admin/src/lib/typedRoute.d.ts +14 -0
- package/dist/packages/bunshot-admin/src/lib/typedRoute.js +17 -0
- package/dist/packages/bunshot-admin/src/plugin.d.ts +4 -0
- package/dist/packages/bunshot-admin/src/plugin.js +46 -0
- package/dist/packages/bunshot-admin/src/providers/auth0Access.d.ts +6 -0
- package/dist/packages/bunshot-admin/src/providers/auth0Access.js +32 -0
- package/dist/packages/bunshot-admin/src/routes/admin.d.ts +10 -0
- package/dist/packages/bunshot-admin/src/routes/admin.js +923 -0
- package/dist/packages/bunshot-admin/src/routes/mail.d.ts +6 -0
- package/dist/packages/bunshot-admin/src/routes/mail.js +114 -0
- package/dist/packages/bunshot-admin/src/routes/permissions.d.ts +8 -0
- package/dist/packages/bunshot-admin/src/routes/permissions.js +315 -0
- package/dist/packages/bunshot-admin/src/types/config.d.ts +16 -0
- package/dist/packages/bunshot-admin/src/types/config.js +37 -0
- package/dist/packages/bunshot-admin/src/types/env.d.ts +14 -0
- package/dist/packages/bunshot-admin/src/types/provider.d.ts +1 -0
- package/dist/packages/bunshot-admin/src/types/provider.js +4 -0
- package/dist/packages/bunshot-auth/src/adapters/memoryAuth.d.ts +66 -0
- package/dist/packages/bunshot-auth/src/adapters/memoryAuth.js +1063 -0
- package/dist/packages/bunshot-auth/src/adapters/mongoAuth.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/adapters/mongoAuth.js +536 -0
- package/dist/packages/bunshot-auth/src/adapters/sqliteAuth.d.ts +88 -0
- package/dist/packages/bunshot-auth/src/adapters/sqliteAuth.js +1366 -0
- package/dist/packages/bunshot-auth/src/admin/bunshotAccess.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/admin/bunshotAccess.js +23 -0
- package/dist/packages/bunshot-auth/src/admin/bunshotUsers.d.ts +5 -0
- package/dist/packages/bunshot-auth/src/admin/bunshotUsers.js +131 -0
- package/dist/packages/bunshot-auth/src/bootstrap.d.ts +38 -0
- package/dist/packages/bunshot-auth/src/bootstrap.js +384 -0
- package/dist/packages/bunshot-auth/src/config/appConfig.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/config/appConfig.js +4 -0
- package/dist/packages/bunshot-auth/src/config/authConfig.d.ts +478 -0
- package/dist/packages/bunshot-auth/src/config/authConfig.js +46 -0
- package/dist/packages/bunshot-auth/src/config/configLock.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/config/configLock.js +10 -0
- package/dist/packages/bunshot-auth/src/index.d.ts +25 -0
- package/dist/packages/bunshot-auth/src/index.js +23 -0
- package/dist/packages/bunshot-auth/src/infra/mongo.d.ts +15 -0
- package/dist/packages/bunshot-auth/src/infra/mongo.js +44 -0
- package/dist/packages/bunshot-auth/src/infra/queue.d.ts +14 -0
- package/dist/packages/bunshot-auth/src/infra/queue.js +27 -0
- package/dist/packages/bunshot-auth/src/infra/redis.d.ts +5 -0
- package/dist/packages/bunshot-auth/src/infra/redis.js +15 -0
- package/dist/packages/bunshot-auth/src/infra/signing.d.ts +7 -0
- package/dist/packages/bunshot-auth/src/infra/signing.js +8 -0
- package/dist/packages/bunshot-auth/src/lib/accountLockout.d.ts +34 -0
- package/dist/packages/bunshot-auth/src/lib/accountLockout.js +244 -0
- package/dist/packages/bunshot-auth/src/lib/adapterTiers.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/lib/adapterTiers.js +1 -0
- package/dist/packages/bunshot-auth/src/lib/authAdapter.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/lib/authAdapter.js +1 -0
- package/dist/packages/bunshot-auth/src/lib/authContext.d.ts +15 -0
- package/dist/packages/bunshot-auth/src/lib/authContext.js +1 -0
- package/dist/packages/bunshot-auth/src/lib/authEventBus.d.ts +4 -0
- package/dist/packages/bunshot-auth/src/lib/authEventBus.js +15 -0
- package/dist/packages/bunshot-auth/src/lib/authRateLimit.d.ts +28 -0
- package/dist/packages/bunshot-auth/src/lib/authRateLimit.js +205 -0
- package/dist/{lib → packages/bunshot-auth/src/lib}/breachedPassword.d.ts +8 -2
- package/dist/{lib → packages/bunshot-auth/src/lib}/breachedPassword.js +22 -9
- package/dist/packages/bunshot-auth/src/lib/cache.d.ts +12 -0
- package/dist/packages/bunshot-auth/src/lib/cache.js +120 -0
- package/dist/packages/bunshot-auth/src/lib/clientIp.d.ts +4 -0
- package/dist/{lib → packages/bunshot-auth/src/lib}/clientIp.js +14 -7
- package/dist/packages/bunshot-auth/src/lib/cookieOptions.d.ts +27 -0
- package/dist/packages/bunshot-auth/src/lib/cookieOptions.js +33 -0
- package/dist/packages/bunshot-auth/src/lib/credentialStuffing.d.ts +40 -0
- package/dist/packages/bunshot-auth/src/lib/credentialStuffing.js +221 -0
- package/dist/packages/bunshot-auth/src/lib/deletionCancelToken.d.ts +19 -0
- package/dist/packages/bunshot-auth/src/lib/deletionCancelToken.js +148 -0
- package/dist/packages/bunshot-auth/src/lib/emailTemplates.d.ts +23 -0
- package/dist/packages/bunshot-auth/src/lib/emailTemplates.js +265 -0
- package/dist/packages/bunshot-auth/src/lib/emailVerification.d.ts +30 -0
- package/dist/packages/bunshot-auth/src/lib/emailVerification.js +200 -0
- package/dist/packages/bunshot-auth/src/lib/env.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/lib/env.js +3 -0
- package/dist/packages/bunshot-auth/src/lib/fingerprint.js +36 -0
- package/dist/{lib → packages/bunshot-auth/src/lib}/groups.d.ts +15 -16
- package/dist/{lib → packages/bunshot-auth/src/lib}/groups.js +22 -34
- package/dist/packages/bunshot-auth/src/lib/jwks.d.ts +28 -0
- package/dist/packages/bunshot-auth/src/lib/jwks.js +79 -0
- package/dist/packages/bunshot-auth/src/lib/jwt.d.ts +12 -0
- package/dist/packages/bunshot-auth/src/lib/jwt.js +86 -0
- package/dist/{lib → packages/bunshot-auth/src/lib}/logger.js +3 -3
- package/dist/{lib → packages/bunshot-auth/src/lib}/m2m.d.ts +5 -4
- package/dist/{lib → packages/bunshot-auth/src/lib}/m2m.js +6 -10
- package/dist/packages/bunshot-auth/src/lib/magicLink.d.ts +13 -0
- package/dist/packages/bunshot-auth/src/lib/magicLink.js +145 -0
- package/dist/packages/bunshot-auth/src/lib/mfaChallenge.d.ts +60 -0
- package/dist/packages/bunshot-auth/src/lib/mfaChallenge.js +419 -0
- package/dist/packages/bunshot-auth/src/lib/oauth.d.ts +82 -0
- package/dist/packages/bunshot-auth/src/lib/oauth.js +177 -0
- package/dist/packages/bunshot-auth/src/lib/oauthCode.d.ts +19 -0
- package/dist/packages/bunshot-auth/src/lib/oauthCode.js +182 -0
- package/dist/packages/bunshot-auth/src/lib/oauthReauth.d.ts +19 -0
- package/dist/packages/bunshot-auth/src/lib/oauthReauth.js +255 -0
- package/dist/packages/bunshot-auth/src/lib/organization.d.ts +66 -0
- package/dist/packages/bunshot-auth/src/lib/organization.js +225 -0
- package/dist/packages/bunshot-auth/src/lib/passwordHistory.d.ts +12 -0
- package/dist/packages/bunshot-auth/src/lib/passwordHistory.js +31 -0
- package/dist/packages/bunshot-auth/src/lib/resetPassword.d.ts +20 -0
- package/dist/packages/bunshot-auth/src/lib/resetPassword.js +148 -0
- package/dist/packages/bunshot-auth/src/lib/roles.d.ts +9 -0
- package/dist/packages/bunshot-auth/src/lib/roles.js +93 -0
- package/dist/packages/bunshot-auth/src/lib/saml.d.ts +29 -0
- package/dist/packages/bunshot-auth/src/lib/saml.js +73 -0
- package/dist/packages/bunshot-auth/src/lib/samlRequestId.d.ts +13 -0
- package/dist/packages/bunshot-auth/src/lib/samlRequestId.js +129 -0
- package/dist/{lib → packages/bunshot-auth/src/lib}/scim.d.ts +7 -7
- package/dist/{lib → packages/bunshot-auth/src/lib}/scim.js +15 -13
- package/dist/packages/bunshot-auth/src/lib/securityEventWiring.d.ts +22 -0
- package/dist/packages/bunshot-auth/src/lib/securityEventWiring.js +65 -0
- package/dist/packages/bunshot-auth/src/lib/session.d.ts +45 -0
- package/dist/packages/bunshot-auth/src/lib/session.js +1211 -0
- package/dist/packages/bunshot-auth/src/lib/storeInfra.d.ts +26 -0
- package/dist/packages/bunshot-auth/src/lib/storeInfra.js +18 -0
- package/dist/{lib → packages/bunshot-auth/src/lib}/suspension.d.ts +3 -2
- package/dist/{lib → packages/bunshot-auth/src/lib}/suspension.js +2 -5
- package/dist/packages/bunshot-auth/src/lib/validateAdapter.d.ts +16 -0
- package/dist/packages/bunshot-auth/src/lib/validateAdapter.js +161 -0
- package/dist/packages/bunshot-auth/src/middleware/bearerAuth.d.ts +13 -0
- package/dist/packages/bunshot-auth/src/middleware/bearerAuth.js +58 -0
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/csrf.d.ts +5 -4
- package/dist/packages/bunshot-auth/src/middleware/csrf.js +138 -0
- package/dist/packages/bunshot-auth/src/middleware/identify.d.ts +4 -0
- package/dist/packages/bunshot-auth/src/middleware/identify.js +124 -0
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireMfaSetup.d.ts +2 -2
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireMfaSetup.js +10 -8
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireRole.d.ts +2 -2
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireRole.js +20 -16
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireScope.d.ts +2 -2
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireScope.js +6 -6
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireStepUp.d.ts +2 -2
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireStepUp.js +8 -7
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireVerifiedEmail.d.ts +2 -2
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireVerifiedEmail.js +7 -6
- package/dist/packages/bunshot-auth/src/middleware/scimAuth.d.ts +8 -0
- package/dist/packages/bunshot-auth/src/middleware/scimAuth.js +29 -0
- package/dist/packages/bunshot-auth/src/middleware/userAuth.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/middleware/userAuth.js +6 -0
- package/dist/{models → packages/bunshot-auth/src/models}/AuthUser.d.ts +12 -8
- package/dist/packages/bunshot-auth/src/models/AuthUser.js +53 -0
- package/dist/packages/bunshot-auth/src/models/Group.d.ts +19 -0
- package/dist/packages/bunshot-auth/src/models/Group.js +22 -0
- package/dist/{models → packages/bunshot-auth/src/models}/GroupMembership.d.ts +6 -8
- package/dist/packages/bunshot-auth/src/models/GroupMembership.js +19 -0
- package/dist/{models → packages/bunshot-auth/src/models}/M2MClient.d.ts +1 -1
- package/dist/{models → packages/bunshot-auth/src/models}/M2MClient.js +5 -5
- package/dist/packages/bunshot-auth/src/models/TenantRole.d.ts +13 -0
- package/dist/packages/bunshot-auth/src/models/TenantRole.js +17 -0
- package/dist/packages/bunshot-auth/src/plugin.d.ts +4 -0
- package/dist/packages/bunshot-auth/src/plugin.js +274 -0
- package/dist/packages/bunshot-auth/src/routes/auth.d.ts +15 -0
- package/dist/packages/bunshot-auth/src/routes/auth.js +1624 -0
- package/dist/packages/bunshot-auth/src/routes/groups.d.ts +4 -0
- package/dist/packages/bunshot-auth/src/routes/groups.js +481 -0
- package/dist/packages/bunshot-auth/src/routes/m2m.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/routes/m2m.js +145 -0
- package/dist/packages/bunshot-auth/src/routes/mfa.d.ts +6 -0
- package/dist/packages/bunshot-auth/src/routes/mfa.js +991 -0
- package/dist/packages/bunshot-auth/src/routes/oauth.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/routes/oauth.js +1727 -0
- package/dist/packages/bunshot-auth/src/routes/oidc.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/routes/oidc.js +84 -0
- package/dist/packages/bunshot-auth/src/routes/organizations.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/routes/organizations.js +741 -0
- package/dist/packages/bunshot-auth/src/routes/passkey.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/routes/passkey.js +199 -0
- package/dist/packages/bunshot-auth/src/routes/saml.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/routes/saml.js +226 -0
- package/dist/packages/bunshot-auth/src/routes/scim.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/routes/scim.js +588 -0
- package/dist/packages/bunshot-auth/src/runtime.d.ts +52 -0
- package/dist/packages/bunshot-auth/src/runtime.js +11 -0
- package/dist/{schemas → packages/bunshot-auth/src/schemas}/auth.d.ts +4 -5
- package/dist/packages/bunshot-auth/src/schemas/auth.js +24 -0
- package/dist/packages/bunshot-auth/src/schemas/error.d.ts +10 -0
- package/dist/packages/bunshot-auth/src/schemas/error.js +10 -0
- package/dist/packages/bunshot-auth/src/schemas/success.d.ts +10 -0
- package/dist/packages/bunshot-auth/src/schemas/success.js +10 -0
- package/dist/packages/bunshot-auth/src/services/auth.d.ts +39 -0
- package/dist/packages/bunshot-auth/src/services/auth.js +378 -0
- package/dist/{services → packages/bunshot-auth/src/services}/mfa.d.ts +41 -17
- package/dist/{services → packages/bunshot-auth/src/services}/mfa.js +259 -183
- package/dist/packages/bunshot-auth/src/testing.d.ts +31 -0
- package/dist/packages/bunshot-auth/src/testing.js +23 -0
- package/dist/packages/bunshot-auth/src/types/adapter.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/types/adapter.js +1 -0
- package/dist/packages/bunshot-auth/src/types/config.d.ts +152 -0
- package/dist/packages/bunshot-auth/src/types/config.js +179 -0
- package/dist/{routes → packages/bunshot-auth/src/types}/groups.d.ts +2 -3
- package/dist/packages/bunshot-auth/src/types/groups.js +1 -0
- package/dist/packages/bunshot-auth/src/types/oauthCode.d.ts +6 -0
- package/dist/packages/bunshot-auth/src/types/oauthCode.js +1 -0
- package/dist/packages/bunshot-auth/src/types/oauthReauth.d.ts +13 -0
- package/dist/packages/bunshot-auth/src/types/oauthReauth.js +1 -0
- package/dist/packages/bunshot-auth/src/types/redis.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/types/redis.js +1 -0
- package/dist/packages/bunshot-auth/src/types/saml.d.ts +10 -0
- package/dist/packages/bunshot-auth/src/types/saml.js +1 -0
- package/dist/packages/bunshot-auth/src/types/session.d.ts +18 -0
- package/dist/packages/bunshot-auth/src/types/session.js +1 -0
- package/dist/packages/bunshot-auth/src/types/store.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/types/store.js +1 -0
- package/dist/packages/bunshot-core/src/adminProvider.d.ts +95 -0
- package/dist/packages/bunshot-core/src/adminProvider.js +1 -0
- package/dist/packages/bunshot-core/src/auditLog.d.ts +34 -0
- package/dist/packages/bunshot-core/src/auditLog.js +1 -0
- package/dist/packages/bunshot-core/src/auth-adapter.d.ts +227 -0
- package/dist/packages/bunshot-core/src/auth-adapter.js +4 -0
- package/dist/packages/bunshot-core/src/authVariables.d.ts +14 -0
- package/dist/packages/bunshot-core/src/authVariables.js +4 -0
- package/dist/packages/bunshot-core/src/cache.d.ts +12 -0
- package/dist/packages/bunshot-core/src/cache.js +21 -0
- package/dist/{lib → packages/bunshot-core/src}/captcha.d.ts +1 -10
- package/dist/packages/bunshot-core/src/captcha.js +1 -0
- package/dist/packages/bunshot-core/src/clearRegistry.d.ts +6 -0
- package/dist/packages/bunshot-core/src/clearRegistry.js +17 -0
- package/dist/packages/bunshot-core/src/clientIp.d.ts +3 -0
- package/dist/packages/bunshot-core/src/clientIp.js +45 -0
- package/dist/packages/bunshot-core/src/configLock.d.ts +4 -0
- package/dist/packages/bunshot-core/src/configLock.js +7 -0
- package/dist/packages/bunshot-core/src/configValidation.d.ts +22 -0
- package/dist/packages/bunshot-core/src/configValidation.js +39 -0
- package/dist/packages/bunshot-core/src/constants.js +10 -0
- package/dist/packages/bunshot-core/src/context/bunshotContext.d.ts +232 -0
- package/dist/packages/bunshot-core/src/context/bunshotContext.js +1 -0
- package/dist/packages/bunshot-core/src/context/contextAccess.d.ts +3 -0
- package/dist/packages/bunshot-core/src/context/contextAccess.js +16 -0
- package/dist/packages/bunshot-core/src/context/contextStore.d.ts +16 -0
- package/dist/packages/bunshot-core/src/context/contextStore.js +31 -0
- package/dist/packages/bunshot-core/src/context/frameworkConfig.d.ts +38 -0
- package/dist/packages/bunshot-core/src/context/frameworkConfig.js +1 -0
- package/dist/packages/bunshot-core/src/context/index.d.ts +4 -0
- package/dist/packages/bunshot-core/src/context/index.js +2 -0
- package/dist/packages/bunshot-core/src/context.d.ts +40 -0
- package/dist/packages/bunshot-core/src/context.js +35 -0
- package/dist/packages/bunshot-core/src/coreContracts.d.ts +47 -0
- package/dist/packages/bunshot-core/src/coreContracts.js +1 -0
- package/dist/packages/bunshot-core/src/coreRegistrar.d.ts +6 -0
- package/dist/packages/bunshot-core/src/coreRegistrar.js +42 -0
- package/dist/{lib → packages/bunshot-core/src}/createRoute.d.ts +4 -30
- package/dist/{lib → packages/bunshot-core/src}/createRoute.js +39 -88
- package/dist/packages/bunshot-core/src/cronRegistry.d.ts +11 -0
- package/dist/packages/bunshot-core/src/cronRegistry.js +1 -0
- package/dist/packages/bunshot-core/src/crypto.d.ts +43 -0
- package/dist/packages/bunshot-core/src/crypto.js +74 -0
- package/dist/packages/bunshot-core/src/csrf.d.ts +8 -0
- package/dist/packages/bunshot-core/src/csrf.js +1 -0
- package/dist/packages/bunshot-core/src/defaults/defaultFingerprint.d.ts +7 -0
- package/dist/packages/bunshot-core/src/defaults/defaultFingerprint.js +19 -0
- package/dist/packages/bunshot-core/src/defaults/memoryCacheAdapter.d.ts +6 -0
- package/dist/packages/bunshot-core/src/defaults/memoryCacheAdapter.js +40 -0
- package/dist/packages/bunshot-core/src/defaults/memoryRateLimit.d.ts +6 -0
- package/dist/packages/bunshot-core/src/defaults/memoryRateLimit.js +24 -0
- package/dist/packages/bunshot-core/src/emailTemplates.d.ts +5 -0
- package/dist/packages/bunshot-core/src/emailTemplates.js +10 -0
- package/dist/{lib/HttpError.d.ts → packages/bunshot-core/src/errors.d.ts} +4 -1
- package/dist/{lib/HttpError.js → packages/bunshot-core/src/errors.js} +7 -1
- package/dist/packages/bunshot-core/src/eventBus.d.ts +270 -0
- package/dist/packages/bunshot-core/src/eventBus.js +143 -0
- package/dist/packages/bunshot-core/src/idempotency.d.ts +18 -0
- package/dist/packages/bunshot-core/src/idempotency.js +1 -0
- package/dist/packages/bunshot-core/src/index.d.ts +60 -0
- package/dist/packages/bunshot-core/src/index.js +34 -0
- package/dist/packages/bunshot-core/src/mail.d.ts +14 -0
- package/dist/packages/bunshot-core/src/mail.js +8 -0
- package/dist/packages/bunshot-core/src/memoryEviction.d.ts +24 -0
- package/dist/packages/bunshot-core/src/memoryEviction.js +52 -0
- package/dist/packages/bunshot-core/src/pagination.d.ts +45 -0
- package/dist/packages/bunshot-core/src/pagination.js +61 -0
- package/dist/packages/bunshot-core/src/permissions.d.ts +64 -0
- package/dist/packages/bunshot-core/src/permissions.js +27 -0
- package/dist/packages/bunshot-core/src/plugin.d.ts +44 -0
- package/dist/packages/bunshot-core/src/plugin.js +1 -0
- package/dist/packages/bunshot-core/src/rateLimit.d.ts +5 -0
- package/dist/packages/bunshot-core/src/rateLimit.js +18 -0
- package/dist/packages/bunshot-core/src/redis.d.ts +21 -0
- package/dist/packages/bunshot-core/src/redis.js +1 -0
- package/dist/packages/bunshot-core/src/routeAuth.d.ts +5 -0
- package/dist/packages/bunshot-core/src/routeAuth.js +11 -0
- package/dist/packages/bunshot-core/src/routeOverrides.d.ts +24 -0
- package/dist/packages/bunshot-core/src/routeOverrides.js +25 -0
- package/dist/packages/bunshot-core/src/routerAdapter.d.ts +6 -0
- package/dist/packages/bunshot-core/src/routerAdapter.js +56 -0
- package/dist/packages/bunshot-core/src/secrets.d.ts +48 -0
- package/dist/packages/bunshot-core/src/secrets.js +8 -0
- package/dist/packages/bunshot-core/src/signing.d.ts +41 -0
- package/dist/packages/bunshot-core/src/signing.js +1 -0
- package/dist/packages/bunshot-core/src/sse.d.ts +36 -0
- package/dist/packages/bunshot-core/src/sse.js +1 -0
- package/dist/packages/bunshot-core/src/storageAdapter.js +1 -0
- package/dist/packages/bunshot-core/src/storeInfra.d.ts +44 -0
- package/dist/packages/bunshot-core/src/storeInfra.js +18 -0
- package/dist/packages/bunshot-core/src/storeType.d.ts +7 -0
- package/dist/packages/bunshot-core/src/storeType.js +1 -0
- package/dist/packages/bunshot-core/src/testing.d.ts +1 -0
- package/dist/packages/bunshot-core/src/testing.js +1 -0
- package/dist/packages/bunshot-core/src/uploadRegistry.d.ts +23 -0
- package/dist/packages/bunshot-core/src/uploadRegistry.js +4 -0
- package/dist/packages/bunshot-core/src/userResolver.d.ts +5 -0
- package/dist/packages/bunshot-core/src/userResolver.js +14 -0
- package/dist/packages/bunshot-core/src/wsMessages.d.ts +42 -0
- package/dist/packages/bunshot-core/src/wsMessages.js +4 -0
- package/dist/packages/bunshot-permissions/src/adapters/memory.d.ts +7 -0
- package/dist/packages/bunshot-permissions/src/adapters/memory.js +73 -0
- package/dist/packages/bunshot-permissions/src/index.d.ts +10 -0
- package/dist/packages/bunshot-permissions/src/index.js +5 -0
- package/dist/packages/bunshot-permissions/src/lib/bootstrap.d.ts +7 -0
- package/dist/packages/bunshot-permissions/src/lib/bootstrap.js +12 -0
- package/dist/packages/bunshot-permissions/src/lib/evaluator.d.ts +10 -0
- package/dist/packages/bunshot-permissions/src/lib/evaluator.js +165 -0
- package/dist/packages/bunshot-permissions/src/lib/registry.d.ts +2 -0
- package/dist/packages/bunshot-permissions/src/lib/registry.js +31 -0
- package/dist/packages/bunshot-permissions/src/lib/validation.d.ts +1 -0
- package/dist/packages/bunshot-permissions/src/lib/validation.js +1 -0
- package/dist/packages/bunshot-permissions/src/types/adapter.d.ts +1 -0
- package/dist/packages/bunshot-permissions/src/types/adapter.js +1 -0
- package/dist/packages/bunshot-permissions/src/types/evaluator.d.ts +1 -0
- package/dist/packages/bunshot-permissions/src/types/evaluator.js +1 -0
- package/dist/packages/bunshot-permissions/src/types/models.d.ts +1 -0
- package/dist/packages/bunshot-permissions/src/types/models.js +1 -0
- package/dist/packages/bunshot-permissions/src/types/registry.d.ts +1 -0
- package/dist/packages/bunshot-permissions/src/types/registry.js +1 -0
- package/dist/packages/bunshot-postgres/src/adapter.d.ts +6 -0
- package/dist/packages/bunshot-postgres/src/adapter.js +794 -0
- package/dist/packages/bunshot-postgres/src/connection.d.ts +15 -0
- package/dist/packages/bunshot-postgres/src/connection.js +16 -0
- package/dist/packages/bunshot-postgres/src/index.d.ts +4 -0
- package/dist/packages/bunshot-postgres/src/index.js +2 -0
- package/dist/packages/bunshot-postgres/src/schema.d.ts +997 -0
- package/dist/packages/bunshot-postgres/src/schema.js +105 -0
- package/dist/src/app.d.ts +230 -0
- package/dist/src/app.js +182 -0
- package/dist/src/cli/commands/init.d.ts +10 -0
- package/dist/src/cli/commands/init.js +709 -0
- package/dist/src/cli/index.d.ts +1 -0
- package/dist/src/cli/index.js +3 -0
- package/dist/src/entrypoints/mongo.d.ts +6 -0
- package/dist/src/entrypoints/mongo.js +4 -0
- package/dist/src/entrypoints/queue.d.ts +2 -0
- package/dist/src/entrypoints/queue.js +1 -0
- package/dist/src/entrypoints/redis.d.ts +1 -0
- package/dist/src/entrypoints/redis.js +1 -0
- package/dist/{adapters → src/framework/adapters}/localStorage.d.ts +1 -1
- package/dist/{adapters → src/framework/adapters}/localStorage.js +10 -10
- package/dist/src/framework/adapters/memoryStorage.d.ts +2 -0
- package/dist/src/framework/adapters/memoryStorage.js +45 -0
- package/dist/{adapters → src/framework/adapters}/s3Storage.d.ts +1 -1
- package/dist/{adapters → src/framework/adapters}/s3Storage.js +12 -12
- package/dist/src/framework/admin/bunshotAccess.d.ts +2 -0
- package/dist/src/framework/admin/bunshotAccess.js +23 -0
- package/dist/src/framework/admin/bunshotUsers.d.ts +2 -0
- package/dist/src/framework/admin/bunshotUsers.js +103 -0
- package/dist/src/framework/admin/index.d.ts +7 -0
- package/dist/src/framework/admin/index.js +21 -0
- package/dist/src/framework/boundaryAdapters/cacheFactories.d.ts +13 -0
- package/dist/src/framework/boundaryAdapters/cacheFactories.js +86 -0
- package/dist/src/framework/boundaryAdapters/index.d.ts +2 -0
- package/dist/src/framework/boundaryAdapters/index.js +1 -0
- package/dist/src/framework/boundaryAdapters.d.ts +17 -0
- package/dist/src/framework/boundaryAdapters.js +62 -0
- package/dist/src/framework/buildContext.d.ts +33 -0
- package/dist/src/framework/buildContext.js +119 -0
- package/dist/src/framework/config/schema.d.ts +447 -0
- package/dist/src/framework/config/schema.js +528 -0
- package/dist/src/framework/createInfrastructure.d.ts +76 -0
- package/dist/src/framework/createInfrastructure.js +221 -0
- package/dist/src/framework/lib/auditLog.d.ts +23 -0
- package/dist/src/framework/lib/auditLog.js +416 -0
- package/dist/src/framework/lib/captcha.d.ts +11 -0
- package/dist/{lib → src/framework/lib}/captcha.js +13 -10
- package/dist/{lib → src/framework/lib}/createDtoMapper.js +4 -4
- package/dist/src/framework/lib/createRoute.d.ts +1 -0
- package/dist/src/framework/lib/createRoute.js +2 -0
- package/dist/{lib → src/framework/lib}/idempotency.d.ts +2 -6
- package/dist/src/framework/lib/idempotency.js +74 -0
- package/dist/src/framework/lib/logger.d.ts +3 -0
- package/dist/src/framework/lib/logger.js +14 -0
- package/dist/src/framework/lib/metrics.d.ts +34 -0
- package/dist/{lib → src/framework/lib}/metrics.js +49 -57
- package/dist/src/framework/lib/pagination.d.ts +42 -0
- package/dist/src/framework/lib/pagination.js +51 -0
- package/dist/src/framework/lib/redisTransport.d.ts +38 -0
- package/dist/src/framework/lib/redisTransport.js +107 -0
- package/dist/src/framework/lib/resolveUserId.d.ts +2 -0
- package/dist/src/framework/lib/resolveUserId.js +5 -0
- package/dist/src/framework/lib/sseCollision.d.ts +6 -0
- package/dist/src/framework/lib/sseCollision.js +26 -0
- package/dist/src/framework/lib/storageAdapter.d.ts +1 -0
- package/dist/src/framework/lib/storageAdapter.js +1 -0
- package/dist/{lib → src/framework/lib}/stripUnreferencedSchemas.js +4 -4
- package/dist/src/framework/lib/tenant.d.ts +21 -0
- package/dist/src/framework/lib/tenant.js +70 -0
- package/dist/{lib → src/framework/lib}/upload.d.ts +11 -10
- package/dist/src/framework/lib/upload.js +132 -0
- package/dist/src/framework/lib/uploadRegistry.d.ts +23 -0
- package/dist/src/framework/lib/uploadRegistry.js +34 -0
- package/dist/{lib → src/framework/lib}/validate.d.ts +1 -1
- package/dist/{lib → src/framework/lib}/validate.js +2 -2
- package/dist/src/framework/lib/ws.d.ts +19 -0
- package/dist/src/framework/lib/ws.js +130 -0
- package/dist/src/framework/lib/wsHeartbeat.d.ts +12 -0
- package/dist/src/framework/lib/wsHeartbeat.js +53 -0
- package/dist/src/framework/lib/wsMessages.d.ts +25 -0
- package/dist/src/framework/lib/wsMessages.js +45 -0
- package/dist/src/framework/lib/wsNamespace.d.ts +17 -0
- package/dist/src/framework/lib/wsNamespace.js +19 -0
- package/dist/src/framework/lib/wsPresence.d.ts +17 -0
- package/dist/src/framework/lib/wsPresence.js +84 -0
- package/dist/src/framework/lib/wsTransport.d.ts +38 -0
- package/dist/src/framework/lib/wsTransport.js +9 -0
- package/dist/{lib → src/framework/lib}/zodToMongoose.d.ts +1 -1
- package/dist/{lib → src/framework/lib}/zodToMongoose.js +11 -11
- package/dist/{middleware → src/framework/middleware}/auditLog.d.ts +4 -3
- package/dist/src/framework/middleware/auditLog.js +42 -0
- package/dist/{middleware → src/framework/middleware}/botProtection.d.ts +2 -2
- package/dist/{middleware → src/framework/middleware}/botProtection.js +8 -9
- package/dist/src/framework/middleware/cacheResponse.d.ts +35 -0
- package/dist/src/framework/middleware/cacheResponse.js +126 -0
- package/dist/{middleware → src/framework/middleware}/captcha.d.ts +2 -3
- package/dist/src/framework/middleware/captcha.js +37 -0
- package/dist/{middleware → src/framework/middleware}/errorHandler.d.ts +1 -1
- package/dist/{middleware → src/framework/middleware}/errorHandler.js +2 -2
- package/dist/src/framework/middleware/index.js +1 -0
- package/dist/{middleware → src/framework/middleware}/logger.d.ts +1 -1
- package/dist/src/framework/middleware/metrics.d.ts +12 -0
- package/dist/src/framework/middleware/metrics.js +26 -0
- package/dist/{middleware → src/framework/middleware}/rateLimit.d.ts +2 -2
- package/dist/src/framework/middleware/rateLimit.js +22 -0
- package/dist/src/framework/middleware/requestId.d.ts +3 -0
- package/dist/{middleware → src/framework/middleware}/requestId.js +2 -2
- package/dist/{middleware → src/framework/middleware}/requestLogger.d.ts +3 -3
- package/dist/{middleware → src/framework/middleware}/requestLogger.js +17 -12
- package/dist/{middleware → src/framework/middleware}/requestSigning.d.ts +2 -2
- package/dist/{middleware → src/framework/middleware}/requestSigning.js +18 -20
- package/dist/src/framework/middleware/tenant.d.ts +14 -0
- package/dist/{middleware → src/framework/middleware}/tenant.js +31 -27
- package/dist/src/framework/middleware/upload.d.ts +5 -0
- package/dist/{middleware → src/framework/middleware}/upload.js +4 -4
- package/dist/{middleware → src/framework/middleware}/webhookAuth.d.ts +3 -3
- package/dist/{middleware → src/framework/middleware}/webhookAuth.js +11 -12
- package/dist/src/framework/models/AuditLog.d.ts +21 -0
- package/dist/src/framework/models/AuditLog.js +31 -0
- package/dist/src/framework/mountMiddleware.d.ts +91 -0
- package/dist/src/framework/mountMiddleware.js +128 -0
- package/dist/src/framework/mountOptionalEndpoints.d.ts +103 -0
- package/dist/src/framework/mountOptionalEndpoints.js +47 -0
- package/dist/src/framework/mountRoutes.d.ts +21 -0
- package/dist/src/framework/mountRoutes.js +144 -0
- package/dist/src/framework/persistence/cronRegistry.d.ts +28 -0
- package/dist/src/framework/persistence/cronRegistry.js +139 -0
- package/dist/src/framework/persistence/idempotency.d.ts +26 -0
- package/dist/src/framework/persistence/idempotency.js +178 -0
- package/dist/src/framework/persistence/index.d.ts +6 -0
- package/dist/src/framework/persistence/index.js +8 -0
- package/dist/src/framework/persistence/storeInfra.d.ts +9 -0
- package/dist/src/framework/persistence/storeInfra.js +1 -0
- package/dist/src/framework/persistence/uploadRegistry.d.ts +35 -0
- package/dist/src/framework/persistence/uploadRegistry.js +235 -0
- package/dist/src/framework/persistence/wsMessages.d.ts +22 -0
- package/dist/src/framework/persistence/wsMessages.js +296 -0
- package/dist/src/framework/preloadSchemas.d.ts +24 -0
- package/dist/src/framework/preloadSchemas.js +42 -0
- package/dist/src/framework/registerBoundaryAdapters.d.ts +23 -0
- package/dist/src/framework/registerBoundaryAdapters.js +46 -0
- package/dist/src/framework/routes/admin.d.ts +9 -0
- package/dist/src/framework/routes/admin.js +361 -0
- package/dist/src/framework/routes/health.d.ts +1 -0
- package/dist/src/framework/routes/health.js +21 -0
- package/dist/src/framework/routes/home.d.ts +1 -0
- package/dist/src/framework/routes/home.js +18 -0
- package/dist/src/framework/routes/jobs.d.ts +3 -0
- package/dist/{routes → src/framework/routes}/jobs.js +128 -103
- package/dist/src/framework/routes/metrics.d.ts +10 -0
- package/dist/src/framework/routes/metrics.js +57 -0
- package/dist/{routes → src/framework/routes}/uploads.d.ts +3 -3
- package/dist/src/framework/routes/uploads.js +262 -0
- package/dist/src/framework/runPluginLifecycle.d.ts +27 -0
- package/dist/src/framework/runPluginLifecycle.js +121 -0
- package/dist/src/framework/secrets/frameworkSecretSchema.d.ts +58 -0
- package/dist/src/framework/secrets/frameworkSecretSchema.js +20 -0
- package/dist/src/framework/secrets/index.d.ts +9 -0
- package/dist/src/framework/secrets/index.js +7 -0
- package/dist/src/framework/secrets/providers/envProvider.d.ts +15 -0
- package/dist/src/framework/secrets/providers/envProvider.js +18 -0
- package/dist/src/framework/secrets/providers/fileProvider.d.ts +8 -0
- package/dist/src/framework/secrets/providers/fileProvider.js +82 -0
- package/dist/src/framework/secrets/providers/ssmProvider.d.ts +20 -0
- package/dist/src/framework/secrets/providers/ssmProvider.js +127 -0
- package/dist/src/framework/secrets/resolveSecretBundle.d.ts +53 -0
- package/dist/src/framework/secrets/resolveSecretBundle.js +84 -0
- package/dist/src/framework/secrets/resolveSecrets.d.ts +18 -0
- package/dist/src/framework/secrets/resolveSecrets.js +34 -0
- package/dist/src/framework/sse/index.d.ts +21 -0
- package/dist/src/framework/sse/index.js +109 -0
- package/dist/src/framework/ws/index.d.ts +11 -0
- package/dist/src/framework/ws/index.js +8 -0
- package/dist/src/index.d.ts +87 -0
- package/dist/src/index.js +58 -0
- package/dist/src/lib/appConfig.d.ts +7 -0
- package/dist/src/lib/appConfig.js +27 -0
- package/dist/src/lib/appMeta.d.ts +7 -0
- package/dist/src/lib/appMeta.js +3 -0
- package/dist/src/lib/authConfig.d.ts +532 -0
- package/dist/{lib/appConfig.js → src/lib/authConfig.js} +75 -17
- package/dist/{lib → src/lib}/context.d.ts +6 -12
- package/dist/{lib → src/lib}/context.js +5 -5
- package/dist/src/lib/logger.d.ts +1 -0
- package/dist/src/lib/logger.js +1 -0
- package/dist/src/lib/mongo.d.ts +58 -0
- package/dist/src/lib/mongo.js +96 -0
- package/dist/src/lib/queue.d.ts +72 -0
- package/dist/src/lib/queue.js +152 -0
- package/dist/src/lib/redis.d.ts +28 -0
- package/dist/src/lib/redis.js +72 -0
- package/dist/{lib → src/lib}/signing.d.ts +2 -2
- package/dist/src/lib/signing.js +210 -0
- package/dist/src/lib/signingConfig.d.ts +40 -0
- package/dist/src/lib/signingConfig.js +28 -0
- package/dist/src/server.d.ts +146 -0
- package/dist/src/server.js +469 -0
- package/dist/src/shared/lib/HttpError.d.ts +1 -0
- package/dist/src/shared/lib/HttpError.js +2 -0
- package/dist/src/shared/lib/constants.d.ts +10 -0
- package/dist/src/shared/lib/crypto.d.ts +43 -0
- package/dist/src/shared/lib/crypto.js +74 -0
- package/dist/src/shared/lib/signing.d.ts +52 -0
- package/dist/{lib → src/shared/lib}/signing.js +35 -8
- package/dist/src/testing.d.ts +34 -0
- package/dist/src/testing.js +93 -0
- package/package.json +60 -24
- package/dist/adapters/memoryAuth.d.ts +0 -52
- package/dist/adapters/memoryAuth.js +0 -749
- package/dist/adapters/memoryStorage.d.ts +0 -3
- package/dist/adapters/memoryStorage.js +0 -44
- package/dist/adapters/mongoAuth.d.ts +0 -2
- package/dist/adapters/mongoAuth.js +0 -403
- package/dist/adapters/sqliteAuth.d.ts +0 -72
- package/dist/adapters/sqliteAuth.js +0 -858
- package/dist/app.d.ts +0 -559
- package/dist/app.js +0 -651
- package/dist/entrypoints/mongo.d.ts +0 -5
- package/dist/entrypoints/mongo.js +0 -4
- package/dist/entrypoints/queue.d.ts +0 -2
- package/dist/entrypoints/queue.js +0 -1
- package/dist/entrypoints/redis.d.ts +0 -1
- package/dist/entrypoints/redis.js +0 -1
- package/dist/index.d.ts +0 -117
- package/dist/index.js +0 -88
- package/dist/lib/appConfig.d.ts +0 -275
- package/dist/lib/auditLog.d.ts +0 -58
- package/dist/lib/auditLog.js +0 -218
- package/dist/lib/authAdapter.d.ts +0 -246
- package/dist/lib/authAdapter.js +0 -7
- package/dist/lib/authRateLimit.d.ts +0 -13
- package/dist/lib/authRateLimit.js +0 -117
- package/dist/lib/clientIp.d.ts +0 -14
- package/dist/lib/credentialStuffing.d.ts +0 -31
- package/dist/lib/credentialStuffing.js +0 -77
- package/dist/lib/crypto.d.ts +0 -11
- package/dist/lib/crypto.js +0 -22
- package/dist/lib/deletionCancelToken.d.ts +0 -12
- package/dist/lib/deletionCancelToken.js +0 -88
- package/dist/lib/emailVerification.d.ts +0 -19
- package/dist/lib/emailVerification.js +0 -129
- package/dist/lib/fingerprint.js +0 -36
- package/dist/lib/idempotency.js +0 -182
- package/dist/lib/jwks.d.ts +0 -25
- package/dist/lib/jwks.js +0 -51
- package/dist/lib/jwt.d.ts +0 -15
- package/dist/lib/jwt.js +0 -111
- package/dist/lib/metrics.d.ts +0 -14
- package/dist/lib/mfaChallenge.d.ts +0 -55
- package/dist/lib/mfaChallenge.js +0 -398
- package/dist/lib/mongo.d.ts +0 -39
- package/dist/lib/mongo.js +0 -124
- package/dist/lib/oauth.d.ts +0 -40
- package/dist/lib/oauth.js +0 -101
- package/dist/lib/oauthCode.d.ts +0 -15
- package/dist/lib/oauthCode.js +0 -95
- package/dist/lib/pagination.d.ts +0 -119
- package/dist/lib/pagination.js +0 -166
- package/dist/lib/queue.d.ts +0 -37
- package/dist/lib/queue.js +0 -117
- package/dist/lib/redis.d.ts +0 -9
- package/dist/lib/redis.js +0 -61
- package/dist/lib/resetPassword.d.ts +0 -12
- package/dist/lib/resetPassword.js +0 -93
- package/dist/lib/roles.d.ts +0 -7
- package/dist/lib/roles.js +0 -49
- package/dist/lib/saml.d.ts +0 -25
- package/dist/lib/saml.js +0 -64
- package/dist/lib/securityEvents.d.ts +0 -28
- package/dist/lib/securityEvents.js +0 -26
- package/dist/lib/session.d.ts +0 -49
- package/dist/lib/session.js +0 -597
- package/dist/lib/tenant.d.ts +0 -15
- package/dist/lib/tenant.js +0 -65
- package/dist/lib/upload.js +0 -112
- package/dist/lib/uploadRegistry.d.ts +0 -18
- package/dist/lib/uploadRegistry.js +0 -83
- package/dist/lib/ws.d.ts +0 -22
- package/dist/lib/ws.js +0 -96
- package/dist/lib/wsHeartbeat.d.ts +0 -12
- package/dist/lib/wsHeartbeat.js +0 -57
- package/dist/lib/wsMessages.d.ts +0 -40
- package/dist/lib/wsMessages.js +0 -330
- package/dist/lib/wsPresence.d.ts +0 -25
- package/dist/lib/wsPresence.js +0 -99
- package/dist/middleware/auditLog.js +0 -39
- package/dist/middleware/bearerAuth.d.ts +0 -2
- package/dist/middleware/bearerAuth.js +0 -11
- package/dist/middleware/cacheResponse.d.ts +0 -15
- package/dist/middleware/cacheResponse.js +0 -178
- package/dist/middleware/captcha.js +0 -36
- package/dist/middleware/csrf.js +0 -129
- package/dist/middleware/identify.d.ts +0 -3
- package/dist/middleware/identify.js +0 -122
- package/dist/middleware/index.js +0 -1
- package/dist/middleware/metrics.d.ts +0 -9
- package/dist/middleware/metrics.js +0 -26
- package/dist/middleware/rateLimit.js +0 -22
- package/dist/middleware/requestId.d.ts +0 -3
- package/dist/middleware/scimAuth.d.ts +0 -8
- package/dist/middleware/scimAuth.js +0 -29
- package/dist/middleware/tenant.d.ts +0 -5
- package/dist/middleware/upload.d.ts +0 -5
- package/dist/middleware/userAuth.d.ts +0 -3
- package/dist/middleware/userAuth.js +0 -6
- package/dist/models/AuditLog.d.ts +0 -30
- package/dist/models/AuditLog.js +0 -39
- package/dist/models/AuthUser.js +0 -55
- package/dist/models/Group.d.ts +0 -21
- package/dist/models/Group.js +0 -28
- package/dist/models/GroupMembership.js +0 -25
- package/dist/models/TenantRole.d.ts +0 -15
- package/dist/models/TenantRole.js +0 -23
- package/dist/routes/auth.d.ts +0 -12
- package/dist/routes/auth.js +0 -744
- package/dist/routes/groups.js +0 -346
- package/dist/routes/health.d.ts +0 -1
- package/dist/routes/health.js +0 -22
- package/dist/routes/home.d.ts +0 -1
- package/dist/routes/home.js +0 -16
- package/dist/routes/jobs.d.ts +0 -2
- package/dist/routes/m2m.d.ts +0 -2
- package/dist/routes/m2m.js +0 -72
- package/dist/routes/metrics.d.ts +0 -8
- package/dist/routes/metrics.js +0 -55
- package/dist/routes/mfa.d.ts +0 -5
- package/dist/routes/mfa.js +0 -628
- package/dist/routes/oauth.d.ts +0 -2
- package/dist/routes/oauth.js +0 -520
- package/dist/routes/oidc.d.ts +0 -2
- package/dist/routes/oidc.js +0 -29
- package/dist/routes/passkey.d.ts +0 -1
- package/dist/routes/passkey.js +0 -157
- package/dist/routes/saml.d.ts +0 -2
- package/dist/routes/saml.js +0 -86
- package/dist/routes/scim.d.ts +0 -2
- package/dist/routes/scim.js +0 -255
- package/dist/routes/uploads.js +0 -227
- package/dist/schemas/auth.js +0 -30
- package/dist/server.d.ts +0 -57
- package/dist/server.js +0 -112
- package/dist/services/auth.d.ts +0 -29
- package/dist/services/auth.js +0 -238
- package/dist/ws/index.d.ts +0 -10
- package/dist/ws/index.js +0 -39
- package/docs/sections/adding-middleware/full.md +0 -35
- package/docs/sections/adding-models/full.md +0 -125
- package/docs/sections/adding-models/overview.md +0 -13
- package/docs/sections/adding-routes/full.md +0 -182
- package/docs/sections/adding-routes/overview.md +0 -23
- package/docs/sections/auth-flow/full.md +0 -790
- package/docs/sections/auth-flow/overview.md +0 -10
- package/docs/sections/auth-security-examples/full.md +0 -388
- package/docs/sections/authentication/full.md +0 -130
- package/docs/sections/authentication/overview.md +0 -5
- package/docs/sections/cli/full.md +0 -42
- package/docs/sections/configuration/full.md +0 -172
- package/docs/sections/configuration/overview.md +0 -18
- package/docs/sections/configuration-example/full.md +0 -117
- package/docs/sections/configuration-example/overview.md +0 -30
- package/docs/sections/documentation/full.md +0 -171
- package/docs/sections/environment-variables/full.md +0 -55
- package/docs/sections/exports/full.md +0 -123
- package/docs/sections/extending-context/full.md +0 -59
- package/docs/sections/header.md +0 -3
- package/docs/sections/installation/full.md +0 -6
- package/docs/sections/jobs/full.md +0 -140
- package/docs/sections/jobs/overview.md +0 -15
- package/docs/sections/logging/full.md +0 -83
- package/docs/sections/metrics/full.md +0 -131
- package/docs/sections/mongodb-connections/full.md +0 -45
- package/docs/sections/mongodb-connections/overview.md +0 -7
- package/docs/sections/multi-tenancy/full.md +0 -66
- package/docs/sections/multi-tenancy/overview.md +0 -15
- package/docs/sections/oauth/full.md +0 -189
- package/docs/sections/oauth/overview.md +0 -16
- package/docs/sections/package-development/full.md +0 -7
- package/docs/sections/pagination/full.md +0 -93
- package/docs/sections/passkey-login/full.md +0 -90
- package/docs/sections/passkey-login/overview.md +0 -1
- package/docs/sections/peer-dependencies/full.md +0 -47
- package/docs/sections/quick-start/full.md +0 -43
- package/docs/sections/response-caching/full.md +0 -117
- package/docs/sections/response-caching/overview.md +0 -13
- package/docs/sections/roles/full.md +0 -225
- package/docs/sections/roles/overview.md +0 -14
- package/docs/sections/running-without-redis/full.md +0 -16
- package/docs/sections/running-without-redis-or-mongodb/full.md +0 -60
- package/docs/sections/signing/full.md +0 -203
- package/docs/sections/stack/full.md +0 -10
- package/docs/sections/uploads/full.md +0 -208
- package/docs/sections/versioning/full.md +0 -85
- package/docs/sections/webhook-auth/full.md +0 -100
- package/docs/sections/websocket/full.md +0 -196
- package/docs/sections/websocket/overview.md +0 -5
- package/docs/sections/websocket-rooms/full.md +0 -102
- package/docs/sections/websocket-rooms/overview.md +0 -5
- /package/dist/{lib/storageAdapter.js → packages/bunshot-admin/src/types/env.js} +0 -0
- /package/dist/{lib → packages/bunshot-auth/src/lib}/fingerprint.d.ts +0 -0
- /package/dist/{lib → packages/bunshot-auth/src/lib}/logger.d.ts +0 -0
- /package/dist/{lib → packages/bunshot-core/src}/constants.d.ts +0 -0
- /package/dist/{lib → packages/bunshot-core/src}/storageAdapter.d.ts +0 -0
- /package/dist/{lib → src/framework/lib}/createDtoMapper.d.ts +0 -0
- /package/dist/{lib → src/framework/lib}/stripUnreferencedSchemas.d.ts +0 -0
- /package/dist/{middleware → src/framework/middleware}/cors.d.ts +0 -0
- /package/dist/{middleware → src/framework/middleware}/cors.js +0 -0
- /package/dist/{middleware → src/framework/middleware}/index.d.ts +0 -0
- /package/dist/{middleware → src/framework/middleware}/logger.js +0 -0
- /package/dist/{lib → src/shared/lib}/constants.js +0 -0
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { HttpError } from
|
|
3
|
-
import {
|
|
4
|
-
import { createMfaChallenge } from "../lib/mfaChallenge";
|
|
1
|
+
import { createMfaChallenge } from '../lib/mfaChallenge';
|
|
2
|
+
import { HttpError } from '../../../bunshot-core/src/index.js';
|
|
3
|
+
import { decryptField, encryptField, isEncryptedField, sha256, timingSafeEqual, } from '../../../bunshot-core/src/index.js';
|
|
5
4
|
// Lazy-load otpauth to keep it as an optional peer dependency
|
|
6
|
-
let _otpauth = null;
|
|
7
5
|
async function getOtpAuth() {
|
|
8
|
-
|
|
9
|
-
_otpauth = await import("otpauth");
|
|
10
|
-
return _otpauth;
|
|
6
|
+
return import('otpauth');
|
|
11
7
|
}
|
|
12
|
-
import { sha256, timingSafeEqual } from "../lib/crypto";
|
|
13
8
|
function generateRandomCode(length) {
|
|
14
|
-
const chars =
|
|
15
|
-
|
|
9
|
+
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; // no ambiguous chars: I/1/O/0
|
|
10
|
+
const charLen = chars.length; // 31
|
|
11
|
+
const maxUnbiased = 248; // largest multiple of 31 below 256 (31 * 8 = 248)
|
|
12
|
+
let code = '';
|
|
16
13
|
const bytes = crypto.getRandomValues(new Uint8Array(length));
|
|
17
14
|
for (let i = 0; i < length; i++) {
|
|
18
|
-
|
|
15
|
+
let byte = bytes[i];
|
|
16
|
+
while (byte >= maxUnbiased) {
|
|
17
|
+
byte = crypto.getRandomValues(new Uint8Array(1))[0];
|
|
18
|
+
}
|
|
19
|
+
code += chars[byte % charLen];
|
|
19
20
|
}
|
|
20
21
|
return code;
|
|
21
22
|
}
|
|
22
|
-
function generateRecoveryCodes() {
|
|
23
|
-
const count =
|
|
23
|
+
function generateRecoveryCodes(runtime) {
|
|
24
|
+
const count = runtime.config.mfa?.recoveryCodes ?? 10;
|
|
24
25
|
const plainCodes = [];
|
|
25
26
|
const hashedCodes = [];
|
|
26
27
|
for (let i = 0; i < count; i++) {
|
|
@@ -30,96 +31,118 @@ function generateRecoveryCodes() {
|
|
|
30
31
|
}
|
|
31
32
|
return { plainCodes, hashedCodes };
|
|
32
33
|
}
|
|
33
|
-
export const setupMfa = async (userId) => {
|
|
34
|
-
const adapter =
|
|
34
|
+
export const setupMfa = async (userId, runtime) => {
|
|
35
|
+
const { adapter, config } = runtime;
|
|
35
36
|
if (!adapter.setMfaSecret)
|
|
36
|
-
throw new HttpError(501,
|
|
37
|
+
throw new HttpError(501, 'Auth adapter does not support MFA');
|
|
37
38
|
const otpauth = await getOtpAuth();
|
|
38
39
|
const secret = new otpauth.Secret();
|
|
40
|
+
const mfaCfg = config.mfa;
|
|
39
41
|
const totp = new otpauth.TOTP({
|
|
40
|
-
issuer:
|
|
42
|
+
issuer: mfaCfg?.issuer ?? config.appName,
|
|
41
43
|
label: userId,
|
|
42
|
-
algorithm:
|
|
43
|
-
digits:
|
|
44
|
-
period:
|
|
44
|
+
algorithm: mfaCfg?.algorithm ?? 'SHA1',
|
|
45
|
+
digits: mfaCfg?.digits ?? 6,
|
|
46
|
+
period: mfaCfg?.period ?? 30,
|
|
45
47
|
secret,
|
|
46
48
|
});
|
|
47
49
|
// Store the secret but don't enable MFA yet — user must confirm with a code
|
|
48
|
-
|
|
50
|
+
// Encrypt at rest when encryption keys are available; store plaintext in dev otherwise.
|
|
51
|
+
const deks = [...runtime.dataEncryptionKeys];
|
|
52
|
+
const storedSecret = deks.length > 0 ? await encryptField(secret.base32, deks) : secret.base32;
|
|
53
|
+
await adapter.setMfaSecret(userId, storedSecret);
|
|
49
54
|
return {
|
|
50
55
|
secret: secret.base32,
|
|
51
56
|
uri: totp.toString(),
|
|
52
57
|
};
|
|
53
58
|
};
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Resolve a stored MFA secret: decrypt it if it looks like an encrypted ciphertext
|
|
61
|
+
* (produced by encryptField), otherwise return as-is (plaintext — allowed in dev).
|
|
62
|
+
*/
|
|
63
|
+
async function resolveStoredSecret(stored, runtime) {
|
|
64
|
+
if (isEncryptedField(stored)) {
|
|
65
|
+
const deks = [...runtime.dataEncryptionKeys];
|
|
66
|
+
if (deks.length === 0) {
|
|
67
|
+
throw new HttpError(500, 'TOTP secret is encrypted but BUNSHOT_DATA_ENCRYPTION_KEY is not set');
|
|
68
|
+
}
|
|
69
|
+
return decryptField(stored, deks);
|
|
70
|
+
}
|
|
71
|
+
return stored;
|
|
72
|
+
}
|
|
73
|
+
export const verifySetup = async (userId, code, runtime) => {
|
|
74
|
+
const { adapter, config } = runtime;
|
|
56
75
|
if (!adapter.getMfaSecret || !adapter.setMfaEnabled || !adapter.setRecoveryCodes) {
|
|
57
|
-
throw new HttpError(501,
|
|
76
|
+
throw new HttpError(501, 'Auth adapter does not support MFA');
|
|
58
77
|
}
|
|
59
|
-
const
|
|
60
|
-
if (!
|
|
61
|
-
throw new HttpError(400,
|
|
78
|
+
const storedSecretStr = await adapter.getMfaSecret(userId);
|
|
79
|
+
if (!storedSecretStr)
|
|
80
|
+
throw new HttpError(400, 'MFA setup not initiated. Call POST /auth/mfa/setup first.');
|
|
81
|
+
const secretStr = await resolveStoredSecret(storedSecretStr, runtime);
|
|
82
|
+
const mfaCfg = config.mfa;
|
|
62
83
|
const otpauth = await getOtpAuth();
|
|
63
84
|
const totp = new otpauth.TOTP({
|
|
64
|
-
issuer:
|
|
65
|
-
algorithm:
|
|
66
|
-
digits:
|
|
67
|
-
period:
|
|
85
|
+
issuer: mfaCfg?.issuer ?? config.appName,
|
|
86
|
+
algorithm: mfaCfg?.algorithm ?? 'SHA1',
|
|
87
|
+
digits: mfaCfg?.digits ?? 6,
|
|
88
|
+
period: mfaCfg?.period ?? 30,
|
|
68
89
|
secret: otpauth.Secret.fromBase32(secretStr),
|
|
69
90
|
});
|
|
70
91
|
const delta = totp.validate({ token: code, window: 1 });
|
|
71
92
|
if (delta === null)
|
|
72
|
-
throw new HttpError(401,
|
|
93
|
+
throw new HttpError(401, 'Invalid TOTP code');
|
|
73
94
|
// Generate recovery codes (regenerates if enabling a second method)
|
|
74
|
-
const { plainCodes, hashedCodes } = generateRecoveryCodes();
|
|
95
|
+
const { plainCodes, hashedCodes } = generateRecoveryCodes(runtime);
|
|
75
96
|
await adapter.setRecoveryCodes(userId, hashedCodes);
|
|
76
97
|
await adapter.setMfaEnabled(userId, true);
|
|
77
98
|
// Add "totp" to mfaMethods
|
|
78
99
|
if (adapter.getMfaMethods && adapter.setMfaMethods) {
|
|
79
100
|
const methods = await adapter.getMfaMethods(userId);
|
|
80
|
-
if (!methods.includes(
|
|
81
|
-
await adapter.setMfaMethods(userId, [...methods,
|
|
101
|
+
if (!methods.includes('totp')) {
|
|
102
|
+
await adapter.setMfaMethods(userId, [...methods, 'totp']);
|
|
82
103
|
}
|
|
83
104
|
}
|
|
84
105
|
return plainCodes;
|
|
85
106
|
};
|
|
86
|
-
export const verifyTotp = async (userId, code) => {
|
|
87
|
-
const adapter =
|
|
107
|
+
export const verifyTotp = async (userId, code, runtime) => {
|
|
108
|
+
const { adapter, config } = runtime;
|
|
88
109
|
if (!adapter.getMfaSecret)
|
|
89
|
-
throw new HttpError(501,
|
|
90
|
-
const
|
|
91
|
-
if (!
|
|
110
|
+
throw new HttpError(501, 'Auth adapter does not support MFA');
|
|
111
|
+
const storedSecretStr = await adapter.getMfaSecret(userId);
|
|
112
|
+
if (!storedSecretStr)
|
|
92
113
|
return false;
|
|
114
|
+
const secretStr = await resolveStoredSecret(storedSecretStr, runtime);
|
|
115
|
+
const mfaCfg = config.mfa;
|
|
93
116
|
const otpauth = await getOtpAuth();
|
|
94
117
|
const totp = new otpauth.TOTP({
|
|
95
|
-
issuer:
|
|
96
|
-
algorithm:
|
|
97
|
-
digits:
|
|
98
|
-
period:
|
|
118
|
+
issuer: mfaCfg?.issuer ?? config.appName,
|
|
119
|
+
algorithm: mfaCfg?.algorithm ?? 'SHA1',
|
|
120
|
+
digits: mfaCfg?.digits ?? 6,
|
|
121
|
+
period: mfaCfg?.period ?? 30,
|
|
99
122
|
secret: otpauth.Secret.fromBase32(secretStr),
|
|
100
123
|
});
|
|
101
124
|
return totp.validate({ token: code, window: 1 }) !== null;
|
|
102
125
|
};
|
|
103
|
-
export const verifyRecoveryCode = async (userId, code) => {
|
|
104
|
-
const adapter =
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
126
|
+
export const verifyRecoveryCode = async (userId, code, runtime) => {
|
|
127
|
+
const { adapter } = runtime;
|
|
128
|
+
// consumeRecoveryCode is a required method on all adapters that support MFA.
|
|
129
|
+
// It atomically finds and removes the code in a single operation, eliminating the race
|
|
130
|
+
// condition where two concurrent requests could both match the same code.
|
|
131
|
+
// Note: timing is now at the DB level rather than using timingSafeEqual in application code.
|
|
132
|
+
// This is acceptable — the code is SHA-256 hashed before storage, so constant-time
|
|
133
|
+
// comparison in app code was only preventing hash enumeration, not timing-based attacks
|
|
134
|
+
// on the plaintext (which is already protected by the hash itself).
|
|
108
135
|
const hashedInput = sha256(code.toUpperCase());
|
|
109
|
-
|
|
110
|
-
if (!match)
|
|
111
|
-
return false;
|
|
112
|
-
await adapter.removeRecoveryCode(userId, match);
|
|
113
|
-
return true;
|
|
136
|
+
return adapter.consumeRecoveryCode(userId, hashedInput);
|
|
114
137
|
};
|
|
115
|
-
export const disableMfa = async (userId, code) => {
|
|
116
|
-
const adapter =
|
|
138
|
+
export const disableMfa = async (userId, code, runtime) => {
|
|
139
|
+
const { adapter } = runtime;
|
|
117
140
|
if (!adapter.setMfaEnabled || !adapter.setMfaSecret || !adapter.setRecoveryCodes) {
|
|
118
|
-
throw new HttpError(501,
|
|
141
|
+
throw new HttpError(501, 'Auth adapter does not support MFA');
|
|
119
142
|
}
|
|
120
|
-
const valid = await verifyTotp(userId, code);
|
|
143
|
+
const valid = await verifyTotp(userId, code, runtime);
|
|
121
144
|
if (!valid)
|
|
122
|
-
throw new HttpError(401,
|
|
145
|
+
throw new HttpError(401, 'Invalid TOTP code');
|
|
123
146
|
await adapter.setMfaEnabled(userId, false);
|
|
124
147
|
await adapter.setMfaSecret(userId, null);
|
|
125
148
|
await adapter.setRecoveryCodes(userId, []);
|
|
@@ -128,14 +151,14 @@ export const disableMfa = async (userId, code) => {
|
|
|
128
151
|
await adapter.setMfaMethods(userId, []);
|
|
129
152
|
}
|
|
130
153
|
};
|
|
131
|
-
export const regenerateRecoveryCodes = async (userId, code) => {
|
|
132
|
-
const adapter =
|
|
154
|
+
export const regenerateRecoveryCodes = async (userId, code, runtime) => {
|
|
155
|
+
const { adapter } = runtime;
|
|
133
156
|
if (!adapter.setRecoveryCodes)
|
|
134
|
-
throw new HttpError(501,
|
|
135
|
-
const valid = await verifyTotp(userId, code);
|
|
157
|
+
throw new HttpError(501, 'Auth adapter does not support MFA');
|
|
158
|
+
const valid = await verifyTotp(userId, code, runtime);
|
|
136
159
|
if (!valid)
|
|
137
|
-
throw new HttpError(401,
|
|
138
|
-
const { plainCodes, hashedCodes } = generateRecoveryCodes();
|
|
160
|
+
throw new HttpError(401, 'Invalid TOTP code');
|
|
161
|
+
const { plainCodes, hashedCodes } = generateRecoveryCodes(runtime);
|
|
139
162
|
await adapter.setRecoveryCodes(userId, hashedCodes);
|
|
140
163
|
return plainCodes;
|
|
141
164
|
};
|
|
@@ -143,12 +166,17 @@ export const regenerateRecoveryCodes = async (userId, code) => {
|
|
|
143
166
|
// Email OTP
|
|
144
167
|
// ---------------------------------------------------------------------------
|
|
145
168
|
/** Generate a cryptographically random numeric OTP code. Returns { code, hash }. */
|
|
146
|
-
export const generateEmailOtpCode = (length) => {
|
|
147
|
-
const len = length ??
|
|
169
|
+
export const generateEmailOtpCode = (runtime, length) => {
|
|
170
|
+
const len = length ?? runtime.config.mfa?.emailOtp?.codeLength ?? 6;
|
|
171
|
+
const maxUnbiased = 250; // largest multiple of 10 below 256 (10 * 25 = 250)
|
|
148
172
|
const bytes = crypto.getRandomValues(new Uint8Array(len));
|
|
149
|
-
let code =
|
|
173
|
+
let code = '';
|
|
150
174
|
for (let i = 0; i < len; i++) {
|
|
151
|
-
|
|
175
|
+
let byte = bytes[i];
|
|
176
|
+
while (byte >= maxUnbiased) {
|
|
177
|
+
byte = crypto.getRandomValues(new Uint8Array(1))[0];
|
|
178
|
+
}
|
|
179
|
+
code += (byte % 10).toString();
|
|
152
180
|
}
|
|
153
181
|
return { code, hash: sha256(code) };
|
|
154
182
|
};
|
|
@@ -160,59 +188,59 @@ export const verifyEmailOtp = (emailOtpHash, code) => {
|
|
|
160
188
|
* Initiate email OTP setup: sends a verification code to the user's email.
|
|
161
189
|
* Returns a setup challenge token that must be confirmed via confirmEmailOtp.
|
|
162
190
|
*/
|
|
163
|
-
export const initiateEmailOtp = async (userId) => {
|
|
164
|
-
const adapter =
|
|
165
|
-
const emailOtpConfig =
|
|
191
|
+
export const initiateEmailOtp = async (userId, runtime) => {
|
|
192
|
+
const { adapter, eventBus, config } = runtime;
|
|
193
|
+
const emailOtpConfig = config.mfa?.emailOtp ?? null;
|
|
166
194
|
if (!emailOtpConfig)
|
|
167
|
-
throw new HttpError(501,
|
|
195
|
+
throw new HttpError(501, 'Email OTP is not configured');
|
|
168
196
|
const user = adapter.getUser ? await adapter.getUser(userId) : null;
|
|
169
197
|
if (!user?.email)
|
|
170
|
-
throw new HttpError(400,
|
|
171
|
-
const { code, hash } = generateEmailOtpCode();
|
|
172
|
-
|
|
198
|
+
throw new HttpError(400, 'No email address on account');
|
|
199
|
+
const { code, hash } = generateEmailOtpCode(runtime);
|
|
200
|
+
eventBus.emit('auth:delivery.email_otp', { email: user.email, code });
|
|
173
201
|
// Store the hash in a challenge token for verification
|
|
174
|
-
const setupToken = await createMfaChallenge(userId, { emailOtpHash: hash });
|
|
202
|
+
const setupToken = await createMfaChallenge(runtime.repos.mfaChallenge, userId, { emailOtpHash: hash }, config);
|
|
175
203
|
return setupToken;
|
|
176
204
|
};
|
|
177
205
|
/**
|
|
178
206
|
* Confirm email OTP setup: verifies the code sent during initiateEmailOtp.
|
|
179
207
|
* Enables email OTP as an MFA method. Returns recovery codes if MFA was not previously active.
|
|
180
208
|
*/
|
|
181
|
-
export const confirmEmailOtp = async (userId, setupToken, code) => {
|
|
182
|
-
const adapter =
|
|
209
|
+
export const confirmEmailOtp = async (userId, setupToken, code, runtime) => {
|
|
210
|
+
const { adapter } = runtime;
|
|
183
211
|
if (!adapter.setMfaEnabled || !adapter.setRecoveryCodes) {
|
|
184
|
-
throw new HttpError(501,
|
|
212
|
+
throw new HttpError(501, 'Auth adapter does not support MFA');
|
|
185
213
|
}
|
|
186
214
|
// Import consumeMfaChallenge here to avoid circular dependency issues at module level
|
|
187
|
-
const { consumeMfaChallenge } = await import(
|
|
188
|
-
const challenge = await consumeMfaChallenge(setupToken);
|
|
215
|
+
const { consumeMfaChallenge } = await import('../lib/mfaChallenge');
|
|
216
|
+
const challenge = await consumeMfaChallenge(runtime.repos.mfaChallenge, setupToken);
|
|
189
217
|
if (!challenge)
|
|
190
|
-
throw new HttpError(401,
|
|
218
|
+
throw new HttpError(401, 'Invalid or expired setup token');
|
|
191
219
|
if (challenge.userId !== userId)
|
|
192
|
-
throw new HttpError(401,
|
|
220
|
+
throw new HttpError(401, 'Token does not match user');
|
|
193
221
|
if (!challenge.emailOtpHash)
|
|
194
|
-
throw new HttpError(400,
|
|
222
|
+
throw new HttpError(400, 'Invalid setup token — no OTP hash');
|
|
195
223
|
if (!verifyEmailOtp(challenge.emailOtpHash, code)) {
|
|
196
|
-
throw new HttpError(401,
|
|
224
|
+
throw new HttpError(401, 'Invalid verification code');
|
|
197
225
|
}
|
|
198
226
|
// Check if MFA was already active
|
|
199
227
|
const wasEnabled = adapter.isMfaEnabled ? await adapter.isMfaEnabled(userId) : false;
|
|
200
228
|
// Add "emailOtp" to mfaMethods
|
|
201
229
|
if (adapter.getMfaMethods && adapter.setMfaMethods) {
|
|
202
230
|
const methods = await adapter.getMfaMethods(userId);
|
|
203
|
-
if (!methods.includes(
|
|
204
|
-
await adapter.setMfaMethods(userId, [...methods,
|
|
231
|
+
if (!methods.includes('emailOtp')) {
|
|
232
|
+
await adapter.setMfaMethods(userId, [...methods, 'emailOtp']);
|
|
205
233
|
}
|
|
206
234
|
}
|
|
207
235
|
await adapter.setMfaEnabled(userId, true);
|
|
208
236
|
// Generate recovery codes if MFA was not previously active
|
|
209
237
|
if (!wasEnabled) {
|
|
210
|
-
const { plainCodes, hashedCodes } = generateRecoveryCodes();
|
|
238
|
+
const { plainCodes, hashedCodes } = generateRecoveryCodes(runtime);
|
|
211
239
|
await adapter.setRecoveryCodes(userId, hashedCodes);
|
|
212
240
|
return plainCodes;
|
|
213
241
|
}
|
|
214
242
|
// Regenerate recovery codes when adding a second method
|
|
215
|
-
const { plainCodes, hashedCodes } = generateRecoveryCodes();
|
|
243
|
+
const { plainCodes, hashedCodes } = generateRecoveryCodes(runtime);
|
|
216
244
|
await adapter.setRecoveryCodes(userId, hashedCodes);
|
|
217
245
|
return plainCodes;
|
|
218
246
|
};
|
|
@@ -220,37 +248,31 @@ export const confirmEmailOtp = async (userId, setupToken, code) => {
|
|
|
220
248
|
* Disable email OTP for a user.
|
|
221
249
|
* If TOTP is also enabled, requires a TOTP code. Otherwise requires password.
|
|
222
250
|
*/
|
|
223
|
-
export const disableEmailOtp = async (userId, params) => {
|
|
224
|
-
const adapter =
|
|
251
|
+
export const disableEmailOtp = async (userId, params, runtime) => {
|
|
252
|
+
const { adapter } = runtime;
|
|
225
253
|
if (!adapter.setMfaEnabled)
|
|
226
|
-
throw new HttpError(501,
|
|
254
|
+
throw new HttpError(501, 'Auth adapter does not support MFA');
|
|
227
255
|
// Get current methods
|
|
228
256
|
const methods = adapter.getMfaMethods ? await adapter.getMfaMethods(userId) : [];
|
|
229
|
-
const hasTotpEnabled = methods.includes(
|
|
257
|
+
const hasTotpEnabled = methods.includes('totp');
|
|
230
258
|
// Verify identity
|
|
231
259
|
if (hasTotpEnabled) {
|
|
232
260
|
if (!params.code)
|
|
233
|
-
throw new HttpError(400,
|
|
234
|
-
const valid = await verifyTotp(userId, params.code);
|
|
261
|
+
throw new HttpError(400, 'TOTP code required to disable email OTP');
|
|
262
|
+
const valid = await verifyTotp(userId, params.code, runtime);
|
|
235
263
|
if (!valid)
|
|
236
|
-
throw new HttpError(401,
|
|
264
|
+
throw new HttpError(401, 'Invalid TOTP code');
|
|
237
265
|
}
|
|
238
266
|
else {
|
|
239
267
|
if (!params.password)
|
|
240
|
-
throw new HttpError(400,
|
|
241
|
-
|
|
242
|
-
const user = adapter.findByIdentifier
|
|
243
|
-
? await adapter.findByIdentifier((await adapter.getUser?.(userId))?.email ?? "")
|
|
244
|
-
: await adapter.findByEmail((await adapter.getUser?.(userId))?.email ?? "");
|
|
245
|
-
if (!user)
|
|
246
|
-
throw new HttpError(404, "User not found");
|
|
247
|
-
const valid = await Bun.password.verify(params.password, user.passwordHash);
|
|
268
|
+
throw new HttpError(400, 'Password required to disable email OTP');
|
|
269
|
+
const valid = await adapter.verifyPassword(userId, params.password);
|
|
248
270
|
if (!valid)
|
|
249
|
-
throw new HttpError(401,
|
|
271
|
+
throw new HttpError(401, 'Invalid password');
|
|
250
272
|
}
|
|
251
273
|
// Remove "emailOtp" from methods
|
|
252
274
|
if (adapter.setMfaMethods) {
|
|
253
|
-
const updated = methods.filter(
|
|
275
|
+
const updated = methods.filter(m => m !== 'emailOtp');
|
|
254
276
|
await adapter.setMfaMethods(userId, updated);
|
|
255
277
|
// If no methods remain, disable MFA entirely
|
|
256
278
|
if (updated.length === 0) {
|
|
@@ -261,45 +283,39 @@ export const disableEmailOtp = async (userId, params) => {
|
|
|
261
283
|
}
|
|
262
284
|
};
|
|
263
285
|
/** Get the MFA methods enabled for a user. */
|
|
264
|
-
export const getMfaMethods = async (userId) => {
|
|
265
|
-
const adapter =
|
|
286
|
+
export const getMfaMethods = async (userId, runtime) => {
|
|
287
|
+
const { adapter } = runtime;
|
|
266
288
|
if (adapter.getMfaMethods)
|
|
267
289
|
return adapter.getMfaMethods(userId);
|
|
268
|
-
// Backward compat
|
|
269
|
-
if (adapter.isMfaEnabled && await adapter.isMfaEnabled(userId))
|
|
270
|
-
return ["totp"];
|
|
271
290
|
return [];
|
|
272
291
|
};
|
|
273
292
|
// ---------------------------------------------------------------------------
|
|
274
293
|
// WebAuthn / FIDO2
|
|
275
294
|
// ---------------------------------------------------------------------------
|
|
276
295
|
// Lazy-load @simplewebauthn/server to keep it as an optional peer dependency
|
|
277
|
-
let _simplewebauthn = null;
|
|
278
296
|
async function getSimpleWebAuthn() {
|
|
279
|
-
|
|
280
|
-
_simplewebauthn = await import("@simplewebauthn/server");
|
|
281
|
-
return _simplewebauthn;
|
|
297
|
+
return import('@simplewebauthn/server');
|
|
282
298
|
}
|
|
283
299
|
/**
|
|
284
300
|
* Eager startup check — call at route mount time to fail fast if the peer dependency is missing.
|
|
285
301
|
*/
|
|
286
302
|
export const assertWebAuthnDependency = async () => {
|
|
287
303
|
try {
|
|
288
|
-
await import(
|
|
304
|
+
await import('@simplewebauthn/server');
|
|
289
305
|
}
|
|
290
306
|
catch {
|
|
291
|
-
throw new Error(
|
|
307
|
+
throw new Error('@simplewebauthn/server is required when mfa.webauthn is configured. Install it: bun add @simplewebauthn/server');
|
|
292
308
|
}
|
|
293
309
|
};
|
|
294
310
|
/**
|
|
295
311
|
* Generate WebAuthn authentication options for the login MFA flow.
|
|
296
312
|
* Called from auth.ts login when the user has "webauthn" in their methods.
|
|
297
313
|
*/
|
|
298
|
-
export const generateWebAuthnAuthenticationOptions = async (userId) => {
|
|
299
|
-
const config =
|
|
314
|
+
export const generateWebAuthnAuthenticationOptions = async (userId, runtime) => {
|
|
315
|
+
const config = runtime.config.mfa?.webauthn ?? null;
|
|
300
316
|
if (!config)
|
|
301
317
|
return null;
|
|
302
|
-
const adapter =
|
|
318
|
+
const { adapter } = runtime;
|
|
303
319
|
if (!adapter.getWebAuthnCredentials)
|
|
304
320
|
return null;
|
|
305
321
|
const credentials = await adapter.getWebAuthnCredentials(userId);
|
|
@@ -308,11 +324,11 @@ export const generateWebAuthnAuthenticationOptions = async (userId) => {
|
|
|
308
324
|
const { generateAuthenticationOptions } = await getSimpleWebAuthn();
|
|
309
325
|
const options = await generateAuthenticationOptions({
|
|
310
326
|
rpID: config.rpId,
|
|
311
|
-
allowCredentials: credentials.map(
|
|
327
|
+
allowCredentials: credentials.map(c => ({
|
|
312
328
|
id: c.credentialId,
|
|
313
329
|
transports: c.transports,
|
|
314
330
|
})),
|
|
315
|
-
userVerification: config.userVerification ??
|
|
331
|
+
userVerification: config.userVerification ?? 'preferred',
|
|
316
332
|
timeout: config.timeout ?? 60000,
|
|
317
333
|
});
|
|
318
334
|
return { challenge: options.challenge, options: options };
|
|
@@ -321,55 +337,55 @@ export const generateWebAuthnAuthenticationOptions = async (userId) => {
|
|
|
321
337
|
* Initiate WebAuthn registration: generates registration options for the client.
|
|
322
338
|
* Returns options + a registration challenge token.
|
|
323
339
|
*/
|
|
324
|
-
export const initiateWebAuthnRegistration = async (userId) => {
|
|
325
|
-
const config =
|
|
340
|
+
export const initiateWebAuthnRegistration = async (userId, runtime) => {
|
|
341
|
+
const config = runtime.config.mfa?.webauthn ?? null;
|
|
326
342
|
if (!config)
|
|
327
|
-
throw new HttpError(501,
|
|
328
|
-
const adapter =
|
|
343
|
+
throw new HttpError(501, 'WebAuthn is not configured');
|
|
344
|
+
const { adapter } = runtime;
|
|
329
345
|
if (!adapter.getWebAuthnCredentials)
|
|
330
|
-
throw new HttpError(501,
|
|
346
|
+
throw new HttpError(501, 'Auth adapter does not support WebAuthn');
|
|
331
347
|
const user = adapter.getUser ? await adapter.getUser(userId) : null;
|
|
332
348
|
// Get existing credentials to exclude (prevent re-registration)
|
|
333
349
|
const existingCreds = await adapter.getWebAuthnCredentials(userId);
|
|
334
350
|
const { generateRegistrationOptions } = await getSimpleWebAuthn();
|
|
335
351
|
const options = await generateRegistrationOptions({
|
|
336
|
-
rpName: config.rpName ??
|
|
352
|
+
rpName: config.rpName ?? runtime.config.appName,
|
|
337
353
|
rpID: config.rpId,
|
|
338
354
|
userName: user?.email ?? userId,
|
|
339
|
-
attestationType: config.attestationType ??
|
|
340
|
-
excludeCredentials: existingCreds.map(
|
|
355
|
+
attestationType: config.attestationType ?? 'none',
|
|
356
|
+
excludeCredentials: existingCreds.map(c => ({
|
|
341
357
|
id: c.credentialId,
|
|
342
358
|
transports: c.transports,
|
|
343
359
|
})),
|
|
344
360
|
authenticatorSelection: {
|
|
345
361
|
authenticatorAttachment: config.authenticatorAttachment,
|
|
346
|
-
userVerification: config.userVerification ??
|
|
347
|
-
residentKey:
|
|
362
|
+
userVerification: config.userVerification ?? 'required',
|
|
363
|
+
residentKey: 'required',
|
|
348
364
|
},
|
|
349
365
|
timeout: config.timeout ?? 60000,
|
|
350
366
|
});
|
|
351
|
-
const { createWebAuthnRegistrationChallenge } = await import(
|
|
352
|
-
const registrationToken = await createWebAuthnRegistrationChallenge(userId, options.challenge);
|
|
367
|
+
const { createWebAuthnRegistrationChallenge } = await import('../lib/mfaChallenge');
|
|
368
|
+
const registrationToken = await createWebAuthnRegistrationChallenge(runtime.repos.mfaChallenge, userId, options.challenge, runtime.config);
|
|
353
369
|
return { options: options, registrationToken };
|
|
354
370
|
};
|
|
355
371
|
/**
|
|
356
372
|
* Complete WebAuthn registration: verifies attestation and stores the credential.
|
|
357
373
|
* Returns recovery codes if this is the first MFA method.
|
|
358
374
|
*/
|
|
359
|
-
export const completeWebAuthnRegistration = async (userId, registrationToken, attestationResponse, name) => {
|
|
360
|
-
const config =
|
|
375
|
+
export const completeWebAuthnRegistration = async (userId, registrationToken, attestationResponse, runtime, name) => {
|
|
376
|
+
const config = runtime.config.mfa?.webauthn ?? null;
|
|
361
377
|
if (!config)
|
|
362
|
-
throw new HttpError(501,
|
|
363
|
-
const adapter =
|
|
378
|
+
throw new HttpError(501, 'WebAuthn is not configured');
|
|
379
|
+
const { adapter } = runtime;
|
|
364
380
|
if (!adapter.addWebAuthnCredential || !adapter.setMfaEnabled || !adapter.setRecoveryCodes) {
|
|
365
|
-
throw new HttpError(501,
|
|
381
|
+
throw new HttpError(501, 'Auth adapter does not support WebAuthn');
|
|
366
382
|
}
|
|
367
|
-
const { consumeWebAuthnRegistrationChallenge } = await import(
|
|
368
|
-
const challenge = await consumeWebAuthnRegistrationChallenge(registrationToken);
|
|
383
|
+
const { consumeWebAuthnRegistrationChallenge } = await import('../lib/mfaChallenge');
|
|
384
|
+
const challenge = await consumeWebAuthnRegistrationChallenge(runtime.repos.mfaChallenge, registrationToken);
|
|
369
385
|
if (!challenge)
|
|
370
|
-
throw new HttpError(401,
|
|
386
|
+
throw new HttpError(401, 'Invalid or expired registration token');
|
|
371
387
|
if (challenge.userId !== userId)
|
|
372
|
-
throw new HttpError(401,
|
|
388
|
+
throw new HttpError(401, 'Token does not match user');
|
|
373
389
|
const { verifyRegistrationResponse } = await getSimpleWebAuthn();
|
|
374
390
|
const verification = await verifyRegistrationResponse({
|
|
375
391
|
response: attestationResponse,
|
|
@@ -378,7 +394,7 @@ export const completeWebAuthnRegistration = async (userId, registrationToken, at
|
|
|
378
394
|
expectedRPID: config.rpId,
|
|
379
395
|
});
|
|
380
396
|
if (!verification.verified || !verification.registrationInfo) {
|
|
381
|
-
throw new HttpError(401,
|
|
397
|
+
throw new HttpError(401, 'WebAuthn registration verification failed');
|
|
382
398
|
}
|
|
383
399
|
const { credential } = verification.registrationInfo;
|
|
384
400
|
const credentialId = credential.id;
|
|
@@ -386,12 +402,12 @@ export const completeWebAuthnRegistration = async (userId, registrationToken, at
|
|
|
386
402
|
if (adapter.findUserByWebAuthnCredentialId) {
|
|
387
403
|
const existingOwner = await adapter.findUserByWebAuthnCredentialId(credentialId);
|
|
388
404
|
if (existingOwner && existingOwner !== userId) {
|
|
389
|
-
throw new HttpError(409,
|
|
405
|
+
throw new HttpError(409, 'This security key is already registered to another account');
|
|
390
406
|
}
|
|
391
407
|
}
|
|
392
408
|
const newCredential = {
|
|
393
409
|
credentialId,
|
|
394
|
-
publicKey: Buffer.from(credential.publicKey).toString(
|
|
410
|
+
publicKey: Buffer.from(credential.publicKey).toString('base64url'),
|
|
395
411
|
signCount: credential.counter,
|
|
396
412
|
transports: attestationResponse.response?.transports ?? [],
|
|
397
413
|
name: name ?? undefined,
|
|
@@ -401,29 +417,29 @@ export const completeWebAuthnRegistration = async (userId, registrationToken, at
|
|
|
401
417
|
// Add "webauthn" to methods
|
|
402
418
|
if (adapter.getMfaMethods && adapter.setMfaMethods) {
|
|
403
419
|
const methods = await adapter.getMfaMethods(userId);
|
|
404
|
-
if (!methods.includes(
|
|
405
|
-
await adapter.setMfaMethods(userId, [...methods,
|
|
420
|
+
if (!methods.includes('webauthn')) {
|
|
421
|
+
await adapter.setMfaMethods(userId, [...methods, 'webauthn']);
|
|
406
422
|
}
|
|
407
423
|
}
|
|
408
424
|
// Enable MFA + generate/regenerate recovery codes
|
|
409
425
|
await adapter.setMfaEnabled(userId, true);
|
|
410
|
-
const { plainCodes, hashedCodes } = generateRecoveryCodes();
|
|
426
|
+
const { plainCodes, hashedCodes } = generateRecoveryCodes(runtime);
|
|
411
427
|
await adapter.setRecoveryCodes(userId, hashedCodes);
|
|
412
428
|
return { credentialId, recoveryCodes: plainCodes };
|
|
413
429
|
};
|
|
414
430
|
/**
|
|
415
431
|
* Verify a WebAuthn authentication assertion during login MFA.
|
|
416
432
|
*/
|
|
417
|
-
export const verifyWebAuthn = async (userId, assertionResponse, expectedChallenge) => {
|
|
418
|
-
const config =
|
|
433
|
+
export const verifyWebAuthn = async (userId, assertionResponse, expectedChallenge, runtime) => {
|
|
434
|
+
const config = runtime.config.mfa?.webauthn ?? null;
|
|
419
435
|
if (!config)
|
|
420
436
|
return false;
|
|
421
|
-
const adapter =
|
|
437
|
+
const { adapter } = runtime;
|
|
422
438
|
if (!adapter.getWebAuthnCredentials || !adapter.updateWebAuthnCredentialSignCount)
|
|
423
439
|
return false;
|
|
424
440
|
const credentials = await adapter.getWebAuthnCredentials(userId);
|
|
425
441
|
const credentialId = assertionResponse.id;
|
|
426
|
-
const matchedCred = credentials.find(
|
|
442
|
+
const matchedCred = credentials.find(c => c.credentialId === credentialId);
|
|
427
443
|
if (!matchedCred)
|
|
428
444
|
return false;
|
|
429
445
|
const { verifyAuthenticationResponse } = await getSimpleWebAuthn();
|
|
@@ -435,7 +451,7 @@ export const verifyWebAuthn = async (userId, assertionResponse, expectedChalleng
|
|
|
435
451
|
expectedRPID: config.rpId,
|
|
436
452
|
credential: {
|
|
437
453
|
id: matchedCred.credentialId,
|
|
438
|
-
publicKey: new Uint8Array(Buffer.from(matchedCred.publicKey,
|
|
454
|
+
publicKey: new Uint8Array(Buffer.from(matchedCred.publicKey, 'base64url')),
|
|
439
455
|
counter: matchedCred.signCount,
|
|
440
456
|
transports: matchedCred.transports,
|
|
441
457
|
},
|
|
@@ -462,26 +478,26 @@ export const verifyWebAuthn = async (userId, assertionResponse, expectedChalleng
|
|
|
462
478
|
* Remove a single WebAuthn credential.
|
|
463
479
|
* Only requires identity verification when removing the last credential of the last MFA method.
|
|
464
480
|
*/
|
|
465
|
-
export const removeWebAuthnCredential = async (userId, credentialId, params) => {
|
|
466
|
-
const adapter =
|
|
481
|
+
export const removeWebAuthnCredential = async (userId, credentialId, params, runtime) => {
|
|
482
|
+
const { adapter } = runtime;
|
|
467
483
|
if (!adapter.getWebAuthnCredentials || !adapter.removeWebAuthnCredential) {
|
|
468
|
-
throw new HttpError(501,
|
|
484
|
+
throw new HttpError(501, 'Auth adapter does not support WebAuthn');
|
|
469
485
|
}
|
|
470
486
|
const credentials = await adapter.getWebAuthnCredentials(userId);
|
|
471
|
-
if (!credentials.some(
|
|
472
|
-
throw new HttpError(404,
|
|
487
|
+
if (!credentials.some(c => c.credentialId === credentialId)) {
|
|
488
|
+
throw new HttpError(404, 'Credential not found');
|
|
473
489
|
}
|
|
474
490
|
const methods = adapter.getMfaMethods ? await adapter.getMfaMethods(userId) : [];
|
|
475
|
-
const otherMethodsExist = methods.some(
|
|
491
|
+
const otherMethodsExist = methods.some(m => m !== 'webauthn');
|
|
476
492
|
const otherCredsExist = credentials.length > 1;
|
|
477
493
|
// Only require verification when removing the last credential of the last method
|
|
478
494
|
if (!otherMethodsExist && !otherCredsExist) {
|
|
479
|
-
await verifyIdentity(userId, params);
|
|
495
|
+
await verifyIdentity(userId, params, runtime);
|
|
480
496
|
}
|
|
481
497
|
await adapter.removeWebAuthnCredential(userId, credentialId);
|
|
482
498
|
// If that was the last credential, remove "webauthn" from methods
|
|
483
499
|
if (!otherCredsExist && adapter.setMfaMethods) {
|
|
484
|
-
const updated = methods.filter(
|
|
500
|
+
const updated = methods.filter(m => m !== 'webauthn');
|
|
485
501
|
await adapter.setMfaMethods(userId, updated);
|
|
486
502
|
// If no methods remain, disable MFA entirely
|
|
487
503
|
if (updated.length === 0 && adapter.setMfaEnabled) {
|
|
@@ -494,12 +510,12 @@ export const removeWebAuthnCredential = async (userId, credentialId, params) =>
|
|
|
494
510
|
/**
|
|
495
511
|
* Disable WebAuthn entirely: removes all credentials and the method.
|
|
496
512
|
*/
|
|
497
|
-
export const disableWebAuthn = async (userId, params) => {
|
|
498
|
-
const adapter =
|
|
513
|
+
export const disableWebAuthn = async (userId, params, runtime) => {
|
|
514
|
+
const { adapter } = runtime;
|
|
499
515
|
if (!adapter.getWebAuthnCredentials || !adapter.removeWebAuthnCredential) {
|
|
500
|
-
throw new HttpError(501,
|
|
516
|
+
throw new HttpError(501, 'Auth adapter does not support WebAuthn');
|
|
501
517
|
}
|
|
502
|
-
await verifyIdentity(userId, params);
|
|
518
|
+
await verifyIdentity(userId, params, runtime);
|
|
503
519
|
const credentials = await adapter.getWebAuthnCredentials(userId);
|
|
504
520
|
for (const cred of credentials) {
|
|
505
521
|
await adapter.removeWebAuthnCredential(userId, cred.credentialId);
|
|
@@ -507,7 +523,7 @@ export const disableWebAuthn = async (userId, params) => {
|
|
|
507
523
|
// Remove "webauthn" from methods
|
|
508
524
|
if (adapter.getMfaMethods && adapter.setMfaMethods) {
|
|
509
525
|
const methods = await adapter.getMfaMethods(userId);
|
|
510
|
-
const updated = methods.filter(
|
|
526
|
+
const updated = methods.filter(m => m !== 'webauthn');
|
|
511
527
|
await adapter.setMfaMethods(userId, updated);
|
|
512
528
|
if (updated.length === 0 && adapter.setMfaEnabled) {
|
|
513
529
|
await adapter.setMfaEnabled(userId, false);
|
|
@@ -516,28 +532,88 @@ export const disableWebAuthn = async (userId, params) => {
|
|
|
516
532
|
}
|
|
517
533
|
}
|
|
518
534
|
};
|
|
535
|
+
// ---------------------------------------------------------------------------
|
|
536
|
+
// verifyAnyFactor — unified factor verification for reauth / destructive actions
|
|
537
|
+
// ---------------------------------------------------------------------------
|
|
538
|
+
/**
|
|
539
|
+
* Verify any supported authentication factor for a given user + session.
|
|
540
|
+
* Used by step-up, account deletion, and MFA disable flows.
|
|
541
|
+
*
|
|
542
|
+
* - "totp": TOTP code
|
|
543
|
+
* - "recovery": recovery code (only when method is explicitly "recovery")
|
|
544
|
+
* - "password": account password
|
|
545
|
+
* - "emailOtp": email OTP via reauth challenge token
|
|
546
|
+
* - "webauthn": WebAuthn assertion via reauth challenge token
|
|
547
|
+
*
|
|
548
|
+
* Hard boundaries:
|
|
549
|
+
* - "recovery" is ONLY checked when method is explicitly "recovery"
|
|
550
|
+
* - emailOtp / webauthn consume a reauth challenge bound to sessionId
|
|
551
|
+
*
|
|
552
|
+
* Returns false (never throws) when required params are missing.
|
|
553
|
+
*/
|
|
554
|
+
export async function verifyAnyFactor(userId, sessionId, runtime, params) {
|
|
555
|
+
const { method, code, password, reauthToken, webauthnResponse } = params;
|
|
556
|
+
if (!method)
|
|
557
|
+
return false;
|
|
558
|
+
const { adapter } = runtime;
|
|
559
|
+
try {
|
|
560
|
+
if (method === 'totp') {
|
|
561
|
+
if (!code)
|
|
562
|
+
return false;
|
|
563
|
+
return verifyTotp(userId, code, runtime);
|
|
564
|
+
}
|
|
565
|
+
if (method === 'recovery') {
|
|
566
|
+
if (!code)
|
|
567
|
+
return false;
|
|
568
|
+
const hashedInput = sha256(code.toUpperCase());
|
|
569
|
+
return adapter.consumeRecoveryCode(userId, hashedInput);
|
|
570
|
+
}
|
|
571
|
+
if (method === 'password') {
|
|
572
|
+
if (!password)
|
|
573
|
+
return false;
|
|
574
|
+
return adapter.verifyPassword(userId, password);
|
|
575
|
+
}
|
|
576
|
+
if (method === 'emailOtp') {
|
|
577
|
+
if (!reauthToken || !code)
|
|
578
|
+
return false;
|
|
579
|
+
const { consumeReauthChallenge } = await import('../lib/mfaChallenge');
|
|
580
|
+
const challenge = await consumeReauthChallenge(runtime.repos.mfaChallenge, reauthToken, sessionId);
|
|
581
|
+
if (!challenge || !challenge.emailOtpHash)
|
|
582
|
+
return false;
|
|
583
|
+
return timingSafeEqual(sha256(code), challenge.emailOtpHash);
|
|
584
|
+
}
|
|
585
|
+
if (method === 'webauthn') {
|
|
586
|
+
if (!reauthToken || !webauthnResponse)
|
|
587
|
+
return false;
|
|
588
|
+
const { consumeReauthChallenge } = await import('../lib/mfaChallenge');
|
|
589
|
+
const challenge = await consumeReauthChallenge(runtime.repos.mfaChallenge, reauthToken, sessionId);
|
|
590
|
+
if (!challenge || !challenge.webauthnChallenge)
|
|
591
|
+
return false;
|
|
592
|
+
return verifyWebAuthn(userId, webauthnResponse, challenge.webauthnChallenge, runtime);
|
|
593
|
+
}
|
|
594
|
+
return false;
|
|
595
|
+
}
|
|
596
|
+
catch {
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
519
600
|
/** Internal: verify identity via TOTP code or password. */
|
|
520
|
-
async function verifyIdentity(userId, params) {
|
|
521
|
-
const adapter =
|
|
601
|
+
async function verifyIdentity(userId, params, runtime) {
|
|
602
|
+
const { adapter } = runtime;
|
|
522
603
|
const methods = adapter.getMfaMethods ? await adapter.getMfaMethods(userId) : [];
|
|
523
|
-
const hasTotpEnabled = methods.includes(
|
|
604
|
+
const hasTotpEnabled = methods.includes('totp');
|
|
524
605
|
if (hasTotpEnabled) {
|
|
525
606
|
if (!params.code)
|
|
526
|
-
throw new HttpError(400,
|
|
527
|
-
const valid = await verifyTotp(userId, params.code);
|
|
607
|
+
throw new HttpError(400, 'TOTP code required');
|
|
608
|
+
const valid = await verifyTotp(userId, params.code, runtime);
|
|
528
609
|
if (!valid)
|
|
529
|
-
throw new HttpError(401,
|
|
610
|
+
throw new HttpError(401, 'Invalid TOTP code');
|
|
530
611
|
}
|
|
531
612
|
else {
|
|
532
613
|
if (!params.password)
|
|
533
|
-
throw new HttpError(400,
|
|
534
|
-
const
|
|
535
|
-
? await adapter.findByIdentifier((await adapter.getUser?.(userId))?.email ?? "")
|
|
536
|
-
: await adapter.findByEmail((await adapter.getUser?.(userId))?.email ?? "");
|
|
537
|
-
if (!user)
|
|
538
|
-
throw new HttpError(404, "User not found");
|
|
539
|
-
const valid = await Bun.password.verify(params.password, user.passwordHash);
|
|
614
|
+
throw new HttpError(400, 'Password required');
|
|
615
|
+
const valid = await adapter.verifyPassword(userId, params.password);
|
|
540
616
|
if (!valid)
|
|
541
|
-
throw new HttpError(401,
|
|
617
|
+
throw new HttpError(401, 'Invalid password');
|
|
542
618
|
}
|
|
543
619
|
}
|