@lastshotlabs/bunshot 0.0.27 → 0.1.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/.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 +211 -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 +277 -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 +64 -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 +100 -26
- 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
|
@@ -0,0 +1,1211 @@
|
|
|
1
|
+
import { DEFAULT_MAX_ENTRIES, hashToken, timingSafeEqual } from '../../../bunshot-core/src/index.js';
|
|
2
|
+
import { DEFAULT_AUTH_CONFIG } from '../config/authConfig';
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// TTL helpers
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
const DEFAULT_SESSION_TTL_SECONDS = 60 * 60 * 24 * 7; // 7 days
|
|
7
|
+
function getSessionTtlSeconds(cfg) {
|
|
8
|
+
return (cfg ?? DEFAULT_AUTH_CONFIG).sessionPolicy.absoluteTimeout ?? DEFAULT_SESSION_TTL_SECONDS;
|
|
9
|
+
}
|
|
10
|
+
function getSessionTtlMs(cfg) {
|
|
11
|
+
return getSessionTtlSeconds(cfg) * 1000;
|
|
12
|
+
}
|
|
13
|
+
function shouldPersistSessionMetadata(cfg) {
|
|
14
|
+
return (cfg ?? DEFAULT_AUTH_CONFIG).persistSessionMetadata;
|
|
15
|
+
}
|
|
16
|
+
function isIdleExpired(lastActiveAt, cfg) {
|
|
17
|
+
const idleTimeout = (cfg ?? DEFAULT_AUTH_CONFIG).sessionPolicy.idleTimeout;
|
|
18
|
+
if (!idleTimeout)
|
|
19
|
+
return false;
|
|
20
|
+
const idleSecs = (Date.now() - lastActiveAt) / 1000;
|
|
21
|
+
return idleSecs > idleTimeout;
|
|
22
|
+
}
|
|
23
|
+
export function createMemorySessionRepository() {
|
|
24
|
+
const sessions = new Map();
|
|
25
|
+
const userSessionIds = new Map();
|
|
26
|
+
const refreshTokenIndex = new Map();
|
|
27
|
+
function removeUserSessionId(userId, sessionId) {
|
|
28
|
+
const ids = userSessionIds.get(userId);
|
|
29
|
+
if (!ids)
|
|
30
|
+
return;
|
|
31
|
+
ids.delete(sessionId);
|
|
32
|
+
if (ids.size === 0) {
|
|
33
|
+
userSessionIds.delete(userId);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function purgeSessionImpl(sessionId) {
|
|
37
|
+
const entry = sessions.get(sessionId);
|
|
38
|
+
if (!entry)
|
|
39
|
+
return;
|
|
40
|
+
if (entry.refreshToken)
|
|
41
|
+
refreshTokenIndex.delete(entry.refreshToken);
|
|
42
|
+
if (entry.prevRefreshToken)
|
|
43
|
+
refreshTokenIndex.delete(entry.prevRefreshToken);
|
|
44
|
+
sessions.delete(sessionId);
|
|
45
|
+
removeUserSessionId(entry.userId, sessionId);
|
|
46
|
+
}
|
|
47
|
+
// Purge tombstoned sessions (token === null) whose natural TTL has passed.
|
|
48
|
+
// Called opportunistically on delete and on new-session creation so expired
|
|
49
|
+
// tombstones do not accumulate indefinitely in the in-memory dev store.
|
|
50
|
+
function sweepExpiredTombstones() {
|
|
51
|
+
const now = Date.now();
|
|
52
|
+
for (const [sessionId, s] of sessions) {
|
|
53
|
+
if (!s.token && s.expiresAt <= now) {
|
|
54
|
+
purgeSessionImpl(sessionId);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function deleteSessionImpl(sessionId, cfg) {
|
|
59
|
+
const entry = sessions.get(sessionId);
|
|
60
|
+
if (!entry)
|
|
61
|
+
return;
|
|
62
|
+
if (shouldPersistSessionMetadata(cfg)) {
|
|
63
|
+
if (entry.refreshToken)
|
|
64
|
+
refreshTokenIndex.delete(entry.refreshToken);
|
|
65
|
+
if (entry.prevRefreshToken)
|
|
66
|
+
refreshTokenIndex.delete(entry.prevRefreshToken);
|
|
67
|
+
entry.token = null;
|
|
68
|
+
entry.refreshToken = null;
|
|
69
|
+
entry.prevRefreshToken = null;
|
|
70
|
+
entry.prevTokenExpiresAt = null;
|
|
71
|
+
entry.refreshTokenPlain = null;
|
|
72
|
+
sweepExpiredTombstones();
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
purgeSessionImpl(sessionId);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function trimSessionsToCapacity() {
|
|
79
|
+
sweepExpiredTombstones();
|
|
80
|
+
while (sessions.size >= DEFAULT_MAX_ENTRIES) {
|
|
81
|
+
const oldestSessionId = sessions.keys().next().value;
|
|
82
|
+
if (oldestSessionId === undefined)
|
|
83
|
+
break;
|
|
84
|
+
purgeSessionImpl(oldestSessionId);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function createSessionImpl(userId, token, sessionId, metadata, cfg) {
|
|
88
|
+
const now = Date.now();
|
|
89
|
+
const session = {
|
|
90
|
+
sessionId,
|
|
91
|
+
userId,
|
|
92
|
+
token,
|
|
93
|
+
createdAt: now,
|
|
94
|
+
lastActiveAt: now,
|
|
95
|
+
expiresAt: now + getSessionTtlMs(cfg),
|
|
96
|
+
ipAddress: metadata?.ipAddress,
|
|
97
|
+
userAgent: metadata?.userAgent,
|
|
98
|
+
};
|
|
99
|
+
trimSessionsToCapacity();
|
|
100
|
+
sessions.set(sessionId, session);
|
|
101
|
+
if (!userSessionIds.has(userId))
|
|
102
|
+
userSessionIds.set(userId, new Set());
|
|
103
|
+
userSessionIds.get(userId).add(sessionId);
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
async createSession(userId, token, sessionId, metadata, cfg) {
|
|
107
|
+
createSessionImpl(userId, token, sessionId, metadata, cfg);
|
|
108
|
+
},
|
|
109
|
+
async atomicCreateSession(userId, token, sessionId, maxSessions, metadata, cfg) {
|
|
110
|
+
const now = Date.now();
|
|
111
|
+
const ids = userSessionIds.get(userId);
|
|
112
|
+
if (ids) {
|
|
113
|
+
let activeCount = 0;
|
|
114
|
+
let oldest = null;
|
|
115
|
+
for (const sid of ids) {
|
|
116
|
+
const s = sessions.get(sid);
|
|
117
|
+
if (s && s.token && s.expiresAt > now) {
|
|
118
|
+
activeCount++;
|
|
119
|
+
if (!oldest || s.createdAt < oldest.createdAt)
|
|
120
|
+
oldest = s;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
while (activeCount >= maxSessions && oldest) {
|
|
124
|
+
deleteSessionImpl(oldest.sessionId, cfg);
|
|
125
|
+
activeCount--;
|
|
126
|
+
oldest = null;
|
|
127
|
+
for (const sid of ids) {
|
|
128
|
+
const s = sessions.get(sid);
|
|
129
|
+
if (s && s.token && s.expiresAt > now) {
|
|
130
|
+
if (!oldest || s.createdAt < oldest.createdAt)
|
|
131
|
+
oldest = s;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
createSessionImpl(userId, token, sessionId, metadata, cfg);
|
|
137
|
+
},
|
|
138
|
+
async getSession(sessionId, cfg) {
|
|
139
|
+
const entry = sessions.get(sessionId);
|
|
140
|
+
if (!entry || !entry.token || entry.expiresAt <= Date.now())
|
|
141
|
+
return null;
|
|
142
|
+
if (isIdleExpired(entry.lastActiveAt, cfg)) {
|
|
143
|
+
deleteSessionImpl(sessionId, cfg);
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
return entry.token;
|
|
147
|
+
},
|
|
148
|
+
async deleteSession(sessionId, cfg) {
|
|
149
|
+
deleteSessionImpl(sessionId, cfg);
|
|
150
|
+
},
|
|
151
|
+
async getUserSessions(userId, cfg) {
|
|
152
|
+
const ids = userSessionIds.get(userId);
|
|
153
|
+
if (!ids)
|
|
154
|
+
return [];
|
|
155
|
+
const now = Date.now();
|
|
156
|
+
const config = cfg ?? DEFAULT_AUTH_CONFIG;
|
|
157
|
+
const includeInactive = config.includeInactiveSessions;
|
|
158
|
+
const persist = config.persistSessionMetadata;
|
|
159
|
+
const results = [];
|
|
160
|
+
for (const sessionId of ids) {
|
|
161
|
+
const s = sessions.get(sessionId);
|
|
162
|
+
if (!s)
|
|
163
|
+
continue;
|
|
164
|
+
const isActive = !!s.token && s.expiresAt > now;
|
|
165
|
+
if (!isActive && !persist)
|
|
166
|
+
continue;
|
|
167
|
+
if (!isActive && !includeInactive)
|
|
168
|
+
continue;
|
|
169
|
+
results.push({
|
|
170
|
+
sessionId: s.sessionId,
|
|
171
|
+
createdAt: s.createdAt,
|
|
172
|
+
lastActiveAt: s.lastActiveAt,
|
|
173
|
+
expiresAt: s.expiresAt,
|
|
174
|
+
ipAddress: s.ipAddress,
|
|
175
|
+
userAgent: s.userAgent,
|
|
176
|
+
isActive,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
return results;
|
|
180
|
+
},
|
|
181
|
+
async getActiveSessionCount(userId) {
|
|
182
|
+
const ids = userSessionIds.get(userId);
|
|
183
|
+
if (!ids)
|
|
184
|
+
return 0;
|
|
185
|
+
const now = Date.now();
|
|
186
|
+
let count = 0;
|
|
187
|
+
for (const sessionId of ids) {
|
|
188
|
+
const s = sessions.get(sessionId);
|
|
189
|
+
if (s && s.token && s.expiresAt > now)
|
|
190
|
+
count++;
|
|
191
|
+
}
|
|
192
|
+
return count;
|
|
193
|
+
},
|
|
194
|
+
async evictOldestSession(userId, cfg) {
|
|
195
|
+
const ids = userSessionIds.get(userId);
|
|
196
|
+
if (!ids)
|
|
197
|
+
return;
|
|
198
|
+
const now = Date.now();
|
|
199
|
+
let oldest = null;
|
|
200
|
+
for (const sessionId of ids) {
|
|
201
|
+
const s = sessions.get(sessionId);
|
|
202
|
+
if (!s || !s.token || s.expiresAt <= now)
|
|
203
|
+
continue;
|
|
204
|
+
if (!oldest || s.createdAt < oldest.createdAt)
|
|
205
|
+
oldest = s;
|
|
206
|
+
}
|
|
207
|
+
if (oldest)
|
|
208
|
+
deleteSessionImpl(oldest.sessionId, cfg);
|
|
209
|
+
},
|
|
210
|
+
async updateSessionLastActive(sessionId) {
|
|
211
|
+
const entry = sessions.get(sessionId);
|
|
212
|
+
if (entry)
|
|
213
|
+
entry.lastActiveAt = Date.now();
|
|
214
|
+
},
|
|
215
|
+
async setRefreshToken(sessionId, refreshToken) {
|
|
216
|
+
const entry = sessions.get(sessionId);
|
|
217
|
+
if (!entry)
|
|
218
|
+
return;
|
|
219
|
+
const tokenHash = hashToken(refreshToken);
|
|
220
|
+
if (entry.refreshToken && entry.refreshToken !== tokenHash) {
|
|
221
|
+
refreshTokenIndex.delete(entry.refreshToken);
|
|
222
|
+
}
|
|
223
|
+
entry.refreshToken = tokenHash;
|
|
224
|
+
refreshTokenIndex.set(tokenHash, sessionId);
|
|
225
|
+
},
|
|
226
|
+
async getSessionByRefreshToken(refreshToken, cfg) {
|
|
227
|
+
const tokenHash = hashToken(refreshToken);
|
|
228
|
+
const sessionId = refreshTokenIndex.get(tokenHash);
|
|
229
|
+
if (!sessionId)
|
|
230
|
+
return null;
|
|
231
|
+
const entry = sessions.get(sessionId);
|
|
232
|
+
if (!entry)
|
|
233
|
+
return null;
|
|
234
|
+
if (isIdleExpired(entry.lastActiveAt, cfg)) {
|
|
235
|
+
deleteSessionImpl(sessionId, cfg);
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
if (entry.refreshToken && timingSafeEqual(entry.refreshToken, tokenHash)) {
|
|
239
|
+
return { sessionId: entry.sessionId, userId: entry.userId, newRefreshToken: refreshToken };
|
|
240
|
+
}
|
|
241
|
+
if (entry.prevRefreshToken &&
|
|
242
|
+
timingSafeEqual(entry.prevRefreshToken, tokenHash) &&
|
|
243
|
+
entry.prevTokenExpiresAt &&
|
|
244
|
+
entry.prevTokenExpiresAt > Date.now()) {
|
|
245
|
+
return {
|
|
246
|
+
sessionId: entry.sessionId,
|
|
247
|
+
userId: entry.userId,
|
|
248
|
+
newRefreshToken: entry.refreshTokenPlain ?? entry.refreshToken,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
if (entry.prevRefreshToken && timingSafeEqual(entry.prevRefreshToken, tokenHash)) {
|
|
252
|
+
deleteSessionImpl(sessionId, cfg);
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
return null;
|
|
256
|
+
},
|
|
257
|
+
async rotateRefreshToken(sessionId, newRefreshToken, newAccessToken, cfg) {
|
|
258
|
+
const entry = sessions.get(sessionId);
|
|
259
|
+
if (!entry)
|
|
260
|
+
return;
|
|
261
|
+
const graceSeconds = (cfg ?? DEFAULT_AUTH_CONFIG).refreshToken?.rotationGraceSeconds ?? 30;
|
|
262
|
+
const newHash = hashToken(newRefreshToken);
|
|
263
|
+
const oldHash = entry.refreshToken;
|
|
264
|
+
if (entry.prevRefreshToken && entry.prevRefreshToken !== oldHash) {
|
|
265
|
+
refreshTokenIndex.delete(entry.prevRefreshToken);
|
|
266
|
+
}
|
|
267
|
+
entry.prevRefreshToken = oldHash;
|
|
268
|
+
entry.prevTokenExpiresAt = Date.now() + graceSeconds * 1000;
|
|
269
|
+
entry.refreshToken = newHash;
|
|
270
|
+
entry.refreshTokenPlain = newRefreshToken;
|
|
271
|
+
entry.token = newAccessToken;
|
|
272
|
+
refreshTokenIndex.set(newHash, sessionId);
|
|
273
|
+
},
|
|
274
|
+
async getSessionFingerprint(sessionId) {
|
|
275
|
+
return sessions.get(sessionId)?.fingerprint ?? null;
|
|
276
|
+
},
|
|
277
|
+
async setSessionFingerprint(sessionId, fingerprint) {
|
|
278
|
+
const entry = sessions.get(sessionId);
|
|
279
|
+
if (entry)
|
|
280
|
+
entry.fingerprint = fingerprint;
|
|
281
|
+
},
|
|
282
|
+
async setMfaVerifiedAt(sessionId) {
|
|
283
|
+
const entry = sessions.get(sessionId);
|
|
284
|
+
if (entry)
|
|
285
|
+
entry.mfaVerifiedAt = Math.floor(Date.now() / 1000);
|
|
286
|
+
},
|
|
287
|
+
async getMfaVerifiedAt(sessionId) {
|
|
288
|
+
return sessions.get(sessionId)?.mfaVerifiedAt ?? null;
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
// ---------------------------------------------------------------------------
|
|
293
|
+
// SQLite repository factory
|
|
294
|
+
// ---------------------------------------------------------------------------
|
|
295
|
+
export function createSqliteSessionRepository(db) {
|
|
296
|
+
let initialized = false;
|
|
297
|
+
function init() {
|
|
298
|
+
if (initialized)
|
|
299
|
+
return;
|
|
300
|
+
// Sessions table is created by sqliteAuth adapter's initSchema.
|
|
301
|
+
// Only create if it doesn't exist (standalone usage).
|
|
302
|
+
db.run(`CREATE TABLE IF NOT EXISTS sessions (
|
|
303
|
+
sessionId TEXT PRIMARY KEY,
|
|
304
|
+
userId TEXT NOT NULL,
|
|
305
|
+
token TEXT,
|
|
306
|
+
createdAt INTEGER NOT NULL,
|
|
307
|
+
lastActiveAt INTEGER NOT NULL,
|
|
308
|
+
expiresAt INTEGER NOT NULL,
|
|
309
|
+
ipAddress TEXT,
|
|
310
|
+
userAgent TEXT,
|
|
311
|
+
refreshToken TEXT,
|
|
312
|
+
prevRefreshToken TEXT,
|
|
313
|
+
prevTokenExpiresAt INTEGER,
|
|
314
|
+
fingerprint TEXT,
|
|
315
|
+
mfaVerifiedAt INTEGER,
|
|
316
|
+
refreshTokenPlain TEXT
|
|
317
|
+
)`);
|
|
318
|
+
db.run('CREATE INDEX IF NOT EXISTS idx_sessions_userId ON sessions(userId)');
|
|
319
|
+
db.run('CREATE UNIQUE INDEX IF NOT EXISTS idx_sessions_refreshToken ON sessions(refreshToken) WHERE refreshToken IS NOT NULL');
|
|
320
|
+
initialized = true;
|
|
321
|
+
}
|
|
322
|
+
function deleteSessionImpl(sessionId, cfg) {
|
|
323
|
+
init();
|
|
324
|
+
if ((cfg ?? DEFAULT_AUTH_CONFIG).persistSessionMetadata) {
|
|
325
|
+
db.run('UPDATE sessions SET token = NULL, refreshToken = NULL, prevRefreshToken = NULL, prevTokenExpiresAt = NULL WHERE sessionId = ?', [sessionId]);
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
db.run('DELETE FROM sessions WHERE sessionId = ?', [sessionId]);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
async createSession(userId, token, sessionId, metadata, cfg) {
|
|
333
|
+
init();
|
|
334
|
+
const now = Date.now();
|
|
335
|
+
const expiresAt = now + getSessionTtlMs(cfg);
|
|
336
|
+
db.run('INSERT INTO sessions (sessionId, userId, token, createdAt, lastActiveAt, expiresAt, ipAddress, userAgent) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', [
|
|
337
|
+
sessionId,
|
|
338
|
+
userId,
|
|
339
|
+
token,
|
|
340
|
+
now,
|
|
341
|
+
now,
|
|
342
|
+
expiresAt,
|
|
343
|
+
metadata?.ipAddress ?? null,
|
|
344
|
+
metadata?.userAgent ?? null,
|
|
345
|
+
]);
|
|
346
|
+
},
|
|
347
|
+
async atomicCreateSession(userId, token, sessionId, maxSessions, metadata, cfg) {
|
|
348
|
+
init();
|
|
349
|
+
const now = Date.now();
|
|
350
|
+
const ttlMs = getSessionTtlMs(cfg);
|
|
351
|
+
const expiresAt = now + ttlMs;
|
|
352
|
+
db.transaction(() => {
|
|
353
|
+
const countRow = db
|
|
354
|
+
.query('SELECT COUNT(*) AS count FROM sessions WHERE userId = ? AND token IS NOT NULL AND expiresAt > ?')
|
|
355
|
+
.get(userId, now);
|
|
356
|
+
let activeCount = countRow?.count ?? 0;
|
|
357
|
+
while (activeCount >= maxSessions) {
|
|
358
|
+
const oldest = db
|
|
359
|
+
.query('SELECT sessionId FROM sessions WHERE userId = ? AND token IS NOT NULL AND expiresAt > ? ORDER BY createdAt ASC LIMIT 1')
|
|
360
|
+
.get(userId, now);
|
|
361
|
+
if (!oldest)
|
|
362
|
+
break;
|
|
363
|
+
deleteSessionImpl(oldest.sessionId, cfg);
|
|
364
|
+
activeCount--;
|
|
365
|
+
}
|
|
366
|
+
db.run('INSERT INTO sessions (sessionId, userId, token, createdAt, lastActiveAt, expiresAt, ipAddress, userAgent) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', [
|
|
367
|
+
sessionId,
|
|
368
|
+
userId,
|
|
369
|
+
token,
|
|
370
|
+
now,
|
|
371
|
+
now,
|
|
372
|
+
expiresAt,
|
|
373
|
+
metadata?.ipAddress ?? null,
|
|
374
|
+
metadata?.userAgent ?? null,
|
|
375
|
+
]);
|
|
376
|
+
})();
|
|
377
|
+
},
|
|
378
|
+
async getSession(sessionId, cfg) {
|
|
379
|
+
init();
|
|
380
|
+
const row = db
|
|
381
|
+
.query('SELECT token, lastActiveAt FROM sessions WHERE sessionId = ? AND expiresAt > ?')
|
|
382
|
+
.get(sessionId, Date.now());
|
|
383
|
+
if (!row || !row.token)
|
|
384
|
+
return null;
|
|
385
|
+
if (isIdleExpired(row.lastActiveAt, cfg)) {
|
|
386
|
+
deleteSessionImpl(sessionId, cfg);
|
|
387
|
+
return null;
|
|
388
|
+
}
|
|
389
|
+
return row.token;
|
|
390
|
+
},
|
|
391
|
+
async deleteSession(sessionId, cfg) {
|
|
392
|
+
deleteSessionImpl(sessionId, cfg);
|
|
393
|
+
},
|
|
394
|
+
async getUserSessions(userId, cfg) {
|
|
395
|
+
init();
|
|
396
|
+
const now = Date.now();
|
|
397
|
+
const rows = db
|
|
398
|
+
.query('SELECT sessionId, token, createdAt, lastActiveAt, expiresAt, ipAddress, userAgent FROM sessions WHERE userId = ? ORDER BY createdAt ASC')
|
|
399
|
+
.all(userId);
|
|
400
|
+
const config = cfg ?? DEFAULT_AUTH_CONFIG;
|
|
401
|
+
const includeInactive = config.includeInactiveSessions;
|
|
402
|
+
const persist = config.persistSessionMetadata;
|
|
403
|
+
const results = [];
|
|
404
|
+
for (const row of rows) {
|
|
405
|
+
const isActive = !!row.token && row.expiresAt > now;
|
|
406
|
+
if (!isActive && !persist)
|
|
407
|
+
continue;
|
|
408
|
+
if (!isActive && !includeInactive)
|
|
409
|
+
continue;
|
|
410
|
+
results.push({
|
|
411
|
+
sessionId: row.sessionId,
|
|
412
|
+
createdAt: row.createdAt,
|
|
413
|
+
lastActiveAt: row.lastActiveAt,
|
|
414
|
+
expiresAt: row.expiresAt,
|
|
415
|
+
ipAddress: row.ipAddress ?? undefined,
|
|
416
|
+
userAgent: row.userAgent ?? undefined,
|
|
417
|
+
isActive,
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
return results;
|
|
421
|
+
},
|
|
422
|
+
async getActiveSessionCount(userId) {
|
|
423
|
+
init();
|
|
424
|
+
const row = db
|
|
425
|
+
.query('SELECT COUNT(*) AS count FROM sessions WHERE userId = ? AND token IS NOT NULL AND expiresAt > ?')
|
|
426
|
+
.get(userId, Date.now());
|
|
427
|
+
return row?.count ?? 0;
|
|
428
|
+
},
|
|
429
|
+
async evictOldestSession(userId, cfg) {
|
|
430
|
+
init();
|
|
431
|
+
const now = Date.now();
|
|
432
|
+
const oldest = db
|
|
433
|
+
.query('SELECT sessionId FROM sessions WHERE userId = ? AND token IS NOT NULL AND expiresAt > ? ORDER BY createdAt ASC LIMIT 1')
|
|
434
|
+
.get(userId, now);
|
|
435
|
+
if (oldest)
|
|
436
|
+
deleteSessionImpl(oldest.sessionId, cfg);
|
|
437
|
+
},
|
|
438
|
+
async updateSessionLastActive(sessionId) {
|
|
439
|
+
init();
|
|
440
|
+
db.run('UPDATE sessions SET lastActiveAt = ? WHERE sessionId = ?', [Date.now(), sessionId]);
|
|
441
|
+
},
|
|
442
|
+
async setRefreshToken(sessionId, refreshToken) {
|
|
443
|
+
init();
|
|
444
|
+
const tokenHash = hashToken(refreshToken);
|
|
445
|
+
db.run('UPDATE sessions SET refreshToken = ? WHERE sessionId = ?', [tokenHash, sessionId]);
|
|
446
|
+
},
|
|
447
|
+
async getSessionByRefreshToken(refreshToken, cfg) {
|
|
448
|
+
init();
|
|
449
|
+
const tokenHash = hashToken(refreshToken);
|
|
450
|
+
let row = db
|
|
451
|
+
.query('SELECT sessionId, userId, refreshToken, lastActiveAt FROM sessions WHERE refreshToken = ?')
|
|
452
|
+
.get(tokenHash);
|
|
453
|
+
if (row) {
|
|
454
|
+
if (isIdleExpired(row.lastActiveAt, cfg)) {
|
|
455
|
+
deleteSessionImpl(row.sessionId, cfg);
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
return { sessionId: row.sessionId, userId: row.userId, newRefreshToken: refreshToken };
|
|
459
|
+
}
|
|
460
|
+
const graceRow = db
|
|
461
|
+
.query('SELECT sessionId, userId, refreshToken, refreshTokenPlain, prevTokenExpiresAt, lastActiveAt FROM sessions WHERE prevRefreshToken = ?')
|
|
462
|
+
.get(tokenHash);
|
|
463
|
+
if (!graceRow)
|
|
464
|
+
return null;
|
|
465
|
+
if (isIdleExpired(graceRow.lastActiveAt, cfg)) {
|
|
466
|
+
deleteSessionImpl(graceRow.sessionId, cfg);
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
if (graceRow.prevTokenExpiresAt && graceRow.prevTokenExpiresAt > Date.now()) {
|
|
470
|
+
return {
|
|
471
|
+
sessionId: graceRow.sessionId,
|
|
472
|
+
userId: graceRow.userId,
|
|
473
|
+
newRefreshToken: graceRow.refreshTokenPlain ?? graceRow.refreshToken,
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
deleteSessionImpl(graceRow.sessionId, cfg);
|
|
477
|
+
return null;
|
|
478
|
+
},
|
|
479
|
+
async rotateRefreshToken(sessionId, newRefreshToken, newAccessToken, cfg) {
|
|
480
|
+
init();
|
|
481
|
+
const graceSeconds = (cfg ?? DEFAULT_AUTH_CONFIG).refreshToken?.rotationGraceSeconds ?? 30;
|
|
482
|
+
const prevTokenExpiresAt = Date.now() + graceSeconds * 1000;
|
|
483
|
+
const newHash = hashToken(newRefreshToken);
|
|
484
|
+
db.run('UPDATE sessions SET prevRefreshToken = refreshToken, prevTokenExpiresAt = ?, refreshToken = ?, refreshTokenPlain = ?, token = ? WHERE sessionId = ?', [prevTokenExpiresAt, newHash, newRefreshToken, newAccessToken, sessionId]);
|
|
485
|
+
},
|
|
486
|
+
async getSessionFingerprint(sessionId) {
|
|
487
|
+
init();
|
|
488
|
+
const row = db
|
|
489
|
+
.query('SELECT fingerprint FROM sessions WHERE sessionId = ?')
|
|
490
|
+
.get(sessionId);
|
|
491
|
+
return row?.fingerprint ?? null;
|
|
492
|
+
},
|
|
493
|
+
async setSessionFingerprint(sessionId, fingerprint) {
|
|
494
|
+
init();
|
|
495
|
+
db.run('UPDATE sessions SET fingerprint = ? WHERE sessionId = ?', [fingerprint, sessionId]);
|
|
496
|
+
},
|
|
497
|
+
async setMfaVerifiedAt(sessionId) {
|
|
498
|
+
init();
|
|
499
|
+
const now = Math.floor(Date.now() / 1000);
|
|
500
|
+
db.run('UPDATE sessions SET mfaVerifiedAt = ? WHERE sessionId = ?', [now, sessionId]);
|
|
501
|
+
},
|
|
502
|
+
async getMfaVerifiedAt(sessionId) {
|
|
503
|
+
init();
|
|
504
|
+
const row = db
|
|
505
|
+
.query('SELECT mfaVerifiedAt FROM sessions WHERE sessionId = ?')
|
|
506
|
+
.get(sessionId);
|
|
507
|
+
return row?.mfaVerifiedAt ?? null;
|
|
508
|
+
},
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
// ---------------------------------------------------------------------------
|
|
512
|
+
// Redis repository factory
|
|
513
|
+
// ---------------------------------------------------------------------------
|
|
514
|
+
export function createRedisSessionRepository(getRedis, appName) {
|
|
515
|
+
function sessionKey(sessionId) {
|
|
516
|
+
return `session:${appName}:${sessionId}`;
|
|
517
|
+
}
|
|
518
|
+
function userSessionsKey(userId) {
|
|
519
|
+
return `usersessions:${appName}:${userId}`;
|
|
520
|
+
}
|
|
521
|
+
function refreshTokenKey(refreshToken) {
|
|
522
|
+
return `refreshtoken:${appName}:${refreshToken}`;
|
|
523
|
+
}
|
|
524
|
+
// Lua script: atomic session field update
|
|
525
|
+
const UPDATE_FIELD_LUA = `
|
|
526
|
+
local key = KEYS[1]
|
|
527
|
+
local field = ARGV[1]
|
|
528
|
+
local value = ARGV[2]
|
|
529
|
+
local valueType = ARGV[3]
|
|
530
|
+
local persist = ARGV[4] == "1"
|
|
531
|
+
|
|
532
|
+
local raw = redis.call('GET', key)
|
|
533
|
+
if not raw then return 0 end
|
|
534
|
+
local rec = cjson.decode(raw)
|
|
535
|
+
if valueType == "number" then
|
|
536
|
+
rec[field] = tonumber(value)
|
|
537
|
+
else
|
|
538
|
+
rec[field] = value
|
|
539
|
+
end
|
|
540
|
+
if persist then
|
|
541
|
+
redis.call('SET', key, cjson.encode(rec))
|
|
542
|
+
else
|
|
543
|
+
local ttl = redis.call('PTTL', key)
|
|
544
|
+
if ttl > 0 then
|
|
545
|
+
redis.call('SET', key, cjson.encode(rec), 'PX', ttl)
|
|
546
|
+
else
|
|
547
|
+
redis.call('SET', key, cjson.encode(rec))
|
|
548
|
+
end
|
|
549
|
+
end
|
|
550
|
+
return 1
|
|
551
|
+
`;
|
|
552
|
+
const WRITE_SESSION_LUA = `
|
|
553
|
+
local key = KEYS[1]
|
|
554
|
+
local rawJson = ARGV[1]
|
|
555
|
+
local persist = ARGV[2] == "1"
|
|
556
|
+
|
|
557
|
+
if persist then
|
|
558
|
+
redis.call('SET', key, rawJson)
|
|
559
|
+
else
|
|
560
|
+
local ttl = redis.call('PTTL', key)
|
|
561
|
+
if ttl > 0 then
|
|
562
|
+
redis.call('SET', key, rawJson, 'PX', ttl)
|
|
563
|
+
else
|
|
564
|
+
redis.call('SET', key, rawJson)
|
|
565
|
+
end
|
|
566
|
+
end
|
|
567
|
+
return 1
|
|
568
|
+
`;
|
|
569
|
+
// Lua script: atomic session creation
|
|
570
|
+
const ATOMIC_CREATE_SESSION_LUA = `
|
|
571
|
+
local userSessionsKey = KEYS[1]
|
|
572
|
+
local newSessionKey = KEYS[2]
|
|
573
|
+
local maxSessions = tonumber(ARGV[1])
|
|
574
|
+
local sessionId = ARGV[2]
|
|
575
|
+
local sessionJson = ARGV[3]
|
|
576
|
+
local createdAt = tonumber(ARGV[4])
|
|
577
|
+
local ttlSeconds = tonumber(ARGV[5])
|
|
578
|
+
local persist = ARGV[6] == "1"
|
|
579
|
+
|
|
580
|
+
local members = redis.call('ZRANGE', userSessionsKey, 0, -1)
|
|
581
|
+
|
|
582
|
+
local activeCount = 0
|
|
583
|
+
local activeSessions = {}
|
|
584
|
+
for i, sid in ipairs(members) do
|
|
585
|
+
local keyPrefix = ARGV[7]
|
|
586
|
+
local sKey = keyPrefix .. sid
|
|
587
|
+
local raw = redis.call('GET', sKey)
|
|
588
|
+
if raw then
|
|
589
|
+
local rec = cjson.decode(raw)
|
|
590
|
+
if rec.token and rec.expiresAt > createdAt then
|
|
591
|
+
activeCount = activeCount + 1
|
|
592
|
+
table.insert(activeSessions, { sid = sid, key = sKey, createdAt = rec.createdAt })
|
|
593
|
+
end
|
|
594
|
+
else
|
|
595
|
+
redis.call('ZREM', userSessionsKey, sid)
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
table.sort(activeSessions, function(a, b) return a.createdAt < b.createdAt end)
|
|
600
|
+
|
|
601
|
+
local evicted = 0
|
|
602
|
+
while activeCount >= maxSessions and evicted < #activeSessions do
|
|
603
|
+
evicted = evicted + 1
|
|
604
|
+
local victim = activeSessions[evicted]
|
|
605
|
+
redis.call('DEL', victim.key)
|
|
606
|
+
redis.call('ZREM', userSessionsKey, victim.sid)
|
|
607
|
+
activeCount = activeCount - 1
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
if persist then
|
|
611
|
+
redis.call('SET', newSessionKey, sessionJson)
|
|
612
|
+
else
|
|
613
|
+
redis.call('SET', newSessionKey, sessionJson, 'EX', ttlSeconds)
|
|
614
|
+
end
|
|
615
|
+
redis.call('ZADD', userSessionsKey, createdAt, sessionId)
|
|
616
|
+
|
|
617
|
+
return evicted
|
|
618
|
+
`;
|
|
619
|
+
async function updateSessionField(sessionId, field, value, persist, cfg) {
|
|
620
|
+
const redis = getRedis();
|
|
621
|
+
const key = sessionKey(sessionId);
|
|
622
|
+
const valueType = typeof value === 'number' ? 'number' : 'string';
|
|
623
|
+
const persistFlag = (persist ?? (cfg ?? DEFAULT_AUTH_CONFIG).persistSessionMetadata) ? '1' : '0';
|
|
624
|
+
const result = await redis.eval(UPDATE_FIELD_LUA, 1, key, field, String(value), valueType, persistFlag);
|
|
625
|
+
return result === 1;
|
|
626
|
+
}
|
|
627
|
+
async function writeSessionRecord(sessionId, record, cfg) {
|
|
628
|
+
const redis = getRedis();
|
|
629
|
+
const persistFlag = shouldPersistSessionMetadata(cfg) ? '1' : '0';
|
|
630
|
+
await redis.eval(WRITE_SESSION_LUA, 1, sessionKey(sessionId), JSON.stringify(record), persistFlag);
|
|
631
|
+
}
|
|
632
|
+
async function deleteSessionImpl(sessionId, cfg) {
|
|
633
|
+
const c = cfg ?? DEFAULT_AUTH_CONFIG;
|
|
634
|
+
const redis = getRedis();
|
|
635
|
+
const raw = await redis.get(sessionKey(sessionId));
|
|
636
|
+
if (!raw)
|
|
637
|
+
return;
|
|
638
|
+
const rec = JSON.parse(raw);
|
|
639
|
+
const persist = c.persistSessionMetadata;
|
|
640
|
+
if (rec.refreshToken)
|
|
641
|
+
await redis.del(refreshTokenKey(rec.refreshToken));
|
|
642
|
+
if (rec.prevRefreshToken)
|
|
643
|
+
await redis.del(refreshTokenKey(rec.prevRefreshToken));
|
|
644
|
+
if (persist) {
|
|
645
|
+
const updated = {
|
|
646
|
+
...rec,
|
|
647
|
+
token: null,
|
|
648
|
+
refreshToken: null,
|
|
649
|
+
prevRefreshToken: null,
|
|
650
|
+
prevTokenExpiresAt: null,
|
|
651
|
+
};
|
|
652
|
+
await redis.set(sessionKey(sessionId), JSON.stringify(updated));
|
|
653
|
+
}
|
|
654
|
+
else {
|
|
655
|
+
await redis.del(sessionKey(sessionId));
|
|
656
|
+
}
|
|
657
|
+
if (!persist) {
|
|
658
|
+
await redis.zrem(userSessionsKey(rec.userId), sessionId);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
async function getUserSessionsImpl(userId, cfg) {
|
|
662
|
+
const c = cfg ?? DEFAULT_AUTH_CONFIG;
|
|
663
|
+
const redis = getRedis();
|
|
664
|
+
const sessionIds = await redis.zrange(userSessionsKey(userId), 0, -1);
|
|
665
|
+
if (!sessionIds.length)
|
|
666
|
+
return [];
|
|
667
|
+
const now = Date.now();
|
|
668
|
+
const raws = await redis.mget(...sessionIds.map(sessionKey));
|
|
669
|
+
const results = [];
|
|
670
|
+
const toRemove = [];
|
|
671
|
+
for (let i = 0; i < sessionIds.length; i++) {
|
|
672
|
+
const raw = raws[i];
|
|
673
|
+
if (!raw) {
|
|
674
|
+
toRemove.push(sessionIds[i]);
|
|
675
|
+
continue;
|
|
676
|
+
}
|
|
677
|
+
const rec = JSON.parse(raw);
|
|
678
|
+
const isActive = !!rec.token && rec.expiresAt > now;
|
|
679
|
+
if (!isActive && !c.persistSessionMetadata) {
|
|
680
|
+
toRemove.push(sessionIds[i]);
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
if (!isActive && !c.includeInactiveSessions)
|
|
684
|
+
continue;
|
|
685
|
+
results.push({
|
|
686
|
+
sessionId: rec.sessionId,
|
|
687
|
+
createdAt: Number(rec.createdAt),
|
|
688
|
+
lastActiveAt: Number(rec.lastActiveAt),
|
|
689
|
+
expiresAt: Number(rec.expiresAt),
|
|
690
|
+
ipAddress: rec.ipAddress,
|
|
691
|
+
userAgent: rec.userAgent,
|
|
692
|
+
isActive,
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
if (toRemove.length) {
|
|
696
|
+
await redis.zrem(userSessionsKey(userId), ...toRemove);
|
|
697
|
+
}
|
|
698
|
+
return results;
|
|
699
|
+
}
|
|
700
|
+
return {
|
|
701
|
+
async createSession(userId, token, sessionId, metadata, cfg) {
|
|
702
|
+
const c = cfg ?? DEFAULT_AUTH_CONFIG;
|
|
703
|
+
const now = Date.now();
|
|
704
|
+
const ttlSeconds = getSessionTtlSeconds(c);
|
|
705
|
+
const expiresAt = now + getSessionTtlMs(c);
|
|
706
|
+
const record = JSON.stringify({
|
|
707
|
+
sessionId,
|
|
708
|
+
userId,
|
|
709
|
+
token,
|
|
710
|
+
createdAt: now,
|
|
711
|
+
lastActiveAt: now,
|
|
712
|
+
expiresAt,
|
|
713
|
+
ipAddress: metadata?.ipAddress,
|
|
714
|
+
userAgent: metadata?.userAgent,
|
|
715
|
+
});
|
|
716
|
+
const redis = getRedis();
|
|
717
|
+
const persist = c.persistSessionMetadata;
|
|
718
|
+
if (persist) {
|
|
719
|
+
await redis.set(sessionKey(sessionId), record);
|
|
720
|
+
}
|
|
721
|
+
else {
|
|
722
|
+
await redis.set(sessionKey(sessionId), record, 'EX', ttlSeconds);
|
|
723
|
+
}
|
|
724
|
+
await redis.zadd(userSessionsKey(userId), now, sessionId);
|
|
725
|
+
},
|
|
726
|
+
async atomicCreateSession(userId, token, sessionId, maxSessions, metadata, cfg) {
|
|
727
|
+
const c = cfg ?? DEFAULT_AUTH_CONFIG;
|
|
728
|
+
const now = Date.now();
|
|
729
|
+
const ttlSeconds = getSessionTtlSeconds(c);
|
|
730
|
+
const expiresAt = now + getSessionTtlMs(c);
|
|
731
|
+
const record = JSON.stringify({
|
|
732
|
+
sessionId,
|
|
733
|
+
userId,
|
|
734
|
+
token,
|
|
735
|
+
createdAt: now,
|
|
736
|
+
lastActiveAt: now,
|
|
737
|
+
expiresAt,
|
|
738
|
+
ipAddress: metadata?.ipAddress,
|
|
739
|
+
userAgent: metadata?.userAgent,
|
|
740
|
+
});
|
|
741
|
+
const redis = getRedis();
|
|
742
|
+
const persist = c.persistSessionMetadata;
|
|
743
|
+
const sessionKeyPrefix = `session:${appName}:`;
|
|
744
|
+
await redis.eval(ATOMIC_CREATE_SESSION_LUA, 2, userSessionsKey(userId), sessionKey(sessionId), maxSessions, sessionId, record, now, ttlSeconds, persist ? '1' : '0', sessionKeyPrefix);
|
|
745
|
+
},
|
|
746
|
+
async getSession(sessionId, cfg) {
|
|
747
|
+
const raw = await getRedis().get(sessionKey(sessionId));
|
|
748
|
+
if (!raw)
|
|
749
|
+
return null;
|
|
750
|
+
const rec = JSON.parse(raw);
|
|
751
|
+
if (!rec.token)
|
|
752
|
+
return null;
|
|
753
|
+
if (rec.expiresAt <= Date.now())
|
|
754
|
+
return null;
|
|
755
|
+
if (typeof rec.lastActiveAt === 'number' && isIdleExpired(rec.lastActiveAt, cfg)) {
|
|
756
|
+
await deleteSessionImpl(sessionId, cfg);
|
|
757
|
+
return null;
|
|
758
|
+
}
|
|
759
|
+
return rec.token;
|
|
760
|
+
},
|
|
761
|
+
async deleteSession(sessionId, cfg) {
|
|
762
|
+
await deleteSessionImpl(sessionId, cfg);
|
|
763
|
+
},
|
|
764
|
+
async getUserSessions(userId, cfg) {
|
|
765
|
+
return getUserSessionsImpl(userId, cfg);
|
|
766
|
+
},
|
|
767
|
+
async getActiveSessionCount(userId, cfg) {
|
|
768
|
+
const sessions = await getUserSessionsImpl(userId, cfg);
|
|
769
|
+
return sessions.filter(s => s.isActive).length;
|
|
770
|
+
},
|
|
771
|
+
async evictOldestSession(userId, cfg) {
|
|
772
|
+
const redis = getRedis();
|
|
773
|
+
const sessionIds = await redis.zrange(userSessionsKey(userId), 0, -1);
|
|
774
|
+
const now = Date.now();
|
|
775
|
+
for (const sid of sessionIds) {
|
|
776
|
+
const raw = await redis.get(sessionKey(sid));
|
|
777
|
+
if (!raw) {
|
|
778
|
+
await redis.zrem(userSessionsKey(userId), sid);
|
|
779
|
+
continue;
|
|
780
|
+
}
|
|
781
|
+
const rec = JSON.parse(raw);
|
|
782
|
+
if (rec.token && rec.expiresAt > now) {
|
|
783
|
+
await deleteSessionImpl(sid, cfg);
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
},
|
|
788
|
+
async updateSessionLastActive(sessionId, cfg) {
|
|
789
|
+
const c = cfg ?? DEFAULT_AUTH_CONFIG;
|
|
790
|
+
const now = Date.now();
|
|
791
|
+
const updated = await updateSessionField(sessionId, 'lastActiveAt', now, undefined, c);
|
|
792
|
+
if (!updated)
|
|
793
|
+
return;
|
|
794
|
+
if (!c.persistSessionMetadata) {
|
|
795
|
+
const redis = getRedis();
|
|
796
|
+
const raw = await redis.get(sessionKey(sessionId));
|
|
797
|
+
if (raw) {
|
|
798
|
+
const rec = JSON.parse(raw);
|
|
799
|
+
if (rec.expiresAt <= now) {
|
|
800
|
+
await deleteSessionImpl(sessionId, c);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
},
|
|
805
|
+
async setRefreshToken(sessionId, refreshToken, cfg) {
|
|
806
|
+
const redis = getRedis();
|
|
807
|
+
const raw = await redis.get(sessionKey(sessionId));
|
|
808
|
+
if (!raw)
|
|
809
|
+
return;
|
|
810
|
+
const rec = JSON.parse(raw);
|
|
811
|
+
const tokenHash = hashToken(refreshToken);
|
|
812
|
+
const oldHash = typeof rec.refreshToken === 'string' ? rec.refreshToken : null;
|
|
813
|
+
rec.refreshToken = tokenHash;
|
|
814
|
+
const refreshExpiry = (cfg ?? DEFAULT_AUTH_CONFIG).refreshToken?.refreshTokenExpiry ?? 2_592_000;
|
|
815
|
+
await writeSessionRecord(sessionId, rec, cfg);
|
|
816
|
+
if (oldHash && oldHash !== tokenHash) {
|
|
817
|
+
await redis.del(refreshTokenKey(oldHash));
|
|
818
|
+
}
|
|
819
|
+
await redis.set(refreshTokenKey(tokenHash), sessionId, 'EX', refreshExpiry);
|
|
820
|
+
},
|
|
821
|
+
async getSessionByRefreshToken(refreshToken, cfg) {
|
|
822
|
+
const redis = getRedis();
|
|
823
|
+
const tokenHash = hashToken(refreshToken);
|
|
824
|
+
const sessionId = await redis.get(refreshTokenKey(tokenHash));
|
|
825
|
+
if (!sessionId)
|
|
826
|
+
return null;
|
|
827
|
+
const raw = await redis.get(sessionKey(sessionId));
|
|
828
|
+
if (!raw)
|
|
829
|
+
return null;
|
|
830
|
+
const rec = JSON.parse(raw);
|
|
831
|
+
if (typeof rec.lastActiveAt === 'number' && isIdleExpired(rec.lastActiveAt, cfg)) {
|
|
832
|
+
await deleteSessionImpl(sessionId, cfg);
|
|
833
|
+
return null;
|
|
834
|
+
}
|
|
835
|
+
if (timingSafeEqual(rec.refreshToken ?? '', tokenHash)) {
|
|
836
|
+
return { sessionId: rec.sessionId, userId: rec.userId, newRefreshToken: refreshToken };
|
|
837
|
+
}
|
|
838
|
+
if (timingSafeEqual(rec.prevRefreshToken ?? '', tokenHash) &&
|
|
839
|
+
rec.prevTokenExpiresAt &&
|
|
840
|
+
rec.prevTokenExpiresAt > Date.now()) {
|
|
841
|
+
return {
|
|
842
|
+
sessionId: rec.sessionId,
|
|
843
|
+
userId: rec.userId,
|
|
844
|
+
newRefreshToken: rec.refreshTokenPlain ?? rec.refreshToken,
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
if (timingSafeEqual(rec.prevRefreshToken ?? '', tokenHash)) {
|
|
848
|
+
await deleteSessionImpl(sessionId, cfg);
|
|
849
|
+
return null;
|
|
850
|
+
}
|
|
851
|
+
return null;
|
|
852
|
+
},
|
|
853
|
+
async rotateRefreshToken(sessionId, newRefreshToken, newAccessToken, cfg) {
|
|
854
|
+
const c = cfg ?? DEFAULT_AUTH_CONFIG;
|
|
855
|
+
const redis = getRedis();
|
|
856
|
+
const raw = await redis.get(sessionKey(sessionId));
|
|
857
|
+
if (!raw)
|
|
858
|
+
return;
|
|
859
|
+
const rec = JSON.parse(raw);
|
|
860
|
+
const graceSeconds = c.refreshToken?.rotationGraceSeconds ?? 30;
|
|
861
|
+
const refreshExpiry = c.refreshToken?.refreshTokenExpiry ?? 2_592_000;
|
|
862
|
+
const newHash = hashToken(newRefreshToken);
|
|
863
|
+
const oldHash = rec.refreshToken;
|
|
864
|
+
const oldPrevHash = rec.prevRefreshToken;
|
|
865
|
+
rec.prevRefreshToken = oldHash;
|
|
866
|
+
rec.prevTokenExpiresAt = Date.now() + graceSeconds * 1000;
|
|
867
|
+
rec.refreshToken = newHash;
|
|
868
|
+
rec.refreshTokenPlain = newRefreshToken;
|
|
869
|
+
rec.token = newAccessToken;
|
|
870
|
+
await writeSessionRecord(sessionId, rec, c);
|
|
871
|
+
await redis.set(refreshTokenKey(newHash), sessionId, 'EX', refreshExpiry);
|
|
872
|
+
if (oldPrevHash && oldPrevHash !== oldHash) {
|
|
873
|
+
await redis.del(refreshTokenKey(oldPrevHash));
|
|
874
|
+
}
|
|
875
|
+
if (oldHash) {
|
|
876
|
+
const oldKeyTtl = Math.max(graceSeconds, 60);
|
|
877
|
+
await redis.expire(refreshTokenKey(oldHash), oldKeyTtl);
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
async getSessionFingerprint(sessionId) {
|
|
881
|
+
const redis = getRedis();
|
|
882
|
+
const raw = await redis.get(sessionKey(sessionId));
|
|
883
|
+
if (!raw)
|
|
884
|
+
return null;
|
|
885
|
+
const rec = JSON.parse(raw);
|
|
886
|
+
return rec.fingerprint ?? null;
|
|
887
|
+
},
|
|
888
|
+
async setSessionFingerprint(sessionId, fingerprint) {
|
|
889
|
+
await updateSessionField(sessionId, 'fingerprint', fingerprint);
|
|
890
|
+
},
|
|
891
|
+
async setMfaVerifiedAt(sessionId) {
|
|
892
|
+
const now = Math.floor(Date.now() / 1000);
|
|
893
|
+
await updateSessionField(sessionId, 'mfaVerifiedAt', now);
|
|
894
|
+
},
|
|
895
|
+
async getMfaVerifiedAt(sessionId) {
|
|
896
|
+
const redis = getRedis();
|
|
897
|
+
const raw = await redis.get(sessionKey(sessionId));
|
|
898
|
+
if (!raw)
|
|
899
|
+
return null;
|
|
900
|
+
const rec = JSON.parse(raw);
|
|
901
|
+
return rec.mfaVerifiedAt ?? null;
|
|
902
|
+
},
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
export function createMongoSessionRepository(conn, mg) {
|
|
906
|
+
function getSessionModel() {
|
|
907
|
+
if (conn.models['Session'])
|
|
908
|
+
return conn.models['Session'];
|
|
909
|
+
const { Schema } = mg;
|
|
910
|
+
const sessionSchema = new Schema({
|
|
911
|
+
sessionId: { type: String, required: true, unique: true },
|
|
912
|
+
userId: { type: String, required: true, index: true },
|
|
913
|
+
token: { type: String, default: null },
|
|
914
|
+
createdAt: { type: Date, required: true },
|
|
915
|
+
lastActiveAt: { type: Date, required: true },
|
|
916
|
+
expiresAt: { type: Date, required: true },
|
|
917
|
+
ipAddress: { type: String },
|
|
918
|
+
userAgent: { type: String },
|
|
919
|
+
refreshToken: { type: String, default: null },
|
|
920
|
+
prevRefreshToken: { type: String, default: null },
|
|
921
|
+
prevTokenExpiresAt: { type: Date, default: null },
|
|
922
|
+
refreshTokenPlain: { type: String, default: null },
|
|
923
|
+
fingerprint: { type: String, default: null },
|
|
924
|
+
mfaVerifiedAt: { type: Number, default: null },
|
|
925
|
+
}, { collection: 'sessions', timestamps: false });
|
|
926
|
+
sessionSchema.index({ refreshToken: 1 }, { unique: true, partialFilterExpression: { refreshToken: { $type: 'string' } } });
|
|
927
|
+
if (!DEFAULT_AUTH_CONFIG.persistSessionMetadata) {
|
|
928
|
+
sessionSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
|
|
929
|
+
}
|
|
930
|
+
return conn.model('Session', sessionSchema);
|
|
931
|
+
}
|
|
932
|
+
function deleteSessionImpl(sessionId, cfg) {
|
|
933
|
+
const c = cfg ?? DEFAULT_AUTH_CONFIG;
|
|
934
|
+
const Session = getSessionModel();
|
|
935
|
+
if (c.persistSessionMetadata) {
|
|
936
|
+
return Session.updateOne({ sessionId }, {
|
|
937
|
+
$set: {
|
|
938
|
+
token: null,
|
|
939
|
+
refreshToken: null,
|
|
940
|
+
prevRefreshToken: null,
|
|
941
|
+
prevTokenExpiresAt: null,
|
|
942
|
+
},
|
|
943
|
+
}).then(() => { });
|
|
944
|
+
}
|
|
945
|
+
return Session.deleteOne({ sessionId }).then(() => { });
|
|
946
|
+
}
|
|
947
|
+
return {
|
|
948
|
+
async createSession(userId, token, sessionId, metadata, cfg) {
|
|
949
|
+
const now = new Date();
|
|
950
|
+
const expiresAt = new Date(Date.now() + getSessionTtlMs(cfg));
|
|
951
|
+
await getSessionModel().create({
|
|
952
|
+
sessionId,
|
|
953
|
+
userId,
|
|
954
|
+
token,
|
|
955
|
+
createdAt: now,
|
|
956
|
+
lastActiveAt: now,
|
|
957
|
+
expiresAt,
|
|
958
|
+
ipAddress: metadata?.ipAddress,
|
|
959
|
+
userAgent: metadata?.userAgent,
|
|
960
|
+
});
|
|
961
|
+
},
|
|
962
|
+
async atomicCreateSession(userId, token, sessionId, maxSessions, metadata, cfg) {
|
|
963
|
+
const c = cfg ?? DEFAULT_AUTH_CONFIG;
|
|
964
|
+
const session = await conn.startSession();
|
|
965
|
+
try {
|
|
966
|
+
await session.withTransaction(async () => {
|
|
967
|
+
const Session = getSessionModel();
|
|
968
|
+
const now = new Date();
|
|
969
|
+
let activeCount = await Session.countDocuments({ userId, token: { $ne: null }, expiresAt: { $gt: now } }, { session });
|
|
970
|
+
while (activeCount >= maxSessions) {
|
|
971
|
+
const oldest = await Session.findOne({ userId, token: { $ne: null }, expiresAt: { $gt: now } }, 'sessionId', { session, sort: { createdAt: 1 } }).lean();
|
|
972
|
+
if (!oldest)
|
|
973
|
+
break;
|
|
974
|
+
if (c.persistSessionMetadata) {
|
|
975
|
+
await Session.updateOne({ sessionId: oldest.sessionId }, {
|
|
976
|
+
$set: {
|
|
977
|
+
token: null,
|
|
978
|
+
refreshToken: null,
|
|
979
|
+
prevRefreshToken: null,
|
|
980
|
+
prevTokenExpiresAt: null,
|
|
981
|
+
},
|
|
982
|
+
}, { session });
|
|
983
|
+
}
|
|
984
|
+
else {
|
|
985
|
+
await Session.deleteOne({ sessionId: oldest.sessionId }, { session });
|
|
986
|
+
}
|
|
987
|
+
activeCount--;
|
|
988
|
+
}
|
|
989
|
+
const expiresAt = new Date(Date.now() + getSessionTtlMs(c));
|
|
990
|
+
await Session.create([
|
|
991
|
+
{
|
|
992
|
+
sessionId,
|
|
993
|
+
userId,
|
|
994
|
+
token,
|
|
995
|
+
createdAt: now,
|
|
996
|
+
lastActiveAt: now,
|
|
997
|
+
expiresAt,
|
|
998
|
+
ipAddress: metadata?.ipAddress,
|
|
999
|
+
userAgent: metadata?.userAgent,
|
|
1000
|
+
},
|
|
1001
|
+
], { session });
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
finally {
|
|
1005
|
+
await session.endSession();
|
|
1006
|
+
}
|
|
1007
|
+
},
|
|
1008
|
+
async getSession(sessionId, cfg) {
|
|
1009
|
+
const doc = (await getSessionModel()
|
|
1010
|
+
.findOne({ sessionId, expiresAt: { $gt: new Date() } }, 'token lastActiveAt')
|
|
1011
|
+
.lean());
|
|
1012
|
+
if (!doc?.token)
|
|
1013
|
+
return null;
|
|
1014
|
+
if (isIdleExpired(doc.lastActiveAt.getTime(), cfg)) {
|
|
1015
|
+
await deleteSessionImpl(sessionId, cfg);
|
|
1016
|
+
return null;
|
|
1017
|
+
}
|
|
1018
|
+
return doc.token;
|
|
1019
|
+
},
|
|
1020
|
+
async deleteSession(sessionId, cfg) {
|
|
1021
|
+
await deleteSessionImpl(sessionId, cfg);
|
|
1022
|
+
},
|
|
1023
|
+
async getUserSessions(userId, cfg) {
|
|
1024
|
+
const c = cfg ?? DEFAULT_AUTH_CONFIG;
|
|
1025
|
+
const now = new Date();
|
|
1026
|
+
const includeInactive = c.includeInactiveSessions;
|
|
1027
|
+
const persist = c.persistSessionMetadata;
|
|
1028
|
+
const query = { userId };
|
|
1029
|
+
if (!includeInactive) {
|
|
1030
|
+
query.token = { $ne: null };
|
|
1031
|
+
query.expiresAt = { $gt: now };
|
|
1032
|
+
}
|
|
1033
|
+
const docs = await getSessionModel().find(query).lean();
|
|
1034
|
+
const results = [];
|
|
1035
|
+
for (const doc of docs) {
|
|
1036
|
+
const isActive = !!doc.token && doc.expiresAt > now;
|
|
1037
|
+
if (!isActive && !persist)
|
|
1038
|
+
continue;
|
|
1039
|
+
if (!isActive && !includeInactive)
|
|
1040
|
+
continue;
|
|
1041
|
+
results.push({
|
|
1042
|
+
sessionId: doc.sessionId,
|
|
1043
|
+
createdAt: doc.createdAt.getTime(),
|
|
1044
|
+
lastActiveAt: doc.lastActiveAt.getTime(),
|
|
1045
|
+
expiresAt: doc.expiresAt.getTime(),
|
|
1046
|
+
ipAddress: doc.ipAddress,
|
|
1047
|
+
userAgent: doc.userAgent,
|
|
1048
|
+
isActive,
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
return results;
|
|
1052
|
+
},
|
|
1053
|
+
async getActiveSessionCount(userId) {
|
|
1054
|
+
const now = new Date();
|
|
1055
|
+
return getSessionModel().countDocuments({
|
|
1056
|
+
userId,
|
|
1057
|
+
token: { $ne: null },
|
|
1058
|
+
expiresAt: { $gt: now },
|
|
1059
|
+
});
|
|
1060
|
+
},
|
|
1061
|
+
async evictOldestSession(userId, cfg) {
|
|
1062
|
+
const now = new Date();
|
|
1063
|
+
const oldest = await getSessionModel()
|
|
1064
|
+
.findOne({ userId, token: { $ne: null }, expiresAt: { $gt: now } }, 'sessionId')
|
|
1065
|
+
.sort({ createdAt: 1 })
|
|
1066
|
+
.lean();
|
|
1067
|
+
if (oldest)
|
|
1068
|
+
await deleteSessionImpl(oldest.sessionId, cfg);
|
|
1069
|
+
},
|
|
1070
|
+
async updateSessionLastActive(sessionId) {
|
|
1071
|
+
await getSessionModel().updateOne({ sessionId }, { $set: { lastActiveAt: new Date() } });
|
|
1072
|
+
},
|
|
1073
|
+
async setRefreshToken(sessionId, refreshToken) {
|
|
1074
|
+
const tokenHash = hashToken(refreshToken);
|
|
1075
|
+
await getSessionModel().updateOne({ sessionId }, { $set: { refreshToken: tokenHash } });
|
|
1076
|
+
},
|
|
1077
|
+
async getSessionByRefreshToken(refreshToken, cfg) {
|
|
1078
|
+
const Session = getSessionModel();
|
|
1079
|
+
const tokenHash = hashToken(refreshToken);
|
|
1080
|
+
let doc = (await Session.findOne({ refreshToken: tokenHash }).lean());
|
|
1081
|
+
if (doc) {
|
|
1082
|
+
if (isIdleExpired(doc.lastActiveAt.getTime(), cfg)) {
|
|
1083
|
+
await deleteSessionImpl(doc.sessionId, cfg);
|
|
1084
|
+
return null;
|
|
1085
|
+
}
|
|
1086
|
+
return { sessionId: doc.sessionId, userId: doc.userId, newRefreshToken: refreshToken };
|
|
1087
|
+
}
|
|
1088
|
+
doc = (await Session.findOne({ prevRefreshToken: tokenHash }).lean());
|
|
1089
|
+
if (!doc)
|
|
1090
|
+
return null;
|
|
1091
|
+
if (isIdleExpired(doc.lastActiveAt.getTime(), cfg)) {
|
|
1092
|
+
await deleteSessionImpl(doc.sessionId, cfg);
|
|
1093
|
+
return null;
|
|
1094
|
+
}
|
|
1095
|
+
if (doc.prevTokenExpiresAt && doc.prevTokenExpiresAt > new Date()) {
|
|
1096
|
+
return {
|
|
1097
|
+
sessionId: doc.sessionId,
|
|
1098
|
+
userId: doc.userId,
|
|
1099
|
+
newRefreshToken: doc.refreshTokenPlain ?? doc.refreshToken,
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
await deleteSessionImpl(doc.sessionId, cfg);
|
|
1103
|
+
return null;
|
|
1104
|
+
},
|
|
1105
|
+
async rotateRefreshToken(sessionId, newRefreshToken, newAccessToken, cfg) {
|
|
1106
|
+
const graceSeconds = (cfg ?? DEFAULT_AUTH_CONFIG).refreshToken?.rotationGraceSeconds ?? 30;
|
|
1107
|
+
const Session = getSessionModel();
|
|
1108
|
+
const doc = await Session.findOne({ sessionId });
|
|
1109
|
+
if (!doc)
|
|
1110
|
+
return;
|
|
1111
|
+
const newHash = hashToken(newRefreshToken);
|
|
1112
|
+
doc.prevRefreshToken = doc.refreshToken;
|
|
1113
|
+
doc.prevTokenExpiresAt = new Date(Date.now() + graceSeconds * 1000);
|
|
1114
|
+
doc.refreshToken = newHash;
|
|
1115
|
+
doc.refreshTokenPlain = newRefreshToken;
|
|
1116
|
+
doc.token = newAccessToken;
|
|
1117
|
+
await doc.save();
|
|
1118
|
+
},
|
|
1119
|
+
async getSessionFingerprint(sessionId) {
|
|
1120
|
+
const doc = await getSessionModel().findOne({ sessionId }, 'fingerprint').lean();
|
|
1121
|
+
return doc?.fingerprint ?? null;
|
|
1122
|
+
},
|
|
1123
|
+
async setSessionFingerprint(sessionId, fingerprint) {
|
|
1124
|
+
await getSessionModel().updateOne({ sessionId }, { $set: { fingerprint } });
|
|
1125
|
+
},
|
|
1126
|
+
async setMfaVerifiedAt(sessionId) {
|
|
1127
|
+
const now = Math.floor(Date.now() / 1000);
|
|
1128
|
+
await getSessionModel().updateOne({ sessionId }, { $set: { mfaVerifiedAt: now } });
|
|
1129
|
+
},
|
|
1130
|
+
async getMfaVerifiedAt(sessionId) {
|
|
1131
|
+
const doc = await getSessionModel().findOne({ sessionId }, 'mfaVerifiedAt').lean();
|
|
1132
|
+
return doc?.mfaVerifiedAt ?? null;
|
|
1133
|
+
},
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1136
|
+
// ---------------------------------------------------------------------------
|
|
1137
|
+
// Factory map
|
|
1138
|
+
// ---------------------------------------------------------------------------
|
|
1139
|
+
export const sessionFactories = {
|
|
1140
|
+
memory: () => createMemorySessionRepository(),
|
|
1141
|
+
sqlite: infra => createSqliteSessionRepository(infra.getSqliteDb()),
|
|
1142
|
+
redis: infra => createRedisSessionRepository(infra.getRedis, infra.appName),
|
|
1143
|
+
mongo: infra => {
|
|
1144
|
+
const { conn, mg } = infra.getMongo();
|
|
1145
|
+
return createMongoSessionRepository(conn, mg);
|
|
1146
|
+
},
|
|
1147
|
+
postgres: () => {
|
|
1148
|
+
throw new Error('[bunshot-auth] postgres store is not yet supported for session repository');
|
|
1149
|
+
},
|
|
1150
|
+
};
|
|
1151
|
+
// ---------------------------------------------------------------------------
|
|
1152
|
+
// Public API — thin wrappers delegating to ISessionRepository
|
|
1153
|
+
//
|
|
1154
|
+
// Callers pass the repo directly (resolved in bootstrap via sessionFactories).
|
|
1155
|
+
// ---------------------------------------------------------------------------
|
|
1156
|
+
export const createSession = async (repo, userId, token, sessionId, metadata, config) => {
|
|
1157
|
+
await repo.createSession(userId, token, sessionId, metadata, config);
|
|
1158
|
+
};
|
|
1159
|
+
export const atomicCreateSession = async (repo, userId, token, sessionId, maxSessions, metadata, config) => {
|
|
1160
|
+
await repo.atomicCreateSession(userId, token, sessionId, maxSessions, metadata, config);
|
|
1161
|
+
};
|
|
1162
|
+
export const getSession = async (repo, sessionId, config) => {
|
|
1163
|
+
const cfg = config ?? DEFAULT_AUTH_CONFIG;
|
|
1164
|
+
return repo.getSession(sessionId, cfg);
|
|
1165
|
+
};
|
|
1166
|
+
export const deleteSession = async (repo, sessionId, config) => {
|
|
1167
|
+
await repo.deleteSession(sessionId, config);
|
|
1168
|
+
};
|
|
1169
|
+
export const getUserSessions = async (repo, userId, config) => {
|
|
1170
|
+
return repo.getUserSessions(userId, config);
|
|
1171
|
+
};
|
|
1172
|
+
export const getActiveSessionCount = async (repo, userId, config) => {
|
|
1173
|
+
return repo.getActiveSessionCount(userId, config);
|
|
1174
|
+
};
|
|
1175
|
+
export const evictOldestSession = async (repo, userId, config) => {
|
|
1176
|
+
await repo.evictOldestSession(userId, config);
|
|
1177
|
+
};
|
|
1178
|
+
export const deleteUserSessions = async (repo, userId, config) => {
|
|
1179
|
+
const sessions = await repo.getUserSessions(userId, config);
|
|
1180
|
+
await Promise.all(sessions.map(s => repo.deleteSession(s.sessionId, config)));
|
|
1181
|
+
};
|
|
1182
|
+
export const deleteOtherSessions = async (repo, userId, currentSessionId, config) => {
|
|
1183
|
+
const sessions = await repo.getUserSessions(userId, config);
|
|
1184
|
+
const others = sessions.filter(s => s.sessionId !== currentSessionId);
|
|
1185
|
+
await Promise.all(others.map(s => repo.deleteSession(s.sessionId, config)));
|
|
1186
|
+
};
|
|
1187
|
+
export const updateSessionLastActive = async (repo, sessionId, config) => {
|
|
1188
|
+
await repo.updateSessionLastActive(sessionId, config);
|
|
1189
|
+
};
|
|
1190
|
+
export const setRefreshToken = async (repo, sessionId, refreshToken, config) => {
|
|
1191
|
+
await repo.setRefreshToken(sessionId, refreshToken, config);
|
|
1192
|
+
};
|
|
1193
|
+
export const getSessionByRefreshToken = async (repo, refreshToken, config) => {
|
|
1194
|
+
return repo.getSessionByRefreshToken(refreshToken, config);
|
|
1195
|
+
};
|
|
1196
|
+
export const rotateRefreshToken = async (repo, sessionId, newRefreshToken, newAccessToken, config) => {
|
|
1197
|
+
await repo.rotateRefreshToken(sessionId, newRefreshToken, newAccessToken, config);
|
|
1198
|
+
await repo.updateSessionLastActive(sessionId, config);
|
|
1199
|
+
};
|
|
1200
|
+
export const getSessionFingerprint = async (repo, sessionId) => {
|
|
1201
|
+
return repo.getSessionFingerprint(sessionId);
|
|
1202
|
+
};
|
|
1203
|
+
export const setSessionFingerprint = async (repo, sessionId, fingerprint) => {
|
|
1204
|
+
await repo.setSessionFingerprint(sessionId, fingerprint);
|
|
1205
|
+
};
|
|
1206
|
+
export const setMfaVerifiedAt = async (repo, sessionId) => {
|
|
1207
|
+
await repo.setMfaVerifiedAt(sessionId);
|
|
1208
|
+
};
|
|
1209
|
+
export const getMfaVerifiedAt = async (repo, sessionId) => {
|
|
1210
|
+
return repo.getMfaVerifiedAt(sessionId);
|
|
1211
|
+
};
|