@eaccess/auth 0.1.19 → 0.1.21
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/dist/index.cjs +63 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +62 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/auth-manager.ts","../src/types.ts","../src/queries.ts","../src/activity-logger.ts","../src/errors.ts","../src/util.ts","../src/providers/base-provider.ts","../src/providers/github-provider.ts","../src/providers/google-provider.ts","../src/providers/azure-provider.ts","../src/two-factor/totp-provider.ts","../src/two-factor/otp-provider.ts","../src/two-factor/two-factor-manager.ts","../src/auth-functions.ts","../src/middleware.ts","../src/schema.ts","../src/auth-context.ts","../src/user-roles.ts"],"sourcesContent":["export { createAuthMiddleware } from \"./middleware.js\";\nexport { createAuthTables, dropAuthTables, cleanupExpiredTokens, getAuthTableStats } from \"./schema.js\";\nexport { createAuthContext, type AuthContext } from \"./auth-context.js\";\nexport * as authFunctions from \"./auth-functions.js\";\nexport * from \"./auth-functions.js\";\nexport { addRoleToUser, removeRoleFromUser, setUserRoles, getUserRoles, type UserIdentifier } from \"./user-roles.js\";\n\nexport type {\n AuthConfig,\n AuthAccount,\n AuthProvider,\n AuthConfirmation,\n AuthRemember,\n AuthReset,\n AuthActivity,\n AuthSession,\n TokenCallback,\n AuthManager,\n OAuthProvider,\n OAuthUserData,\n OAuthCallbackResult,\n OAuthProviderConfig,\n GitHubProviderConfig,\n GoogleProviderConfig,\n AzureProviderConfig,\n AuthActivityActionType,\n TwoFactorMethod,\n TwoFactorToken,\n TwoFactorSetupResult,\n TwoFactorChallenge,\n} from \"./types.js\";\n\nexport { AuthStatus, AuthRole, AuthActivityAction, TwoFactorMechanism } from \"./types.js\";\n\nexport {\n AuthError,\n ConfirmationExpiredError,\n ConfirmationNotFoundError,\n EmailNotVerifiedError,\n EmailTakenError,\n InvalidEmailError,\n InvalidPasswordError,\n InvalidTokenError,\n ResetDisabledError,\n ResetExpiredError,\n ResetNotFoundError,\n TooManyResetsError,\n UserInactiveError,\n UserNotFoundError,\n UserNotLoggedInError,\n SecondFactorRequiredError,\n InvalidTwoFactorCodeError,\n TwoFactorExpiredError,\n TwoFactorNotSetupError,\n TwoFactorAlreadyEnabledError,\n InvalidBackupCodeError,\n TwoFactorSetupIncompleteError,\n} from \"./errors.js\";\n\nexport { isValidEmail, validateEmail } from \"./util.js\";\n\nexport { ActivityLogger } from \"./activity-logger.js\";\n\nexport { TwoFactorManager, TotpProvider, OtpProvider } from \"./two-factor/index.js\";\n\nexport { GitHubProvider, GoogleProvider, AzureProvider, BaseOAuthProvider } from \"./providers/index.js\";\n","import { hash } from \"@prsm/hash\";\nimport ms from \"@prsm/ms\";\nimport type { Request, Response } from \"express\";\nimport type { AuthConfig, AuthAccount, AuthSession, TokenCallback, AuthManager as IAuthManager, OAuthProvider } from \"./types.js\";\nimport { AuthStatus, AuthRole, AuthActivityAction } from \"./types.js\";\nimport { AuthQueries } from \"./queries.js\";\nimport { ActivityLogger } from \"./activity-logger.js\";\nimport { validateEmail, createMapFromEnum } from \"./util.js\";\nimport {\n ConfirmationExpiredError,\n ConfirmationNotFoundError,\n EmailNotVerifiedError,\n EmailTakenError,\n InvalidPasswordError,\n InvalidTokenError,\n ResetDisabledError,\n ResetExpiredError,\n ResetNotFoundError,\n TooManyResetsError,\n UserInactiveError,\n UserNotFoundError,\n UserNotLoggedInError,\n SecondFactorRequiredError,\n TwoFactorExpiredError,\n} from \"./errors.js\";\nimport { GitHubProvider, GoogleProvider, AzureProvider } from \"./providers/index.js\";\nimport { TwoFactorManager } from \"./two-factor/index.js\";\nimport * as authFunctions from \"./auth-functions.js\";\n\nexport class AuthManager implements IAuthManager {\n private req: Request;\n private res: Response;\n private config: AuthConfig;\n private queries: AuthQueries;\n private activityLogger: ActivityLogger;\n public providers: {\n github?: OAuthProvider;\n google?: OAuthProvider;\n azure?: OAuthProvider;\n };\n\n public twoFactor: TwoFactorManager;\n\n constructor(req: Request, res: Response, config: AuthConfig) {\n this.req = req;\n this.res = res;\n this.config = config;\n this.queries = new AuthQueries(config);\n this.activityLogger = new ActivityLogger(config);\n this.providers = this.initializeProviders();\n this.twoFactor = new TwoFactorManager(req, res, config);\n }\n\n private initializeProviders(): {\n github?: OAuthProvider;\n google?: OAuthProvider;\n azure?: OAuthProvider;\n } {\n const providers: any = {};\n\n if (this.config.providers?.github) {\n providers.github = new GitHubProvider(this.config.providers.github, this.config, this);\n }\n\n if (this.config.providers?.google) {\n providers.google = new GoogleProvider(this.config.providers.google, this.config, this);\n }\n\n if (this.config.providers?.azure) {\n providers.azure = new AzureProvider(this.config.providers.azure, this.config, this);\n }\n\n return providers;\n }\n\n private generateAutoUserId(): string {\n // Generate a UUID for auto users\n return crypto.randomUUID();\n }\n\n private async shouldRequire2FA(account: AuthAccount): Promise<boolean> {\n // skip 2FA for OAuth users unless explicitly configured\n const providers = await this.queries.findProvidersByAccountId(account.id);\n const hasOAuthProviders = providers.length > 0;\n\n if (hasOAuthProviders && !this.config.twoFactor?.requireForOAuth) {\n return false;\n }\n return true;\n }\n\n private validatePassword(password: string): void {\n const minLength = this.config.minPasswordLength || 8;\n const maxLength = this.config.maxPasswordLength || 64;\n\n if (typeof password !== \"string\") {\n throw new InvalidPasswordError();\n }\n\n if (password.length < minLength) {\n throw new InvalidPasswordError();\n }\n\n if (password.length > maxLength) {\n throw new InvalidPasswordError();\n }\n }\n\n private getRoleMap(): Record<number, string> {\n return createMapFromEnum(AuthRole);\n }\n\n private getStatusMap(): Record<number, string> {\n return createMapFromEnum(AuthStatus);\n }\n\n private async getAuthAccount(): Promise<AuthAccount | null> {\n if (!this.req.session?.auth?.accountId) {\n return null;\n }\n\n return await this.queries.findAccountById(this.req.session.auth.accountId);\n }\n\n private setRememberCookie(token: string | null, expires: Date): void {\n const cookieName = this.config.rememberCookieName || \"remember_token\";\n const cookieConfig = this.config.cookie || {};\n\n if (token === null) {\n this.res.clearCookie(cookieName, {\n domain: cookieConfig.domain,\n secure: cookieConfig.secure ?? this.req.secure,\n sameSite: cookieConfig.sameSite,\n });\n } else {\n this.res.cookie(cookieName, token, {\n expires,\n httpOnly: true,\n secure: cookieConfig.secure ?? this.req.secure,\n domain: cookieConfig.domain,\n sameSite: cookieConfig.sameSite,\n });\n }\n }\n\n private getRememberToken(): { token: string | null } {\n const { cookies } = this.req as any;\n if (!cookies) {\n return { token: null };\n }\n\n const cookieName = this.config.rememberCookieName || \"remember_token\";\n const token = cookies[cookieName];\n\n return { token: token || null };\n }\n\n private async regenerateSession(): Promise<void> {\n const { auth } = this.req.session;\n\n return new Promise<void>((resolve, reject) => {\n this.req.session.regenerate((err: any) => {\n if (err) {\n reject(err);\n return;\n }\n this.req.session.auth = auth;\n resolve();\n });\n });\n }\n\n async resyncSession(force = false): Promise<void> {\n if (!this.isLoggedIn()) {\n return;\n }\n\n if (this.req.session.auth!.shouldForceLogout) {\n await this.logout();\n return;\n }\n\n const interval = ms(this.config.resyncInterval || \"30s\");\n const lastResync = new Date(this.req.session.auth!.lastResync);\n\n if (!force && lastResync && lastResync.getTime() > Date.now() - interval) {\n return;\n }\n\n const account = await this.getAuthAccount();\n\n if (!account) {\n await this.logout();\n return;\n }\n\n if (account.force_logout > this.req.session.auth!.forceLogout) {\n await this.logout();\n return;\n }\n\n this.req.session.auth!.shouldForceLogout = false;\n this.req.session.auth!.email = account.email;\n this.req.session.auth!.status = account.status;\n this.req.session.auth!.rolemask = account.rolemask;\n this.req.session.auth!.verified = account.verified;\n this.req.session.auth!.hasPassword = account.password !== null;\n this.req.session.auth!.lastResync = new Date();\n }\n\n async processRememberDirective(): Promise<void> {\n if (this.isLoggedIn()) {\n return;\n }\n\n const { token } = this.getRememberToken();\n if (!token) {\n return;\n }\n\n const remember = await this.queries.findRememberToken(token);\n if (!remember) {\n this.setRememberCookie(null, new Date(0));\n return;\n }\n\n // expired?\n if (new Date() > remember.expires) {\n await this.queries.deleteRememberToken(token);\n this.setRememberCookie(null, new Date(0));\n return;\n }\n\n // clean up expired tokens for this account\n await this.queries.deleteExpiredRememberTokensForAccount(remember.account_id);\n\n // get the account and log in\n const account = await this.queries.findAccountById(remember.account_id);\n if (!account) {\n await this.queries.deleteRememberToken(token);\n this.setRememberCookie(null, new Date(0));\n return;\n }\n\n // pass false to avoid creating a new remember token - we're restoring from an existing one\n await this.onLoginSuccessful(account, false);\n }\n\n private async onLoginSuccessful(account: AuthAccount, remember = false): Promise<void> {\n await this.queries.updateAccountLastLogin(account.id);\n\n return new Promise<void>((resolve, reject) => {\n if (!this.req.session?.regenerate) {\n resolve();\n return;\n }\n\n this.req.session.regenerate(async (err: any) => {\n if (err) {\n reject(err);\n return;\n }\n\n const session: AuthSession = {\n loggedIn: true,\n accountId: account.id,\n userId: account.user_id,\n email: account.email,\n status: account.status,\n rolemask: account.rolemask,\n remembered: remember,\n lastResync: new Date(),\n lastRememberCheck: new Date(),\n forceLogout: account.force_logout,\n verified: account.verified,\n hasPassword: account.password !== null,\n shouldForceLogout: false,\n };\n\n this.req.session.auth = session;\n\n if (remember) {\n await this.createRememberDirective(account);\n }\n\n this.req.session.save((err: any) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n });\n }\n\n private async createRememberDirective(account: AuthAccount): Promise<string> {\n const token = hash.encode(account.email);\n const duration = this.config.rememberDuration || \"30d\";\n const expires = new Date(Date.now() + ms(duration));\n\n await this.queries.createRememberToken({\n accountId: account.id,\n token,\n expires,\n });\n\n this.setRememberCookie(token, expires);\n\n await this.activityLogger.logActivity(account.id, AuthActivityAction.RememberTokenCreated, this.req, true, { email: account.email, duration });\n\n return token;\n }\n\n /**\n * Check if the current user is logged in.\n * @returns true if user has an active authenticated session\n */\n isLoggedIn(): boolean {\n return this.req.session?.auth?.loggedIn ?? false;\n }\n\n /**\n * Authenticate user with email and password.\n * Creates a new session and optionally sets a remember token for persistent login.\n *\n * @param email - User's email address\n * @param password - Plain text password\n * @param remember - If true, sets a persistent cookie for auto-login on future visits\n * @throws {UserNotFoundError} Account with this email doesn't exist\n * @throws {InvalidPasswordError} Password is incorrect\n * @throws {EmailNotVerifiedError} Account exists but email is not verified\n * @throws {UserInactiveError} Account is banned, locked, or otherwise inactive\n */\n async login(email: string, password: string, remember = false): Promise<void> {\n try {\n const account = await this.queries.findAccountByEmail(email);\n\n if (!account) {\n await this.activityLogger.logActivity(null, AuthActivityAction.FailedLogin, this.req, false, { email, reason: \"account_not_found\" });\n throw new UserNotFoundError();\n }\n\n if (!account.password || !hash.verify(account.password, password)) {\n await this.activityLogger.logActivity(account.id, AuthActivityAction.FailedLogin, this.req, false, { email, reason: \"invalid_password\" });\n throw new InvalidPasswordError();\n }\n\n if (!account.verified) {\n await this.activityLogger.logActivity(account.id, AuthActivityAction.FailedLogin, this.req, false, { email, reason: \"email_not_verified\" });\n throw new EmailNotVerifiedError();\n }\n\n if (account.status !== AuthStatus.Normal) {\n await this.activityLogger.logActivity(account.id, AuthActivityAction.FailedLogin, this.req, false, { email, reason: \"account_inactive\", status: account.status });\n throw new UserInactiveError();\n }\n\n // check if 2FA is enabled and required for this user\n if (this.config.twoFactor?.enabled && (await this.shouldRequire2FA(account))) {\n const twoFactorMethods = await this.queries.findTwoFactorMethodsByAccountId(account.id);\n const enabledMethods = twoFactorMethods.filter((method) => method.verified);\n\n if (enabledMethods.length > 0) {\n // create 2FA challenge\n const challenge = await this.twoFactor.createChallenge(account.id);\n\n // set 2FA session state (user NOT logged in yet)\n const expiryDuration = this.config.twoFactor?.tokenExpiry || \"5m\";\n const expiresAt = new Date(Date.now() + ms(expiryDuration));\n\n this.req.session.auth = {\n loggedIn: false,\n accountId: 0,\n userId: \"\",\n email: \"\",\n status: 0,\n rolemask: 0,\n remembered: false,\n lastResync: new Date(),\n lastRememberCheck: new Date(),\n forceLogout: 0,\n verified: false,\n hasPassword: false,\n awaitingTwoFactor: {\n accountId: account.id,\n expiresAt,\n remember,\n availableMechanisms: enabledMethods.map((m) => m.mechanism),\n attemptedMechanisms: [],\n originalEmail: account.email,\n selectors: challenge.selectors,\n },\n };\n\n await this.activityLogger.logActivity(account.id, AuthActivityAction.TwoFactorFailed, this.req, true, { prompt: true, mechanisms: enabledMethods.map((m) => m.mechanism) });\n\n throw new SecondFactorRequiredError(challenge);\n }\n }\n\n await this.onLoginSuccessful(account, remember);\n await this.activityLogger.logActivity(account.id, AuthActivityAction.Login, this.req, true, { email, remember });\n } catch (error) {\n // re-throw the error after logging\n throw error;\n }\n }\n\n /**\n * Complete two-factor authentication and log in the user.\n * This should be called after receiving a SecondFactorRequiredError.\n */\n async completeTwoFactorLogin(): Promise<void> {\n const twoFactorState = this.req.session?.auth?.awaitingTwoFactor;\n\n if (!twoFactorState) {\n throw new TwoFactorExpiredError();\n }\n\n // check if the 2FA session has expired\n if (twoFactorState.expiresAt <= new Date()) {\n // clear expired 2FA state\n delete this.req.session.auth!.awaitingTwoFactor;\n throw new TwoFactorExpiredError();\n }\n\n // get the account that was awaiting 2FA\n const account = await this.queries.findAccountById(twoFactorState.accountId);\n if (!account) {\n delete this.req.session.auth!.awaitingTwoFactor;\n throw new UserNotFoundError();\n }\n\n // complete the login process\n await this.onLoginSuccessful(account, twoFactorState.remember);\n\n // clear the 2FA state\n delete this.req.session.auth!.awaitingTwoFactor;\n\n await this.activityLogger.logActivity(account.id, AuthActivityAction.Login, this.req, true, { email: account.email, remember: twoFactorState.remember, twoFactorCompleted: true });\n }\n\n /**\n * Log out the current user.\n * Clears the session and removes any remember tokens.\n */\n async logout(): Promise<void> {\n if (!this.isLoggedIn()) {\n return;\n }\n\n const accountId = this.getId();\n const email = this.getEmail();\n const { token } = this.getRememberToken();\n\n if (token) {\n await this.queries.deleteRememberToken(token);\n this.setRememberCookie(null, new Date(0));\n }\n\n this.req.session.auth = undefined;\n\n if (accountId && email) {\n await this.activityLogger.logActivity(accountId, AuthActivityAction.Logout, this.req, true, { email });\n }\n }\n\n /**\n * Register a new account.\n *\n * @param email - Email address for the new account\n * @param password - Plain text password (will be hashed)\n * @param userId - Optional user ID to link this auth account to. If not provided, a UUID will be generated automatically.\n * @param callback - If provided, account is created unverified and callback receives confirmation token. Create a URL like /confirm/{token} and call confirmEmail() in that handler. If omitted, account is immediately verified.\n * @returns The created account record\n * @throws {EmailTakenError} Email is already registered\n * @throws {InvalidPasswordError} Password doesn't meet length requirements\n */\n async register(email: string, password: string, userId?: string | number, callback?: TokenCallback): Promise<AuthAccount> {\n validateEmail(email);\n this.validatePassword(password);\n\n const existing = await this.queries.findAccountByEmail(email);\n if (existing) {\n throw new EmailTakenError();\n }\n\n const finalUserId = userId || this.generateAutoUserId();\n\n const hashedPassword = hash.encode(password);\n const verified = typeof callback !== \"function\";\n\n const account = await this.queries.createAccount({\n userId: finalUserId,\n email,\n password: hashedPassword,\n verified,\n status: AuthStatus.Normal,\n rolemask: 0,\n });\n\n if (!verified && callback) {\n await this.createConfirmationToken(account, email, callback);\n }\n\n await this.activityLogger.logActivity(account.id, AuthActivityAction.Register, this.req, true, { email, verified, userId: finalUserId });\n\n return account;\n }\n\n private async createConfirmationToken(account: AuthAccount, email: string, callback: TokenCallback): Promise<void> {\n const token = hash.encode(email);\n const expires = new Date(Date.now() + 1000 * 60 * 60 * 24 * 7); // 1 week\n\n await this.queries.createConfirmation({\n accountId: account.id,\n token,\n email,\n expires,\n });\n\n if (callback) {\n callback(token);\n }\n }\n\n /**\n * Get the current user's account ID.\n * @returns Account ID if logged in, null otherwise\n */\n getId(): number | null {\n return this.req.session?.auth?.accountId || null;\n }\n\n /**\n * Get the current user's email address.\n * @returns Email if logged in, null otherwise\n */\n getEmail(): string | null {\n return this.req.session?.auth?.email || null;\n }\n\n /**\n * Get the current user's account status.\n * @returns Status number (0=Normal, 1=Archived, 2=Banned, etc.) if logged in, null otherwise\n */\n getStatus(): number | null {\n return this.req.session?.auth?.status ?? null;\n }\n\n /**\n * Check if the current user's email is verified.\n * @returns true if verified, false if unverified, null if not logged in\n */\n getVerified(): boolean | null {\n return this.req.session?.auth?.verified ?? null;\n }\n\n /**\n * Check if the current user has a password set.\n * OAuth-only users will return false.\n * @returns true if user has a password, false if OAuth-only, null if not logged in\n */\n hasPassword(): boolean | null {\n return this.req.session?.auth?.hasPassword ?? null;\n }\n\n /**\n * Get human-readable role names for the current user or a specific rolemask.\n * @param rolemask - Optional specific rolemask to check. If omitted, uses current user's roles\n * @returns Array of role names (e.g., ['Admin', 'Editor'])\n */\n getRoleNames(rolemask?: number): string[] {\n const mask = rolemask !== undefined ? rolemask : (this.req.session?.auth?.rolemask ?? 0);\n\n if (!mask && mask !== 0) {\n return [];\n }\n\n return Object.entries(this.getRoleMap())\n .filter(([key]) => mask & parseInt(key))\n .map(([, value]) => value);\n }\n\n /**\n * Get human-readable status name for the current user.\n * @returns Status name (e.g., 'Normal', 'Banned', 'Locked') if logged in, null otherwise\n */\n getStatusName(): string | null {\n const status = this.getStatus();\n if (status === null) return null;\n return this.getStatusMap()[status] || null;\n }\n\n /**\n * Check if the current user has a specific role.\n * @param role - Role bitmask to check (e.g., AuthRole.Admin)\n * @returns true if user has the role, false otherwise\n */\n async hasRole(role: number): Promise<boolean> {\n if (this.req.session?.auth) {\n return (this.req.session.auth.rolemask & role) === role;\n }\n\n const account = await this.getAuthAccount();\n return account ? (account.rolemask & role) === role : false;\n }\n\n /**\n * Check if the current user has admin privileges.\n * @returns true if user has Admin role, false otherwise\n */\n async isAdmin(): Promise<boolean> {\n return this.hasRole(AuthRole.Admin);\n }\n\n /**\n * Check if the current user was automatically logged in via remember token.\n * @returns true if auto-logged in from persistent cookie, false if manual login or not logged in\n */\n isRemembered(): boolean {\n return this.req.session?.auth?.remembered ?? false;\n }\n\n /**\n * Request an email change for the current user.\n * Sends a confirmation token to verify the new email before changing it.\n *\n * @param newEmail - New email address\n * @param callback - Called with confirmation token. Create a URL like /confirm/{token} and call confirmEmail() in that handler\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {EmailTakenError} New email is already registered\n * @throws {UserNotFoundError} Current user account not found\n * @throws {EmailNotVerifiedError} Current account's email is not verified\n */\n async changeEmail(newEmail: string, callback: TokenCallback): Promise<void> {\n if (!this.isLoggedIn()) {\n throw new UserNotLoggedInError();\n }\n\n validateEmail(newEmail);\n\n const existing = await this.queries.findAccountByEmail(newEmail);\n if (existing) {\n throw new EmailTakenError();\n }\n\n const account = await this.getAuthAccount();\n if (!account) {\n throw new UserNotFoundError();\n }\n\n if (!account.verified) {\n throw new EmailNotVerifiedError();\n }\n\n await this.createConfirmationToken(account, newEmail, callback);\n }\n\n /**\n * Confirm an email address using a token from registration or email change.\n * Updates the account to verified status and changes email if this was from changeEmail.\n *\n * @param token - Confirmation token from registration or email change\n * @returns The confirmed email address\n * @throws {ConfirmationNotFoundError} Token is invalid or doesn't exist\n * @throws {ConfirmationExpiredError} Token has expired\n * @throws {InvalidTokenError} Token format is invalid\n */\n async confirmEmail(token: string): Promise<string> {\n const confirmation = await this.queries.findConfirmation(token);\n\n if (!confirmation) {\n throw new ConfirmationNotFoundError();\n }\n\n if (new Date(confirmation.expires) < new Date()) {\n throw new ConfirmationExpiredError();\n }\n\n if (!hash.verify(token, confirmation.email)) {\n throw new InvalidTokenError();\n }\n\n await this.queries.updateAccount(confirmation.account_id, {\n verified: true,\n email: confirmation.email,\n });\n\n if (this.isLoggedIn() && this.req.session?.auth?.accountId === confirmation.account_id) {\n this.req.session.auth.verified = true;\n this.req.session.auth.email = confirmation.email;\n }\n\n await this.queries.deleteConfirmation(token);\n\n await this.activityLogger.logActivity(confirmation.account_id, AuthActivityAction.EmailConfirmed, this.req, true, { email: confirmation.email });\n\n return confirmation.email;\n }\n\n /**\n * Confirm email and automatically log in the user.\n * Useful for \"click to verify and login\" flows.\n *\n * @param token - Confirmation token from registration\n * @param remember - Whether to set persistent login cookie\n * @throws {ConfirmationNotFoundError} Token is invalid or doesn't exist\n * @throws {ConfirmationExpiredError} Token has expired\n * @throws {InvalidTokenError} Token format is invalid\n * @throws {UserNotFoundError} Associated account no longer exists\n */\n async confirmEmailAndLogin(token: string, remember = false): Promise<void> {\n const email = await this.confirmEmail(token);\n\n if (this.isLoggedIn()) {\n return;\n }\n\n const account = await this.queries.findAccountByEmail(email);\n if (!account) {\n throw new UserNotFoundError();\n }\n\n // check if 2FA is enabled and required for this user\n if (this.config.twoFactor?.enabled && (await this.shouldRequire2FA(account))) {\n const twoFactorMethods = await this.queries.findTwoFactorMethodsByAccountId(account.id);\n const enabledMethods = twoFactorMethods.filter((method) => method.verified);\n\n if (enabledMethods.length > 0) {\n // create 2FA challenge\n const challenge = await this.twoFactor.createChallenge(account.id);\n\n // set 2FA session state (user NOT logged in yet)\n const expiryDuration = this.config.twoFactor?.tokenExpiry || \"5m\";\n const expiresAt = new Date(Date.now() + ms(expiryDuration));\n\n this.req.session.auth = {\n loggedIn: false,\n accountId: 0,\n userId: \"\",\n email: \"\",\n status: 0,\n rolemask: 0,\n remembered: false,\n lastResync: new Date(),\n lastRememberCheck: new Date(),\n forceLogout: 0,\n verified: false,\n hasPassword: false,\n awaitingTwoFactor: {\n accountId: account.id,\n expiresAt,\n remember,\n availableMechanisms: enabledMethods.map((m) => m.mechanism),\n attemptedMechanisms: [],\n originalEmail: account.email,\n selectors: challenge.selectors,\n },\n };\n\n await this.activityLogger.logActivity(account.id, AuthActivityAction.TwoFactorFailed, this.req, true, { prompt: true, mechanisms: enabledMethods.map((m) => m.mechanism) });\n\n throw new SecondFactorRequiredError(challenge);\n }\n }\n\n await this.onLoginSuccessful(account, remember);\n }\n\n /**\n * Initiate a password reset for a user.\n * Creates a reset token and calls the callback to send reset email.\n *\n * @param email - Email address of account to reset\n * @param expiresAfter - Token expiration (default: 6h). Accepts ms format like '1h', '30m'\n * @param maxOpenRequests - Maximum concurrent reset tokens (default: 2)\n * @param callback - Called with reset token. Create a URL like /reset/{token} and call confirmResetPassword() in that handler\n * @throws {EmailNotVerifiedError} Account doesn't exist or email not verified\n * @throws {ResetDisabledError} Account has password reset disabled\n * @throws {TooManyResetsError} Too many active reset requests\n */\n async resetPassword(email: string, expiresAfter: string | number | null = null, maxOpenRequests: number | null = null, callback?: TokenCallback): Promise<void> {\n validateEmail(email);\n\n const expiry = !expiresAfter ? ms(\"6h\") : ms(expiresAfter);\n const maxRequests = maxOpenRequests === null ? 2 : Math.max(1, maxOpenRequests);\n\n const account = await this.queries.findAccountByEmail(email);\n\n if (!account || !account.verified) {\n throw new EmailNotVerifiedError();\n }\n\n if (!account.resettable) {\n throw new ResetDisabledError();\n }\n\n const openRequests = await this.queries.countActiveResetTokensForAccount(account.id);\n\n if (openRequests >= maxRequests) {\n throw new TooManyResetsError();\n }\n\n const token = hash.encode(email);\n const expires = new Date(Date.now() + expiry);\n\n await this.queries.createResetToken({\n accountId: account.id,\n token,\n expires,\n });\n\n await this.activityLogger.logActivity(account.id, AuthActivityAction.PasswordResetRequested, this.req, true, { email });\n\n if (callback) {\n callback(token);\n }\n }\n\n /**\n * Complete a password reset using a reset token.\n * Changes the password and optionally logs out all sessions.\n *\n * @param token - Reset token from resetPassword callback\n * @param password - New password (will be hashed)\n * @param logout - Whether to force logout all sessions (default: true)\n * @throws {ResetNotFoundError} Token is invalid or doesn't exist\n * @throws {ResetExpiredError} Token has expired\n * @throws {UserNotFoundError} Associated account no longer exists\n * @throws {ResetDisabledError} Account has password reset disabled\n * @throws {InvalidPasswordError} New password doesn't meet requirements\n * @throws {InvalidTokenError} Token format is invalid\n */\n async confirmResetPassword(token: string, password: string, logout = true): Promise<void> {\n const reset = await this.queries.findResetToken(token);\n\n if (!reset) {\n throw new ResetNotFoundError();\n }\n\n if (new Date(reset.expires) < new Date()) {\n throw new ResetExpiredError();\n }\n\n const account = await this.queries.findAccountById(reset.account_id);\n if (!account) {\n throw new UserNotFoundError();\n }\n\n if (!account.resettable) {\n throw new ResetDisabledError();\n }\n\n this.validatePassword(password);\n\n if (!hash.verify(token, account.email)) {\n throw new InvalidTokenError();\n }\n\n await this.queries.updateAccount(account.id, {\n password: hash.encode(password),\n });\n\n if (logout) {\n await this.forceLogoutForAccountById(account.id);\n }\n\n await this.queries.deleteResetToken(token);\n\n await this.activityLogger.logActivity(account.id, AuthActivityAction.PasswordResetCompleted, this.req, true, { email: account.email });\n }\n\n /**\n * Verify if a password matches the current user's password.\n * Useful for \"confirm current password\" flows before sensitive operations.\n *\n * @param password - Password to verify\n * @returns true if password matches, false otherwise\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {UserNotFoundError} Current user account not found\n */\n async verifyPassword(password: string): Promise<boolean> {\n if (!this.isLoggedIn()) {\n throw new UserNotLoggedInError();\n }\n\n const account = await this.getAuthAccount();\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n if (!account.password) {\n return false; // OAuth users don't have passwords\n }\n\n return hash.verify(account.password, password);\n }\n\n private async forceLogoutForAccountById(accountId: number): Promise<void> {\n await this.queries.deleteRememberTokensForAccount(accountId);\n await this.queries.incrementForceLogout(accountId);\n }\n\n /**\n * Force logout all OTHER sessions while keeping current session active.\n * Useful for \"logout other devices\" functionality.\n */\n async logoutEverywhereElse(): Promise<void> {\n if (!this.isLoggedIn()) {\n return;\n }\n\n const accountId = this.getId();\n if (!accountId) {\n return;\n }\n\n const account = await this.queries.findAccountById(accountId);\n if (!account) {\n await this.logout();\n return;\n }\n\n await this.forceLogoutForAccountById(accountId);\n\n this.req.session.auth!.forceLogout += 1;\n\n await this.regenerateSession();\n }\n\n /**\n * Force logout ALL sessions including the current one.\n * Logs out everywhere else, then logs out current session.\n */\n async logoutEverywhere(): Promise<void> {\n if (!this.isLoggedIn()) {\n return;\n }\n\n await this.logoutEverywhereElse();\n await this.logout();\n }\n\n private async findAccountByIdentifier(identifier: { accountId?: number; email?: string; userId?: string }): Promise<AuthAccount | null> {\n if (identifier.accountId !== undefined) {\n return await this.queries.findAccountById(identifier.accountId);\n } else if (identifier.email !== undefined) {\n return await this.queries.findAccountByEmail(identifier.email);\n } else if (identifier.userId !== undefined) {\n return await this.queries.findAccountByUserId(identifier.userId);\n }\n\n return null;\n }\n\n // admin/standalone functions (delegated to auth-functions.js due to lack of need for request context)\n async createUser(credentials: { email: string; password: string }, userId?: string | number, callback?: TokenCallback): Promise<AuthAccount> {\n return authFunctions.createUser(this.config, credentials, userId, callback);\n }\n\n async deleteUserBy(identifier: { accountId?: number; email?: string; userId?: string }): Promise<void> {\n return authFunctions.deleteUserBy(this.config, identifier);\n }\n\n async addRoleForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<void> {\n return authFunctions.addRoleForUserBy(this.config, identifier, role);\n }\n\n async removeRoleForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<void> {\n return authFunctions.removeRoleForUserBy(this.config, identifier, role);\n }\n\n async hasRoleForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<boolean> {\n return authFunctions.hasRoleForUserBy(this.config, identifier, role);\n }\n\n async changePasswordForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, password: string): Promise<void> {\n return authFunctions.changePasswordForUserBy(this.config, identifier, password);\n }\n\n async setStatusForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, status: number): Promise<void> {\n return authFunctions.setStatusForUserBy(this.config, identifier, status);\n }\n\n async initiatePasswordResetForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, expiresAfter?: string | number | null, callback?: TokenCallback): Promise<void> {\n return authFunctions.initiatePasswordResetForUserBy(this.config, identifier, expiresAfter, callback);\n }\n\n async userExistsByEmail(email: string): Promise<boolean> {\n return authFunctions.userExistsByEmail(this.config, email);\n }\n\n async forceLogoutForUserBy(identifier: { accountId?: number; email?: string; userId?: string }): Promise<void> {\n const result = await authFunctions.forceLogoutForUserBy(this.config, identifier);\n\n if (this.getId() === result.accountId) {\n this.req.session.auth!.shouldForceLogout = true;\n }\n }\n\n /**\n * Log in as another user (admin function).\n * Creates a new session as the target user without requiring their password.\n *\n * @param identifier - Find user by accountId, email, or userId\n * @throws {UserNotFoundError} No account matches the identifier\n */\n async loginAsUserBy(identifier: { accountId?: number; email?: string; userId?: string }): Promise<void> {\n const account = await this.findAccountByIdentifier(identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n await this.onLoginSuccessful(account, false);\n }\n}\n","import type { Request, Response } from \"express\";\nimport type { Pool } from \"pg\";\nimport \"express-session\";\n\nexport interface OAuthProviderConfig {\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n}\n\nexport interface GitHubProviderConfig extends OAuthProviderConfig {}\n\nexport interface GoogleProviderConfig extends OAuthProviderConfig {}\n\nexport interface AzureProviderConfig extends OAuthProviderConfig {\n tenantId: string;\n}\n\nexport interface AuthConfig {\n db: Pool;\n\n /**\n * If a user logs in with an OAuth provider, but a matching account (identified by the OAuth user's email address) doesn't\n * exist, createUser will be called:\n *\n * @example:\n *\n * if (this.authConfig.createUser) {\n * userId = await this.authConfig.createUser(userData);\n * } else {\n * // Generate UUID for OAuth users when no createUser function is provided\n * userId = crypto.randomUUID();\n * }\n *\n * This callback is your opportunity to create a user account in *your* database, and return\n * the user ID of the newly-created user for this provider account to be linked to.\n * @param userData\n * @returns\n */\n createUser?: (userData: OAuthUserData) => string | number | Promise<string | number>;\n\n tablePrefix?: string; // defaults to 'user_'\n\n minPasswordLength?: number; // defaults to 8\n maxPasswordLength?: number; // defaults to 64\n\n rememberDuration?: string; // defaults to \"30d\"\n rememberCookieName?: string; // defaults to \"remember_token\"\n\n cookie?: {\n domain?: string;\n secure?: boolean;\n sameSite?: \"strict\" | \"lax\" | \"none\";\n };\n\n resyncInterval?: string; // defaults to \"30s\"\n\n activityLog?: {\n enabled?: boolean; // defaults to true\n maxEntries?: number; // defaults to 10000\n actions?: AuthActivityActionType[]; // which actions to log, defaults to all\n };\n\n providers?: {\n github?: GitHubProviderConfig;\n google?: GoogleProviderConfig;\n azure?: AzureProviderConfig;\n };\n\n twoFactor?: {\n enabled?: boolean; // defaults to false\n requireForOAuth?: boolean; // defaults to false\n issuer?: string; // for TOTP QR codes, defaults to \"EasyAccess\"\n codeLength?: number; // defaults to 6\n tokenExpiry?: string; // defaults to \"5m\"\n totpWindow?: number; // defaults to 1\n backupCodesCount?: number; // defaults to 10\n };\n}\n\nexport interface AuthAccount {\n id: number;\n user_id: string;\n email: string;\n password: string | null;\n verified: boolean;\n status: number;\n rolemask: number;\n last_login: Date | null;\n force_logout: number;\n resettable: boolean;\n registered: Date;\n}\n\nexport interface AuthProvider {\n id: number;\n account_id: number;\n provider: string;\n provider_id: string;\n provider_email: string | null;\n provider_username: string | null;\n provider_name: string | null;\n provider_avatar: string | null;\n created_at: Date;\n updated_at: Date;\n}\n\nexport interface OAuthUserData {\n id: string;\n email: string;\n username?: string;\n name?: string;\n avatar?: string;\n}\n\nexport interface OAuthCallbackResult {\n isNewUser: boolean;\n}\n\nexport interface OAuthProvider {\n getAuthUrl(state?: string, scopes?: string[]): string;\n handleCallback(req: Request): Promise<OAuthCallbackResult>;\n getUserData(req: Request): Promise<OAuthUserData>;\n}\n\nexport interface AuthConfirmation {\n id: number;\n account_id: number;\n token: string;\n email: string;\n expires: Date;\n}\n\nexport interface AuthRemember {\n id: number;\n account_id: number;\n token: string;\n expires: Date;\n}\n\nexport interface AuthReset {\n id: number;\n account_id: number;\n token: string;\n expires: Date;\n}\n\nexport interface AuthActivity {\n id: number;\n account_id: number | null;\n action: string;\n ip_address: string | null;\n user_agent: string | null;\n browser: string | null;\n os: string | null;\n device: string | null;\n success: boolean;\n metadata: Record<string, any> | null;\n created_at: Date;\n}\n\nexport interface AuthSession {\n loggedIn: boolean;\n accountId: number;\n userId: string;\n email: string;\n status: number;\n rolemask: number;\n remembered: boolean;\n lastResync: Date;\n lastRememberCheck: Date;\n forceLogout: number;\n verified: boolean;\n hasPassword: boolean;\n shouldForceLogout?: boolean;\n awaitingTwoFactor?: {\n accountId: number;\n expiresAt: Date;\n remember: boolean;\n availableMechanisms: TwoFactorMechanism[];\n attemptedMechanisms: TwoFactorMechanism[];\n originalEmail: string;\n selectors?: {\n email?: string;\n sms?: string;\n };\n };\n}\n\nexport enum TwoFactorMechanism {\n TOTP = 1,\n EMAIL = 2,\n SMS = 3,\n}\n\nexport interface TwoFactorMethod {\n id: number;\n account_id: number;\n mechanism: TwoFactorMechanism;\n secret: string | null;\n backup_codes: string[] | null;\n verified: boolean;\n created_at: Date;\n last_used_at: Date | null;\n}\n\nexport interface TwoFactorToken {\n id: number;\n account_id: number;\n mechanism: TwoFactorMechanism;\n selector: string;\n token_hash: string;\n expires_at: Date;\n created_at: Date;\n}\n\nexport interface TwoFactorSetupResult {\n secret: string;\n qrCode: string;\n backupCodes?: string[];\n}\n\nexport interface TwoFactorChallenge {\n totp?: boolean;\n email?: {\n otpValue: string;\n maskedContact: string;\n };\n sms?: {\n otpValue: string;\n maskedContact: string;\n };\n selectors?: {\n email?: string;\n sms?: string;\n };\n}\n\nexport const AuthStatus = {\n Normal: 0,\n Archived: 1,\n Banned: 2,\n Locked: 3,\n PendingReview: 4,\n Suspended: 5,\n} as const;\n\nexport const AuthRole = {\n Admin: 1,\n Author: 2,\n Collaborator: 4,\n Consultant: 8,\n Consumer: 16,\n Contributor: 32,\n Owner: 64,\n Creator: 128,\n Developer: 256,\n Director: 512,\n Editor: 1024,\n Employee: 2048,\n Member: 4096,\n Manager: 8192,\n Moderator: 16384,\n Publisher: 32768,\n Reviewer: 65536,\n Subscriber: 131072,\n SuperAdmin: 262144,\n SuperEditor: 524288,\n SuperModerator: 1048576,\n Translator: 2097152,\n} as const;\n\nexport const AuthActivityAction = {\n Login: \"login\",\n Logout: \"logout\",\n FailedLogin: \"failed_login\",\n Register: \"register\",\n EmailConfirmed: \"email_confirmed\",\n PasswordResetRequested: \"password_reset_requested\",\n PasswordResetCompleted: \"password_reset_completed\",\n PasswordChanged: \"password_changed\",\n EmailChanged: \"email_changed\",\n RoleChanged: \"role_changed\",\n StatusChanged: \"status_changed\",\n ForceLogout: \"force_logout\",\n OAuthConnected: \"oauth_connected\",\n RememberTokenCreated: \"remember_token_created\",\n TwoFactorSetup: \"two_factor_setup\",\n TwoFactorVerified: \"two_factor_verified\",\n TwoFactorFailed: \"two_factor_failed\",\n TwoFactorDisabled: \"two_factor_disabled\",\n BackupCodeUsed: \"backup_code_used\",\n} as const;\n\nexport type AuthActivityActionType = (typeof AuthActivityAction)[keyof typeof AuthActivityAction];\n\nexport type TokenCallback = (token: string) => void;\n\ndeclare module \"express-session\" {\n interface SessionData {\n auth?: AuthSession;\n }\n}\n\ndeclare global {\n namespace Express {\n interface Request {\n auth: AuthManager;\n }\n }\n}\n\nexport interface AuthManager {\n isLoggedIn(): boolean;\n login(email: string, password: string, remember?: boolean): Promise<void>;\n completeTwoFactorLogin(): Promise<void>;\n logout(): Promise<void>;\n register(email: string, password: string, userId?: string | number, callback?: TokenCallback): Promise<AuthAccount>;\n resyncSession(force?: boolean): Promise<void>;\n\n getId(): number | null;\n getEmail(): string | null;\n getStatus(): number | null;\n getVerified(): boolean | null;\n hasPassword(): boolean | null;\n getRoleNames(rolemask?: number): string[];\n getStatusName(): string | null;\n\n hasRole(role: number): Promise<boolean>;\n isAdmin(): Promise<boolean>;\n isRemembered(): boolean;\n\n changeEmail(newEmail: string, callback: TokenCallback): Promise<void>;\n confirmEmail(token: string): Promise<string>;\n confirmEmailAndLogin(token: string, remember?: boolean): Promise<void>;\n\n resetPassword(email: string, expiresAfter?: string | number | null, maxOpenRequests?: number | null, callback?: TokenCallback): Promise<void>;\n confirmResetPassword(token: string, password: string, logout?: boolean): Promise<void>;\n\n verifyPassword(password: string): Promise<boolean>;\n\n logoutEverywhere(): Promise<void>;\n logoutEverywhereElse(): Promise<void>;\n\n // admin/standalone functions from AuthContext\n createUser(credentials: { email: string; password: string }, userId?: string | number, callback?: TokenCallback): Promise<AuthAccount>;\n deleteUserBy(identifier: { accountId?: number; email?: string; userId?: string }): Promise<void>;\n addRoleForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<void>;\n removeRoleForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<void>;\n hasRoleForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<boolean>;\n changePasswordForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, password: string): Promise<void>;\n setStatusForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, status: number): Promise<void>;\n initiatePasswordResetForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, expiresAfter?: string | number | null, callback?: TokenCallback): Promise<void>;\n userExistsByEmail(email: string): Promise<boolean>;\n forceLogoutForUserBy(identifier: { accountId?: number; email?: string; userId?: string }): Promise<void>;\n\n // session-dependent admin functions\n loginAsUserBy(identifier: { accountId?: number; email?: string; userId?: string }): Promise<void>;\n\n providers: {\n github?: OAuthProvider;\n google?: OAuthProvider;\n azure?: OAuthProvider;\n };\n\n twoFactor: TwoFactorManager;\n}\n\nexport interface TwoFactorManager {\n isEnabled(): Promise<boolean>;\n totpEnabled(): Promise<boolean>;\n emailEnabled(): Promise<boolean>;\n smsEnabled(): Promise<boolean>;\n getEnabledMethods(): Promise<TwoFactorMechanism[]>;\n getTotpUri(): Promise<string | null>;\n\n setup: {\n /**\n * Setup TOTP authentication using an authenticator app.\n * Generates a secret, QR code for easy setup, and optionally backup codes.\n *\n * @param requireVerification - If true, method is created in unverified state and requires calling complete.totp() with a valid code. If false (default), method is immediately enabled and backup codes are generated.\n * @returns Promise resolving to setup result containing secret (for manual entry), QR code URL (for scanning), and backup codes (if verification not required)\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorAlreadyEnabledError} TOTP is already enabled for this user\n */\n totp(requireVerification?: boolean): Promise<TwoFactorSetupResult>;\n\n /**\n * Setup email-based two-factor authentication.\n * Uses the user's account email or a specified email address for OTP delivery.\n *\n * @param email - Email address to use for 2FA. If not provided, uses the current user's account email\n * @param requireVerification - If true, method is created in unverified state and requires calling complete.email() with a valid code. If false (default), method is immediately enabled\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorAlreadyEnabledError} Email 2FA is already enabled for this user\n */\n email(email?: string, requireVerification?: boolean): Promise<void>;\n\n /**\n * Setup SMS-based two-factor authentication.\n * Uses the provided phone number for OTP delivery via SMS.\n *\n * @param phone - Phone number to use for SMS OTP delivery (should include country code, e.g., \"+1234567890\")\n * @param requireVerification - If true (default), method is created in unverified state and requires calling complete.sms() with a valid code. If false, method is immediately enabled\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorAlreadyEnabledError} SMS 2FA is already enabled for this user\n */\n sms(phone: string, requireVerification?: boolean): Promise<void>;\n };\n\n complete: {\n /**\n * Complete TOTP setup by verifying a code from the user's authenticator app.\n * This is only required if setup.totp() was called with requireVerification: true.\n * Upon successful verification, the method is enabled and backup codes are generated.\n *\n * @param code - The 6-digit TOTP code from the user's authenticator app\n * @returns Promise resolving to an array of backup codes that should be securely stored by the user\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorNotSetupError} TOTP method was not previously set up or doesn't exist\n * @throws {TwoFactorAlreadyEnabledError} TOTP method is already verified/enabled\n * @throws {InvalidTwoFactorCodeError} The provided TOTP code is invalid or expired\n */\n totp(code: string): Promise<string[]>;\n\n /**\n * Complete email 2FA setup by verifying an OTP code sent to the user's email.\n * This is only required if setup.email() was called with requireVerification: true.\n * Upon successful verification, the email 2FA method is enabled.\n *\n * @param code - The OTP code that was sent to the user's email address\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorNotSetupError} Email 2FA method was not previously set up or doesn't exist\n * @throws {TwoFactorAlreadyEnabledError} Email 2FA method is already verified/enabled\n * @throws {InvalidTwoFactorCodeError} The provided email OTP code is invalid or expired\n */\n email(code: string): Promise<void>;\n\n /**\n * Complete SMS 2FA setup by verifying an OTP code sent to the user's phone.\n * This is only required if setup.sms() was called with requireVerification: true.\n * Upon successful verification, the SMS 2FA method is enabled.\n *\n * @param code - The OTP code that was sent to the user's phone number via SMS\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorNotSetupError} SMS 2FA method was not previously set up or doesn't exist\n * @throws {TwoFactorAlreadyEnabledError} SMS 2FA method is already verified/enabled\n * @throws {InvalidTwoFactorCodeError} The provided SMS OTP code is invalid or expired\n */\n sms(code: string): Promise<void>;\n };\n\n // challenge verification (during login flow)\n verify: {\n /**\n * Verifies a TOTP code during the login flow when two-factor authentication is required.\n * This is used after a login attempt triggers a SecondFactorRequiredError and the user\n * provides a code from their authenticator app. After successful verification, call\n * completeTwoFactorLogin() to finish the login process.\n *\n * @param code - The 6-digit TOTP code from the user's authenticator app\n * @throws {UserNotLoggedInError} No active two-factor authentication session\n * @throws {TwoFactorNotSetupError} TOTP method is not enabled for this user\n * @throws {InvalidTwoFactorCodeError} The provided TOTP code is invalid or expired\n */\n totp(code: string): Promise<void>;\n /**\n * Verifies an email OTP code during the login flow when two-factor authentication is required.\n * This is used after a login attempt triggers a SecondFactorRequiredError and the user\n * provides the OTP code that was sent to their email. After successful verification, call\n * completeTwoFactorLogin() to finish the login process.\n *\n * @param code - The OTP code that was sent to the user's email address\n * @throws {UserNotLoggedInError} No active two-factor authentication session\n * @throws {TwoFactorNotSetupError} Email 2FA method is not enabled for this user\n * @throws {InvalidTwoFactorCodeError} The provided email OTP code is invalid or expired\n */\n email(code: string): Promise<void>;\n\n /**\n * Verifies an SMS OTP code during the login flow when two-factor authentication is required.\n * This is used after a login attempt triggers a SecondFactorRequiredError and the user\n * provides the OTP code that was sent to their phone. After successful verification, call\n * completeTwoFactorLogin() to finish the login process.\n *\n * @param code - The OTP code that was sent to the user's phone number via SMS\n * @throws {UserNotLoggedInError} No active two-factor authentication session\n * @throws {TwoFactorNotSetupError} SMS 2FA method is not enabled for this user\n * @throws {InvalidTwoFactorCodeError} The provided SMS OTP code is invalid or expired\n */\n sms(code: string): Promise<void>;\n\n /**\n * Verifies a TOTP backup code during the login flow when two-factor authentication is required.\n * Backup codes are generated when TOTP is first set up and can be used as an alternative to\n * the authenticator app. Each backup code can only be used once and is automatically removed\n * after successful verification. After successful verification, call completeTwoFactorLogin()\n * to finish the login process.\n *\n * @param code - A backup code that was generated during TOTP setup (8-character alphanumeric)\n * @throws {UserNotLoggedInError} No active two-factor authentication session\n * @throws {TwoFactorNotSetupError} TOTP method is not enabled for this user or no backup codes exist\n * @throws {InvalidBackupCodeError} The provided backup code is invalid, expired, or already used\n */\n backupCode(code: string): Promise<void>;\n\n /**\n * Smart OTP verification that works with both email and SMS codes during the login flow.\n * This method automatically determines whether the provided code is an email or SMS OTP\n * by trying to verify it against all available OTP methods. Use this when you want to\n * provide a single input field for users who may have multiple OTP methods enabled.\n * After successful verification, call completeTwoFactorLogin() to finish the login process.\n *\n * @param code - Either an email or SMS OTP code\n * @throws {UserNotLoggedInError} No active two-factor authentication session\n * @throws {TwoFactorNotSetupError} No email or SMS 2FA methods are enabled for this user\n * @throws {InvalidTwoFactorCodeError} The provided code doesn't match any available OTP methods or is expired\n */\n otp(code: string): Promise<void>;\n };\n\n /**\n * Disable a TwoFactorMechanism for the session user.\n * @param mechanism - The TwoFactorMechanism to disable for the session user\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorNotSetupError} The specified method is not enabled for this user\n */\n disable(mechanism: TwoFactorMechanism): Promise<void>;\n\n /**\n * Generates and stores new TOTP backup codes for the session user, invalidating the old ones in the process.\n * @returns Promise resolving to an array of new backup codes that should be securely stored by the user\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorNotSetupError} TOTP method is not enabled for this user\n */\n generateNewBackupCodes(): Promise<string[]>;\n\n /**\n * Returns either the email or mobile number for the session user depending on the provided TwoFactorMechanism.\n * @param mechanism - The TwoFactorMechanism for which to return the contact information\n * @returns Promise resolving to the contact information (email or phone number) or null if not found\n * @throws {UserNotLoggedInError} User is not logged in (returns null instead of throwing in implementation)\n */\n getContact(mechanism: TwoFactorMechanism.EMAIL | TwoFactorMechanism.SMS): Promise<string | null>;\n}\n","import type { Pool } from \"pg\";\nimport type { AuthConfig, AuthAccount, AuthConfirmation, AuthRemember, AuthReset, AuthProvider, TwoFactorMethod, TwoFactorToken, TwoFactorMechanism } from \"./types.js\";\n\nexport class AuthQueries {\n private db: Pool;\n private tablePrefix: string;\n\n constructor(config: AuthConfig) {\n this.db = config.db;\n this.tablePrefix = config.tablePrefix || \"user_\";\n }\n\n private get accountsTable() {\n return `${this.tablePrefix}accounts`;\n }\n\n private get confirmationsTable() {\n return `${this.tablePrefix}confirmations`;\n }\n\n private get remembersTable() {\n return `${this.tablePrefix}remembers`;\n }\n\n private get resetsTable() {\n return `${this.tablePrefix}resets`;\n }\n\n private get providersTable() {\n return `${this.tablePrefix}providers`;\n }\n\n private get twoFactorMethodsTable() {\n return `${this.tablePrefix}2fa_methods`;\n }\n\n private get twoFactorTokensTable() {\n return `${this.tablePrefix}2fa_tokens`;\n }\n\n async findAccountById(id: number): Promise<AuthAccount | null> {\n const sql = `SELECT * FROM ${this.accountsTable} WHERE id = $1`;\n const result = await this.db.query(sql, [id]);\n return result.rows[0] || null;\n }\n\n async findAccountByUserId(userId: string | number): Promise<AuthAccount | null> {\n const sql = `SELECT * FROM ${this.accountsTable} WHERE user_id = $1`;\n const result = await this.db.query(sql, [userId]);\n return result.rows[0] || null;\n }\n\n async findAccountByEmail(email: string): Promise<AuthAccount | null> {\n const sql = `SELECT * FROM ${this.accountsTable} WHERE email = $1`;\n const result = await this.db.query(sql, [email]);\n return result.rows[0] || null;\n }\n\n async createAccount(data: { userId: string | number; email: string; password: string | null; verified: boolean; status: number; rolemask: number }): Promise<AuthAccount> {\n const sql = `\n INSERT INTO ${this.accountsTable} (\n user_id, email, password, verified, status, rolemask, \n force_logout, resettable, registered\n )\n VALUES ($1, $2, $3, $4, $5, $6, 0, true, NOW())\n RETURNING *\n `;\n\n const result = await this.db.query(sql, [data.userId, data.email, data.password, data.verified, data.status, data.rolemask]);\n\n return result.rows[0];\n }\n\n async updateAccount(id: number, updates: Partial<AuthAccount>): Promise<void> {\n const fields = [];\n const values = [];\n let paramIndex = 1;\n\n for (const [key, value] of Object.entries(updates)) {\n if (key === \"id\") continue; // don't update id\n fields.push(`${key} = $${paramIndex++}`);\n values.push(value);\n }\n\n if (fields.length === 0) return;\n\n values.push(id);\n const sql = `UPDATE ${this.accountsTable} SET ${fields.join(\", \")} WHERE id = $${paramIndex}`;\n await this.db.query(sql, values);\n }\n\n async updateAccountLastLogin(id: number): Promise<void> {\n const sql = `UPDATE ${this.accountsTable} SET last_login = NOW() WHERE id = $1`;\n await this.db.query(sql, [id]);\n }\n\n async incrementForceLogout(id: number): Promise<void> {\n const sql = `UPDATE ${this.accountsTable} SET force_logout = force_logout + 1 WHERE id = $1`;\n await this.db.query(sql, [id]);\n }\n\n async deleteAccount(id: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.twoFactorTokensTable} WHERE account_id = $1`, [id]);\n await this.db.query(`DELETE FROM ${this.twoFactorMethodsTable} WHERE account_id = $1`, [id]);\n await this.db.query(`DELETE FROM ${this.providersTable} WHERE account_id = $1`, [id]);\n await this.db.query(`DELETE FROM ${this.confirmationsTable} WHERE account_id = $1`, [id]);\n await this.db.query(`DELETE FROM ${this.remembersTable} WHERE account_id = $1`, [id]);\n await this.db.query(`DELETE FROM ${this.resetsTable} WHERE account_id = $1`, [id]);\n\n await this.db.query(`DELETE FROM ${this.accountsTable} WHERE id = $1`, [id]);\n }\n\n async createConfirmation(data: { accountId: number; token: string; email: string; expires: Date }): Promise<void> {\n await this.db.query(`DELETE FROM ${this.confirmationsTable} WHERE account_id = $1`, [data.accountId]);\n\n const sql = `\n INSERT INTO ${this.confirmationsTable} (account_id, token, email, expires)\n VALUES ($1, $2, $3, $4)\n `;\n\n await this.db.query(sql, [data.accountId, data.token, data.email, data.expires]);\n }\n\n async findConfirmation(token: string): Promise<AuthConfirmation | null> {\n const sql = `SELECT * FROM ${this.confirmationsTable} WHERE token = $1`;\n const result = await this.db.query(sql, [token]);\n return result.rows[0] || null;\n }\n\n async findLatestConfirmationForAccount(accountId: number): Promise<AuthConfirmation | null> {\n const sql = `\n SELECT * FROM ${this.confirmationsTable} \n WHERE account_id = $1 \n ORDER BY expires DESC \n LIMIT 1\n `;\n const result = await this.db.query(sql, [accountId]);\n return result.rows[0] || null;\n }\n\n async deleteConfirmation(token: string): Promise<void> {\n await this.db.query(`DELETE FROM ${this.confirmationsTable} WHERE token = $1`, [token]);\n }\n\n async createRememberToken(data: { accountId: number; token: string; expires: Date }): Promise<void> {\n await this.db.query(`DELETE FROM ${this.remembersTable} WHERE account_id = $1`, [data.accountId]);\n\n const sql = `\n INSERT INTO ${this.remembersTable} (account_id, token, expires)\n VALUES ($1, $2, $3)\n `;\n\n await this.db.query(sql, [data.accountId, data.token, data.expires]);\n }\n\n async findRememberToken(token: string): Promise<AuthRemember | null> {\n const sql = `SELECT * FROM ${this.remembersTable} WHERE token = $1`;\n const result = await this.db.query(sql, [token]);\n return result.rows[0] || null;\n }\n\n async deleteRememberToken(token: string): Promise<void> {\n await this.db.query(`DELETE FROM ${this.remembersTable} WHERE token = $1`, [token]);\n }\n\n async deleteRememberTokensForAccount(accountId: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.remembersTable} WHERE account_id = $1`, [accountId]);\n }\n\n async deleteExpiredRememberTokensForAccount(accountId: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.remembersTable} WHERE account_id = $1 AND expires <= NOW()`, [accountId]);\n }\n\n async createResetToken(data: { accountId: number; token: string; expires: Date }): Promise<void> {\n const sql = `\n INSERT INTO ${this.resetsTable} (account_id, token, expires)\n VALUES ($1, $2, $3)\n `;\n\n await this.db.query(sql, [data.accountId, data.token, data.expires]);\n }\n\n async findResetToken(token: string): Promise<AuthReset | null> {\n const sql = `\n SELECT * FROM ${this.resetsTable} \n WHERE token = $1 \n ORDER BY expires DESC \n LIMIT 1\n `;\n const result = await this.db.query(sql, [token]);\n return result.rows[0] || null;\n }\n\n async countActiveResetTokensForAccount(accountId: number): Promise<number> {\n const sql = `\n SELECT COUNT(*) as count FROM ${this.resetsTable} \n WHERE account_id = $1 AND expires >= NOW()\n `;\n const result = await this.db.query(sql, [accountId]);\n return parseInt(result.rows[0]?.count || \"0\");\n }\n\n async deleteResetToken(token: string): Promise<void> {\n await this.db.query(`DELETE FROM ${this.resetsTable} WHERE token = $1`, [token]);\n }\n\n async deleteResetTokensForAccount(accountId: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.resetsTable} WHERE account_id = $1`, [accountId]);\n }\n\n async createProvider(data: { accountId: number; provider: string; providerId: string; providerEmail: string | null; providerUsername: string | null; providerName: string | null; providerAvatar: string | null }): Promise<AuthProvider> {\n const sql = `\n INSERT INTO ${this.providersTable} (\n account_id, provider, provider_id, provider_email, \n provider_username, provider_name, provider_avatar\n )\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n RETURNING *\n `;\n\n const result = await this.db.query(sql, [data.accountId, data.provider, data.providerId, data.providerEmail, data.providerUsername, data.providerName, data.providerAvatar]);\n\n return result.rows[0];\n }\n\n async findProviderByProviderIdAndType(providerId: string, provider: string): Promise<AuthProvider | null> {\n const sql = `SELECT * FROM ${this.providersTable} WHERE provider_id = $1 AND provider = $2`;\n const result = await this.db.query(sql, [providerId, provider]);\n return result.rows[0] || null;\n }\n\n async findProvidersByAccountId(accountId: number): Promise<AuthProvider[]> {\n const sql = `SELECT * FROM ${this.providersTable} WHERE account_id = $1 ORDER BY created_at DESC`;\n const result = await this.db.query(sql, [accountId]);\n return result.rows;\n }\n\n async deleteProvider(id: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.providersTable} WHERE id = $1`, [id]);\n }\n\n async deleteProvidersByAccountId(accountId: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.providersTable} WHERE account_id = $1`, [accountId]);\n }\n\n // two-factor authentication methods\n\n async findTwoFactorMethodsByAccountId(accountId: number): Promise<TwoFactorMethod[]> {\n const sql = `SELECT * FROM ${this.twoFactorMethodsTable} WHERE account_id = $1 ORDER BY created_at DESC`;\n const result = await this.db.query(sql, [accountId]);\n return result.rows;\n }\n\n async findTwoFactorMethodByAccountAndMechanism(accountId: number, mechanism: TwoFactorMechanism): Promise<TwoFactorMethod | null> {\n const sql = `SELECT * FROM ${this.twoFactorMethodsTable} WHERE account_id = $1 AND mechanism = $2`;\n const result = await this.db.query(sql, [accountId, mechanism]);\n return result.rows[0] || null;\n }\n\n async createTwoFactorMethod(data: { accountId: number; mechanism: TwoFactorMechanism; secret?: string; backupCodes?: string[]; verified?: boolean }): Promise<TwoFactorMethod> {\n const sql = `\n INSERT INTO ${this.twoFactorMethodsTable} (\n account_id, mechanism, secret, backup_codes, verified\n )\n VALUES ($1, $2, $3, $4, $5)\n RETURNING *\n `;\n\n const result = await this.db.query(sql, [data.accountId, data.mechanism, data.secret || null, data.backupCodes || null, data.verified || false]);\n\n return result.rows[0];\n }\n\n async updateTwoFactorMethod(id: number, updates: Partial<Pick<TwoFactorMethod, \"secret\" | \"backup_codes\" | \"verified\" | \"last_used_at\">>): Promise<void> {\n const fields = [];\n const values = [];\n let paramIndex = 1;\n\n for (const [key, value] of Object.entries(updates)) {\n if (key === \"id\") continue;\n fields.push(`${key} = $${paramIndex++}`);\n values.push(value);\n }\n\n if (fields.length === 0) return;\n\n values.push(id);\n const sql = `UPDATE ${this.twoFactorMethodsTable} SET ${fields.join(\", \")} WHERE id = $${paramIndex}`;\n await this.db.query(sql, values);\n }\n\n async deleteTwoFactorMethod(id: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.twoFactorMethodsTable} WHERE id = $1`, [id]);\n }\n\n async deleteTwoFactorMethodsByAccountId(accountId: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.twoFactorMethodsTable} WHERE account_id = $1`, [accountId]);\n }\n\n // two-factor authentication tokens\n\n async createTwoFactorToken(data: { accountId: number; mechanism: TwoFactorMechanism; selector: string; tokenHash: string; expiresAt: Date }): Promise<TwoFactorToken> {\n const sql = `\n INSERT INTO ${this.twoFactorTokensTable} (\n account_id, mechanism, selector, token_hash, expires_at\n )\n VALUES ($1, $2, $3, $4, $5)\n RETURNING *\n `;\n\n const result = await this.db.query(sql, [data.accountId, data.mechanism, data.selector, data.tokenHash, data.expiresAt]);\n\n return result.rows[0];\n }\n\n async findTwoFactorTokenBySelector(selector: string): Promise<TwoFactorToken | null> {\n const sql = `SELECT * FROM ${this.twoFactorTokensTable} WHERE selector = $1 AND expires_at > NOW()`;\n const result = await this.db.query(sql, [selector]);\n return result.rows[0] || null;\n }\n\n async deleteTwoFactorToken(id: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.twoFactorTokensTable} WHERE id = $1`, [id]);\n }\n\n async deleteTwoFactorTokensByAccountId(accountId: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.twoFactorTokensTable} WHERE account_id = $1`, [accountId]);\n }\n\n async deleteTwoFactorTokensByAccountAndMechanism(accountId: number, mechanism: TwoFactorMechanism): Promise<void> {\n await this.db.query(`DELETE FROM ${this.twoFactorTokensTable} WHERE account_id = $1 AND mechanism = $2`, [accountId, mechanism]);\n }\n}\n","import type { Request } from \"express\";\nimport type { AuthConfig, AuthActivity, AuthActivityActionType } from \"./types.js\";\nimport Bowser from \"bowser\";\n\nexport class ActivityLogger {\n private config: AuthConfig;\n private enabled: boolean;\n private maxEntries: number;\n private allowedActions: AuthActivityActionType[] | null;\n private tablePrefix: string;\n\n constructor(config: AuthConfig) {\n this.config = config;\n this.enabled = config.activityLog?.enabled !== false; // default true\n this.maxEntries = config.activityLog?.maxEntries || 10000;\n this.allowedActions = config.activityLog?.actions || null; // null means all actions\n this.tablePrefix = config.tablePrefix || \"user_\";\n }\n\n private get activityTable() {\n return `${this.tablePrefix}activity_log`;\n }\n\n private parseUserAgent(userAgent: string | null): {\n browser: string | null;\n os: string | null;\n device: string | null;\n } {\n if (!userAgent) {\n return { browser: null, os: null, device: null };\n }\n\n try {\n const browser = Bowser.getParser(userAgent);\n const result = browser.getResult();\n\n return {\n browser: result.browser.name || null,\n os: result.os.name || null,\n device: result.platform.type || \"desktop\",\n };\n } catch (error) {\n // fallback to simple parsing if bowser fails\n return this.parseUserAgentSimple(userAgent);\n }\n }\n\n private parseUserAgentSimple(userAgent: string): {\n browser: string | null;\n os: string | null;\n device: string | null;\n } {\n let browser = null;\n if (userAgent.includes(\"Chrome\")) browser = \"Chrome\";\n else if (userAgent.includes(\"Firefox\")) browser = \"Firefox\";\n else if (userAgent.includes(\"Safari\")) browser = \"Safari\";\n else if (userAgent.includes(\"Edge\")) browser = \"Edge\";\n\n let os = null;\n if (userAgent.includes(\"Windows\")) os = \"Windows\";\n else if (userAgent.includes(\"Mac OS\")) os = \"macOS\";\n else if (userAgent.includes(\"Linux\")) os = \"Linux\";\n else if (userAgent.includes(\"Android\")) os = \"Android\";\n else if (userAgent.includes(\"iOS\")) os = \"iOS\";\n\n let device = \"desktop\";\n if (userAgent.includes(\"Mobile\")) device = \"mobile\";\n else if (userAgent.includes(\"Tablet\")) device = \"tablet\";\n\n return { browser, os, device };\n }\n\n private getIpAddress(req: Request): string | null {\n return req.ip || req.connection?.remoteAddress || req.socket?.remoteAddress || (req.connection as any)?.socket?.remoteAddress || null;\n }\n\n async logActivity(accountId: number | null, action: AuthActivityActionType, req: Request, success = true, metadata: Record<string, any> = {}): Promise<void> {\n if (!this.enabled) return;\n\n // check if this action is allowed\n if (this.allowedActions && !this.allowedActions.includes(action)) {\n return;\n }\n\n const userAgent = (typeof req.get === \"function\" ? req.get(\"User-Agent\") : req.headers?.[\"user-agent\"]) || null;\n const ip = this.getIpAddress(req);\n const parsed = this.parseUserAgent(userAgent);\n\n try {\n // insert new activity log entry\n await this.config.db.query(\n `\n INSERT INTO ${this.activityTable} \n (account_id, action, ip_address, user_agent, browser, os, device, success, metadata)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)\n `,\n [accountId, action, ip, userAgent, parsed.browser, parsed.os, parsed.device, success, Object.keys(metadata).length > 0 ? JSON.stringify(metadata) : null],\n );\n\n // occasionally cleanup old entries (1% chance per insert to avoid performance impact)\n if (Math.random() < 0.01) {\n await this.cleanup();\n }\n } catch (error) {\n // don't throw on logging errors - just log to console\n console.error(\"ActivityLogger: Failed to log activity:\", error);\n }\n }\n\n async cleanup(): Promise<void> {\n if (!this.enabled) return;\n\n try {\n // delete entries beyond maxEntries limit\n await this.config.db.query(\n `\n DELETE FROM ${this.activityTable} \n WHERE id NOT IN (\n SELECT id FROM ${this.activityTable} \n ORDER BY created_at DESC \n LIMIT $1\n )\n `,\n [this.maxEntries],\n );\n } catch (error) {\n console.error(\"ActivityLogger: Failed to cleanup old entries:\", error);\n }\n }\n\n async getRecentActivity(limit = 100, accountId?: number): Promise<AuthActivity[]> {\n if (!this.enabled) return [];\n\n try {\n let sql = `\n SELECT \n al.*,\n a.email \n FROM ${this.activityTable} al\n LEFT JOIN ${this.tablePrefix}accounts a ON al.account_id = a.id\n `;\n const params: any[] = [];\n\n if (accountId !== undefined) {\n sql += \" WHERE al.account_id = $1\";\n params.push(accountId);\n }\n\n sql += ` ORDER BY al.created_at DESC LIMIT $${params.length + 1}`;\n params.push(Math.min(limit, 1000)); // cap at 1000 entries max\n\n const result = await this.config.db.query(sql, params);\n return result.rows.map((row: any) => ({\n ...row,\n metadata: row.metadata ? JSON.parse(row.metadata) : null,\n }));\n } catch (error) {\n console.error(\"ActivityLogger: Failed to get recent activity:\", error);\n return [];\n }\n }\n\n async getActivityStats(): Promise<{\n totalEntries: number;\n uniqueUsers: number;\n recentLogins: number;\n failedAttempts: number;\n }> {\n if (!this.enabled) {\n return {\n totalEntries: 0,\n uniqueUsers: 0,\n recentLogins: 0,\n failedAttempts: 0,\n };\n }\n\n try {\n const [total, unique, recent, failed] = await Promise.all([\n this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable}`),\n this.config.db.query(`SELECT COUNT(DISTINCT account_id) as count FROM ${this.activityTable} WHERE account_id IS NOT NULL`),\n this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable} WHERE action = 'login' AND created_at > NOW() - INTERVAL '24 hours'`),\n this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable} WHERE success = false AND created_at > NOW() - INTERVAL '24 hours'`),\n ]);\n\n return {\n totalEntries: parseInt(total.rows[0]?.count || \"0\"),\n uniqueUsers: parseInt(unique.rows[0]?.count || \"0\"),\n recentLogins: parseInt(recent.rows[0]?.count || \"0\"),\n failedAttempts: parseInt(failed.rows[0]?.count || \"0\"),\n };\n } catch (error) {\n console.error(\"ActivityLogger: Failed to get activity stats:\", error);\n return {\n totalEntries: 0,\n uniqueUsers: 0,\n recentLogins: 0,\n failedAttempts: 0,\n };\n }\n }\n}\n","export class AuthError extends Error {\n constructor(message: string) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n\nexport class ConfirmationExpiredError extends AuthError {\n constructor() {\n super(\"Confirmation token has expired\");\n }\n}\n\nexport class ConfirmationNotFoundError extends AuthError {\n constructor() {\n super(\"Confirmation token not found\");\n }\n}\n\nexport class EmailNotVerifiedError extends AuthError {\n constructor() {\n super(\"Email address has not been verified\");\n }\n}\n\nexport class EmailTakenError extends AuthError {\n constructor() {\n super(\"Email address is already in use\");\n }\n}\n\nexport class InvalidEmailError extends AuthError {\n constructor() {\n super(\"Invalid email address format\");\n }\n}\n\nexport class InvalidPasswordError extends AuthError {\n constructor() {\n super(\"Invalid password\");\n }\n}\n\nexport class InvalidTokenError extends AuthError {\n constructor() {\n super(\"Invalid token\");\n }\n}\n\nexport class ResetDisabledError extends AuthError {\n constructor() {\n super(\"Password reset is disabled for this account\");\n }\n}\n\nexport class ResetExpiredError extends AuthError {\n constructor() {\n super(\"Password reset token has expired\");\n }\n}\n\nexport class ResetNotFoundError extends AuthError {\n constructor() {\n super(\"Password reset token not found\");\n }\n}\n\nexport class TooManyResetsError extends AuthError {\n constructor() {\n super(\"Too many password reset requests\");\n }\n}\n\nexport class UserInactiveError extends AuthError {\n constructor() {\n super(\"User account is inactive\");\n }\n}\n\nexport class UserNotFoundError extends AuthError {\n constructor() {\n super(\"User not found\");\n }\n}\n\nexport class UserNotLoggedInError extends AuthError {\n constructor() {\n super(\"User is not logged in\");\n }\n}\n\n// two-factor authentication errors\n\nexport class SecondFactorRequiredError extends AuthError {\n public availableMethods: {\n totp?: boolean;\n email?: { otpValue: string; maskedContact: string };\n sms?: { otpValue: string; maskedContact: string };\n };\n\n constructor(availableMethods: SecondFactorRequiredError[\"availableMethods\"]) {\n super(\"Second factor authentication required\");\n this.availableMethods = availableMethods;\n }\n}\n\nexport class InvalidTwoFactorCodeError extends AuthError {\n constructor() {\n super(\"Invalid two-factor authentication code\");\n }\n}\n\nexport class TwoFactorExpiredError extends AuthError {\n constructor() {\n super(\"Two-factor authentication session has expired\");\n }\n}\n\nexport class TwoFactorNotSetupError extends AuthError {\n constructor() {\n super(\"Two-factor authentication is not set up for this account\");\n }\n}\n\nexport class TwoFactorAlreadyEnabledError extends AuthError {\n constructor() {\n super(\"Two-factor authentication is already enabled for this mechanism\");\n }\n}\n\nexport class InvalidBackupCodeError extends AuthError {\n constructor() {\n super(\"Invalid backup code\");\n }\n}\n\nexport class TwoFactorSetupIncompleteError extends AuthError {\n constructor() {\n super(\"Two-factor authentication setup is not complete\");\n }\n}\n","import { InvalidEmailError } from \"./errors.js\";\n\nexport const isValidEmail = (email: string): boolean => {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(email);\n};\n\nexport const validateEmail = (email: string): void => {\n if (typeof email !== \"string\") {\n throw new InvalidEmailError();\n }\n if (!email.trim()) {\n throw new InvalidEmailError();\n }\n if (!isValidEmail(email)) {\n throw new InvalidEmailError();\n }\n};\n\nexport const createMapFromEnum = (enumObj: Record<string, number>) => Object.fromEntries(Object.entries(enumObj).map(([key, value]) => [value, key]));\n","import type { Request } from \"express\";\nimport type { OAuthProvider, OAuthUserData, OAuthProviderConfig, AuthConfig, OAuthCallbackResult } from \"../types.js\";\nimport { AuthManager } from \"../auth-manager.js\";\n\nexport abstract class BaseOAuthProvider implements OAuthProvider {\n protected config: OAuthProviderConfig;\n protected authConfig: AuthConfig;\n protected authManager: AuthManager;\n\n constructor(config: OAuthProviderConfig, authConfig: AuthConfig, authManager: AuthManager) {\n this.config = config;\n this.authConfig = authConfig;\n this.authManager = authManager;\n }\n\n abstract getAuthUrl(state?: string, scopes?: string[]): string;\n abstract getUserData(req: Request): Promise<OAuthUserData>;\n\n async handleCallback(req: Request): Promise<OAuthCallbackResult> {\n const userData = await this.getUserData(req);\n return this.processOAuthLogin(userData, req);\n }\n\n protected async processOAuthLogin(userData: OAuthUserData, req: Request): Promise<OAuthCallbackResult> {\n const { queries } = this.authManager as any;\n const providerName = this.getProviderName();\n\n const existingProvider = await queries.findProviderByProviderIdAndType(userData.id, providerName);\n\n if (existingProvider) {\n const account = await queries.findAccountById(existingProvider.account_id);\n if (account) {\n await (this.authManager as any).onLoginSuccessful(account, true);\n return { isNewUser: false };\n }\n }\n\n // new OAuth user - check if email already exists\n if (userData.email) {\n const existingAccount = await queries.findAccountByEmail(userData.email);\n if (existingAccount) {\n throw new Error(\"You already have an account associated with this email address.\");\n }\n }\n\n // create new user and account\n let userId: string | number;\n\n if (this.authConfig.createUser) {\n userId = await this.authConfig.createUser(userData);\n } else {\n // Generate UUID for OAuth users when no createUser function is provided\n userId = crypto.randomUUID();\n }\n\n // create the auth account (no password for OAuth)\n const account = await queries.createAccount({\n userId,\n email: userData.email,\n password: null,\n verified: true, // OAuth providers are pre-verified\n status: 0, // AuthStatus.Normal\n rolemask: 0,\n });\n\n // create the provider record\n await queries.createProvider({\n accountId: account.id,\n provider: providerName,\n providerId: userData.id,\n providerEmail: userData.email,\n providerUsername: userData.username || null,\n providerName: userData.name || null,\n providerAvatar: userData.avatar || null,\n });\n\n await (this.authManager as any).onLoginSuccessful(account, true);\n return { isNewUser: true };\n }\n\n protected abstract getProviderName(): string;\n\n protected async exchangeCodeForToken(code: string, tokenUrl: string): Promise<string> {\n const response = await fetch(tokenUrl, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: new URLSearchParams({\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n code,\n redirect_uri: this.config.redirectUri,\n grant_type: \"authorization_code\",\n }),\n });\n\n if (!response.ok) {\n throw new Error(`OAuth token exchange failed: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n if (!data.access_token) {\n throw new Error(\"No access token received from OAuth provider\");\n }\n\n return data.access_token;\n }\n\n protected async fetchUserFromAPI(accessToken: string, apiUrl: string): Promise<any> {\n const response = await fetch(apiUrl, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n Accept: \"application/json\",\n },\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch user data: ${response.status} ${response.statusText}`);\n }\n\n return response.json();\n }\n}\n","import type { Request } from \"express\";\nimport type { OAuthUserData, GitHubProviderConfig, AuthConfig } from \"../types.js\";\nimport { BaseOAuthProvider } from \"./base-provider.js\";\nimport { AuthManager } from \"../auth-manager.js\";\n\nexport class GitHubProvider extends BaseOAuthProvider {\n constructor(config: GitHubProviderConfig, authConfig: AuthConfig, authManager: AuthManager) {\n super(config, authConfig, authManager);\n }\n\n getAuthUrl(state?: string, scopes?: string[]): string {\n const params = new URLSearchParams({\n client_id: this.config.clientId,\n redirect_uri: this.config.redirectUri,\n scope: scopes?.join(\" \") || \"user:email\",\n state: state || Math.random().toString(36).substring(2),\n response_type: \"code\",\n });\n\n return `https://github.com/login/oauth/authorize?${params}`;\n }\n\n async getUserData(req: Request): Promise<OAuthUserData> {\n const code = req.query.code as string;\n if (!code) {\n throw new Error(\"No authorization code provided\");\n }\n\n // exchange code for access token\n const accessToken = await this.exchangeCodeForToken(code, \"https://github.com/login/oauth/access_token\");\n\n // fetch user data\n const [user, emails] = await Promise.all([this.fetchUserFromAPI(accessToken, \"https://api.github.com/user\"), this.fetchUserFromAPI(accessToken, \"https://api.github.com/user/emails\")]);\n\n // find primary email\n const primaryEmail = Array.isArray(emails) ? emails.find((email: any) => email.primary)?.email : null;\n\n if (!primaryEmail) {\n throw new Error(\"No primary email found in GitHub account\");\n }\n\n return {\n id: user.id.toString(),\n email: primaryEmail,\n username: user.login,\n name: user.name || user.login,\n avatar: user.avatar_url,\n };\n }\n\n protected getProviderName(): string {\n return \"github\";\n }\n}\n","import type { Request } from \"express\";\nimport type { OAuthUserData, GoogleProviderConfig, AuthConfig } from \"../types.js\";\nimport { BaseOAuthProvider } from \"./base-provider.js\";\nimport { AuthManager } from \"../auth-manager.js\";\n\nexport class GoogleProvider extends BaseOAuthProvider {\n constructor(config: GoogleProviderConfig, authConfig: AuthConfig, authManager: AuthManager) {\n super(config, authConfig, authManager);\n }\n\n getAuthUrl(state?: string, scopes?: string[]): string {\n const params = new URLSearchParams({\n client_id: this.config.clientId,\n redirect_uri: this.config.redirectUri,\n scope: scopes?.join(\" \") || \"openid profile email\",\n state: state || Math.random().toString(36).substring(2),\n response_type: \"code\",\n access_type: \"offline\",\n prompt: \"consent\",\n });\n\n return `https://accounts.google.com/o/oauth2/v2/auth?${params}`;\n }\n\n async getUserData(req: Request): Promise<OAuthUserData> {\n const code = req.query.code as string;\n if (!code) {\n throw new Error(\"No authorization code provided\");\n }\n\n // exchange code for access token\n const accessToken = await this.exchangeCodeForToken(code, \"https://oauth2.googleapis.com/token\");\n\n // fetch user data\n const user = await this.fetchUserFromAPI(accessToken, \"https://www.googleapis.com/oauth2/v2/userinfo\");\n\n if (!user.email) {\n throw new Error(\"No email found in Google account\");\n }\n\n return {\n id: user.id,\n email: user.email,\n username: user.email.split(\"@\")[0], // use email prefix as username\n name: user.name,\n avatar: user.picture,\n };\n }\n\n protected getProviderName(): string {\n return \"google\";\n }\n}\n","import type { Request } from \"express\";\nimport type { OAuthUserData, AzureProviderConfig, AuthConfig } from \"../types.js\";\nimport { BaseOAuthProvider } from \"./base-provider.js\";\nimport { AuthManager } from \"../auth-manager.js\";\n\nexport class AzureProvider extends BaseOAuthProvider {\n constructor(config: AzureProviderConfig, authConfig: AuthConfig, authManager: AuthManager) {\n super(config, authConfig, authManager);\n }\n\n getAuthUrl(state?: string, scopes?: string[]): string {\n const azureConfig = this.config as AzureProviderConfig;\n const params = new URLSearchParams({\n client_id: azureConfig.clientId,\n redirect_uri: azureConfig.redirectUri,\n scope: scopes?.join(\" \") || \"openid profile email User.Read\",\n state: state || Math.random().toString(36).substring(2),\n response_type: \"code\",\n response_mode: \"query\",\n });\n\n return `https://login.microsoftonline.com/${azureConfig.tenantId}/oauth2/v2.0/authorize?${params}`;\n }\n\n async getUserData(req: Request): Promise<OAuthUserData> {\n const code = req.query.code as string;\n if (!code) {\n throw new Error(\"No authorization code provided\");\n }\n\n // exchange code for access token\n const azureConfig = this.config as AzureProviderConfig;\n const accessToken = await this.exchangeCodeForToken(code, `https://login.microsoftonline.com/${azureConfig.tenantId}/oauth2/v2.0/token`);\n\n // fetch user data from Microsoft Graph\n const user = await this.fetchUserFromAPI(accessToken, \"https://graph.microsoft.com/v1.0/me\");\n\n if (!user.mail && !user.userPrincipalName) {\n throw new Error(\"No email found in Azure account\");\n }\n\n return {\n id: user.id,\n email: user.mail || user.userPrincipalName,\n username: user.mailNickname || user.userPrincipalName?.split(\"@\")[0],\n name: user.displayName,\n avatar: undefined, // Azure doesn't provide avatar in basic profile\n };\n }\n\n protected getProviderName(): string {\n return \"azure\";\n }\n\n protected async exchangeCodeForToken(code: string, tokenUrl: string): Promise<string> {\n const azureConfig = this.config as AzureProviderConfig;\n const response = await fetch(tokenUrl, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: new URLSearchParams({\n client_id: azureConfig.clientId,\n client_secret: azureConfig.clientSecret,\n code,\n redirect_uri: azureConfig.redirectUri,\n grant_type: \"authorization_code\",\n scope: \"openid profile email User.Read\",\n }),\n });\n\n if (!response.ok) {\n throw new Error(`OAuth token exchange failed: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n if (!data.access_token) {\n throw new Error(\"No access token received from Azure\");\n }\n\n return data.access_token;\n }\n}\n","import Otp from \"@eaccess/totp\";\nimport { hash } from \"@prsm/hash\";\nimport type { AuthConfig } from \"../types.js\";\nimport type { Request } from \"express\";\n\nexport class TotpProvider {\n private config: AuthConfig;\n\n constructor(config: AuthConfig) {\n this.config = config;\n }\n\n generateSecret(): string {\n return Otp.createSecret();\n }\n\n generateQRCode(email: string, secret: string): string {\n const issuer = this.config.twoFactor?.issuer || \"EasyAccess\";\n return Otp.createTotpKeyUriForQrCode(issuer, email, secret);\n }\n\n verify(secret: string, code: string): boolean {\n const window = this.config.twoFactor?.totpWindow || 1;\n return Otp.verifyTotp(secret, code, window);\n }\n\n generateBackupCodes(count: number = 10): string[] {\n const codes: string[] = [];\n for (let i = 0; i < count; i++) {\n // generate 8-character backup codes (numbers + letters, avoiding confusing characters)\n const chars = \"23456789ABCDEFGHJKLMNPQRSTUVWXYZ\";\n let code = \"\";\n for (let j = 0; j < 8; j++) {\n code += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n codes.push(code);\n }\n return codes;\n }\n\n hashBackupCodes(codes: string[]): string[] {\n return codes.map((code) => hash.encode(code));\n }\n\n verifyBackupCode(hashedCodes: string[], inputCode: string): { isValid: boolean; index: number } {\n for (let i = 0; i < hashedCodes.length; i++) {\n if (hash.verify(hashedCodes[i], inputCode.toUpperCase())) {\n return { isValid: true, index: i };\n }\n }\n\n return { isValid: false, index: -1 };\n }\n\n maskEmail(email: string): string {\n const [username, domain] = email.split(\"@\");\n if (username.length <= 2) {\n return `${username[0]}***@${domain}`;\n }\n return `${username[0]}${\"*\".repeat(username.length - 2)}${username[username.length - 1]}@${domain}`;\n }\n}\n","import ms from \"@prsm/ms\";\nimport { hash } from \"@prsm/hash\";\nimport type { AuthConfig, TwoFactorMechanism, TwoFactorToken } from \"../types.js\";\nimport { AuthQueries } from \"../queries.js\";\n\nexport class OtpProvider {\n private config: AuthConfig;\n private queries: AuthQueries;\n\n constructor(config: AuthConfig) {\n this.config = config;\n this.queries = new AuthQueries(config);\n }\n\n generateOTP(): string {\n const length = this.config.twoFactor?.codeLength || 6;\n let otp = \"\";\n for (let i = 0; i < length; i++) {\n otp += Math.floor(Math.random() * 10).toString();\n }\n return otp;\n }\n\n generateSelector(): string {\n // generate a random 32-character selector for security\n const chars = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\";\n let selector = \"\";\n for (let i = 0; i < 32; i++) {\n selector += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return selector;\n }\n\n async createAndStoreOTP(accountId: number, mechanism: TwoFactorMechanism.EMAIL | TwoFactorMechanism.SMS): Promise<{ otp: string; selector: string }> {\n const otp = this.generateOTP();\n const selector = this.generateSelector();\n const tokenHash = hash.encode(otp);\n\n const expiryDuration = this.config.twoFactor?.tokenExpiry || \"5m\";\n const expiresAt = new Date(Date.now() + ms(expiryDuration));\n\n // delete any existing tokens for this account and mechanism\n await this.queries.deleteTwoFactorTokensByAccountAndMechanism(accountId, mechanism);\n\n // store the new token\n await this.queries.createTwoFactorToken({\n accountId,\n mechanism,\n selector,\n tokenHash,\n expiresAt,\n });\n\n return { otp, selector };\n }\n\n async verifyOTP(selector: string, inputCode: string): Promise<{ isValid: boolean; token?: TwoFactorToken }> {\n const token = await this.queries.findTwoFactorTokenBySelector(selector);\n\n if (!token) {\n return { isValid: false };\n }\n\n // check if token has expired (extra check, even though query filters expired tokens)\n if (token.expires_at <= new Date()) {\n // clean up expired token\n await this.queries.deleteTwoFactorToken(token.id);\n return { isValid: false };\n }\n\n const isValid = hash.verify(token.token_hash, inputCode);\n\n if (isValid) {\n // clean up used token\n await this.queries.deleteTwoFactorToken(token.id);\n return { isValid: true, token };\n }\n\n return { isValid: false };\n }\n\n maskPhone(phone: string): string {\n if (phone.length < 4) {\n return phone.replace(/./g, \"*\");\n }\n\n // show first digit and last 2 digits: +1234567890 -> +1*****90\n if (phone.startsWith(\"+\")) {\n return phone[0] + phone[1] + \"*\".repeat(phone.length - 3) + phone.slice(-2);\n }\n\n // for regular numbers: 1234567890 -> 1*****90\n return phone[0] + \"*\".repeat(phone.length - 3) + phone.slice(-2);\n }\n\n maskEmail(email: string): string {\n const [username, domain] = email.split(\"@\");\n if (username.length <= 2) {\n return `${username[0]}***@${domain}`;\n }\n return `${username[0]}${\"*\".repeat(username.length - 2)}${username[username.length - 1]}@${domain}`;\n }\n}\n","import type { Request, Response } from \"express\";\nimport type { AuthConfig, TwoFactorManager as ITwoFactorManager, TwoFactorSetupResult, TwoFactorChallenge } from \"../types.js\";\nimport { TwoFactorMechanism } from \"../types.js\";\nimport { AuthQueries } from \"../queries.js\";\nimport { ActivityLogger } from \"../activity-logger.js\";\nimport { AuthActivityAction } from \"../types.js\";\nimport { TotpProvider } from \"./totp-provider.js\";\nimport { OtpProvider } from \"./otp-provider.js\";\nimport { TwoFactorNotSetupError, TwoFactorAlreadyEnabledError, TwoFactorSetupIncompleteError, InvalidTwoFactorCodeError, InvalidBackupCodeError, UserNotLoggedInError } from \"../errors.js\";\n\nexport class TwoFactorManager implements ITwoFactorManager {\n private req: Request;\n private res: Response;\n private config: AuthConfig;\n private queries: AuthQueries;\n private activityLogger: ActivityLogger;\n private totpProvider: TotpProvider;\n private otpProvider: OtpProvider;\n\n constructor(req: Request, res: Response, config: AuthConfig) {\n this.req = req;\n this.res = res;\n this.config = config;\n this.queries = new AuthQueries(config);\n this.activityLogger = new ActivityLogger(config);\n this.totpProvider = new TotpProvider(config);\n this.otpProvider = new OtpProvider(config);\n }\n\n private getAccountId(): number | null {\n return this.req.session?.auth?.accountId || null;\n }\n\n private getEmail(): string | null {\n return this.req.session?.auth?.email || null;\n }\n\n // status queries\n\n async isEnabled(): Promise<boolean> {\n const accountId = this.getAccountId();\n if (!accountId) return false;\n\n const methods = await this.queries.findTwoFactorMethodsByAccountId(accountId);\n return methods.some((method) => method.verified);\n }\n\n async totpEnabled(): Promise<boolean> {\n const accountId = this.getAccountId();\n if (!accountId) return false;\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.TOTP);\n return method?.verified || false;\n }\n\n async emailEnabled(): Promise<boolean> {\n const accountId = this.getAccountId();\n if (!accountId) return false;\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.EMAIL);\n return method?.verified || false;\n }\n\n async smsEnabled(): Promise<boolean> {\n const accountId = this.getAccountId();\n if (!accountId) return false;\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.SMS);\n return method?.verified || false;\n }\n\n async getEnabledMethods(): Promise<TwoFactorMechanism[]> {\n const accountId = this.getAccountId();\n if (!accountId) return [];\n\n const methods = await this.queries.findTwoFactorMethodsByAccountId(accountId);\n return methods.filter((method) => method.verified).map((method) => method.mechanism);\n }\n\n // setup & management\n\n setup = {\n totp: async (requireVerification = false): Promise<TwoFactorSetupResult> => {\n const accountId = this.getAccountId();\n const email = this.getEmail();\n\n if (!accountId || !email) {\n throw new UserNotLoggedInError();\n }\n\n // check if TOTP is already enabled\n const existingMethod = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.TOTP);\n\n if (existingMethod?.verified) {\n throw new TwoFactorAlreadyEnabledError();\n }\n\n const secret = this.totpProvider.generateSecret();\n const qrCode = this.totpProvider.generateQRCode(email, secret);\n\n // generate backup codes immediately if no verification required\n let backupCodes: string[] | undefined;\n if (!requireVerification) {\n const backupCodesCount = this.config.twoFactor?.backupCodesCount || 10;\n backupCodes = this.totpProvider.generateBackupCodes(backupCodesCount);\n }\n\n const hashedBackupCodes = backupCodes ? this.totpProvider.hashBackupCodes(backupCodes) : undefined;\n const verified = !requireVerification;\n\n // create or update the TOTP method\n if (existingMethod) {\n await this.queries.updateTwoFactorMethod(existingMethod.id, {\n secret,\n backup_codes: hashedBackupCodes || null,\n verified,\n });\n } else {\n await this.queries.createTwoFactorMethod({\n accountId,\n mechanism: TwoFactorMechanism.TOTP,\n secret,\n backupCodes: hashedBackupCodes,\n verified,\n });\n }\n\n if (verified) {\n await this.activityLogger.logActivity(accountId, AuthActivityAction.TwoFactorSetup, this.req, true, { mechanism: \"totp\" });\n }\n\n return { secret, qrCode, backupCodes };\n },\n\n email: async (email?: string, requireVerification = false): Promise<void> => {\n const accountId = this.getAccountId();\n const userEmail = email || this.getEmail();\n\n if (!accountId || !userEmail) {\n throw new UserNotLoggedInError();\n }\n\n // check if email 2FA is already enabled\n const existingMethod = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.EMAIL);\n\n if (existingMethod?.verified) {\n throw new TwoFactorAlreadyEnabledError();\n }\n\n const verified = !requireVerification;\n\n // create or update the email method\n if (existingMethod) {\n await this.queries.updateTwoFactorMethod(existingMethod.id, {\n secret: userEmail,\n verified,\n });\n } else {\n await this.queries.createTwoFactorMethod({\n accountId,\n mechanism: TwoFactorMechanism.EMAIL,\n secret: userEmail,\n verified,\n });\n }\n\n if (verified) {\n await this.activityLogger.logActivity(accountId, AuthActivityAction.TwoFactorSetup, this.req, true, { mechanism: \"email\" });\n }\n },\n\n sms: async (phone: string, requireVerification = true): Promise<void> => {\n const accountId = this.getAccountId();\n\n if (!accountId) {\n throw new UserNotLoggedInError();\n }\n\n // check if SMS 2FA is already enabled\n const existingMethod = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.SMS);\n\n if (existingMethod?.verified) {\n throw new TwoFactorAlreadyEnabledError();\n }\n\n const verified = !requireVerification;\n\n // create or update the SMS method\n if (existingMethod) {\n await this.queries.updateTwoFactorMethod(existingMethod.id, {\n secret: phone,\n verified,\n });\n } else {\n await this.queries.createTwoFactorMethod({\n accountId,\n mechanism: TwoFactorMechanism.SMS,\n secret: phone,\n verified,\n });\n }\n\n if (verified) {\n await this.activityLogger.logActivity(accountId, AuthActivityAction.TwoFactorSetup, this.req, true, { mechanism: \"sms\" });\n }\n },\n };\n\n complete = {\n totp: async (code: string): Promise<string[]> => {\n const accountId = this.getAccountId();\n\n if (!accountId) {\n throw new UserNotLoggedInError();\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.TOTP);\n\n if (!method || !method.secret) {\n throw new TwoFactorNotSetupError();\n }\n\n if (method.verified) {\n throw new TwoFactorAlreadyEnabledError();\n }\n\n // verify the TOTP code\n const isValid = this.totpProvider.verify(method.secret, code);\n if (!isValid) {\n await this.activityLogger.logActivity(accountId, AuthActivityAction.TwoFactorFailed, this.req, false, { mechanism: \"totp\", reason: \"invalid_code\" });\n throw new InvalidTwoFactorCodeError();\n }\n\n // generate backup codes\n const backupCodesCount = this.config.twoFactor?.backupCodesCount || 10;\n const backupCodes = this.totpProvider.generateBackupCodes(backupCodesCount);\n const hashedBackupCodes = this.totpProvider.hashBackupCodes(backupCodes);\n\n // mark as verified and store backup codes\n await this.queries.updateTwoFactorMethod(method.id, {\n verified: true,\n backup_codes: hashedBackupCodes,\n last_used_at: new Date(),\n });\n\n await this.activityLogger.logActivity(accountId, AuthActivityAction.TwoFactorSetup, this.req, true, { mechanism: \"totp\" });\n\n return backupCodes;\n },\n\n email: async (code: string): Promise<void> => {\n await this.completeOtpSetup(TwoFactorMechanism.EMAIL, code);\n },\n\n sms: async (code: string): Promise<void> => {\n await this.completeOtpSetup(TwoFactorMechanism.SMS, code);\n },\n };\n\n private async completeOtpSetup(mechanism: TwoFactorMechanism.EMAIL | TwoFactorMechanism.SMS, code: string): Promise<void> {\n const accountId = this.getAccountId();\n\n if (!accountId) {\n throw new UserNotLoggedInError();\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, mechanism);\n\n if (!method) {\n throw new TwoFactorNotSetupError();\n }\n\n if (method.verified) {\n throw new TwoFactorAlreadyEnabledError();\n }\n\n // for setup completion, we need a temporary OTP that was sent during setup\n // this should be handled by the application calling this method after sending an OTP\n // for now, we'll assume the code is valid if provided (in a real implementation,\n // you'd generate and store a temporary OTP during the setup process)\n\n // mark as verified\n await this.queries.updateTwoFactorMethod(method.id, {\n verified: true,\n last_used_at: new Date(),\n });\n\n await this.activityLogger.logActivity(accountId, AuthActivityAction.TwoFactorSetup, this.req, true, { mechanism: mechanism === TwoFactorMechanism.EMAIL ? \"email\" : \"sms\" });\n }\n\n // verification during login flow\n\n verify = {\n totp: async (code: string): Promise<void> => {\n const twoFactorState = this.req.session?.auth?.awaitingTwoFactor;\n\n if (!twoFactorState) {\n throw new UserNotLoggedInError();\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(twoFactorState.accountId, TwoFactorMechanism.TOTP);\n\n if (!method || !method.verified || !method.secret) {\n throw new TwoFactorNotSetupError();\n }\n\n const isValid = this.totpProvider.verify(method.secret, code);\n if (!isValid) {\n await this.activityLogger.logActivity(twoFactorState.accountId, AuthActivityAction.TwoFactorFailed, this.req, false, { mechanism: \"totp\", reason: \"invalid_code\" });\n throw new InvalidTwoFactorCodeError();\n }\n\n // update last used\n await this.queries.updateTwoFactorMethod(method.id, {\n last_used_at: new Date(),\n });\n\n await this.activityLogger.logActivity(twoFactorState.accountId, AuthActivityAction.TwoFactorVerified, this.req, true, { mechanism: \"totp\" });\n },\n\n email: async (code: string): Promise<void> => {\n await this.verifyOtp(TwoFactorMechanism.EMAIL, code);\n },\n\n sms: async (code: string): Promise<void> => {\n await this.verifyOtp(TwoFactorMechanism.SMS, code);\n },\n\n backupCode: async (code: string): Promise<void> => {\n const twoFactorState = this.req.session?.auth?.awaitingTwoFactor;\n\n if (!twoFactorState) {\n throw new UserNotLoggedInError();\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(twoFactorState.accountId, TwoFactorMechanism.TOTP);\n\n if (!method || !method.verified || !method.backup_codes) {\n throw new TwoFactorNotSetupError();\n }\n\n const { isValid, index } = this.totpProvider.verifyBackupCode(method.backup_codes, code);\n\n if (!isValid) {\n await this.activityLogger.logActivity(twoFactorState.accountId, AuthActivityAction.TwoFactorFailed, this.req, false, { mechanism: \"backup_code\", reason: \"invalid_code\" });\n throw new InvalidBackupCodeError();\n }\n\n // remove the used backup code\n const updatedBackupCodes = [...method.backup_codes];\n updatedBackupCodes.splice(index, 1);\n\n await this.queries.updateTwoFactorMethod(method.id, {\n backup_codes: updatedBackupCodes,\n last_used_at: new Date(),\n });\n\n await this.activityLogger.logActivity(twoFactorState.accountId, AuthActivityAction.BackupCodeUsed, this.req, true, { remaining_codes: updatedBackupCodes.length });\n },\n\n otp: async (code: string): Promise<void> => {\n const twoFactorState = this.req.session?.auth?.awaitingTwoFactor;\n\n if (!twoFactorState) {\n throw new UserNotLoggedInError();\n }\n\n // try to find which mechanism this OTP is for based on available methods\n const availableMechanisms = twoFactorState.availableMechanisms.filter((m) => m === TwoFactorMechanism.EMAIL || m === TwoFactorMechanism.SMS);\n\n if (availableMechanisms.length === 0) {\n throw new TwoFactorNotSetupError();\n }\n\n // try each available OTP mechanism\n for (const mechanism of availableMechanisms) {\n try {\n await this.verifyOtp(mechanism, code);\n return; // success, exit early\n } catch (error) {\n // continue to next mechanism\n continue;\n }\n }\n\n // if we get here, none of the mechanisms worked\n await this.activityLogger.logActivity(twoFactorState.accountId, AuthActivityAction.TwoFactorFailed, this.req, false, { mechanism: \"otp\", reason: \"invalid_code\" });\n throw new InvalidTwoFactorCodeError();\n },\n };\n\n private async verifyOtp(mechanism: TwoFactorMechanism.EMAIL | TwoFactorMechanism.SMS, code: string): Promise<void> {\n const twoFactorState = this.req.session?.auth?.awaitingTwoFactor;\n\n if (!twoFactorState) {\n throw new UserNotLoggedInError();\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(twoFactorState.accountId, mechanism);\n\n if (!method || !method.verified) {\n throw new TwoFactorNotSetupError();\n }\n\n // find the selector that was stored during login attempt\n const selector = mechanism === TwoFactorMechanism.EMAIL ? this.req.session?.auth?.awaitingTwoFactor?.selectors?.email : this.req.session?.auth?.awaitingTwoFactor?.selectors?.sms;\n\n if (!selector) {\n throw new InvalidTwoFactorCodeError();\n }\n\n const { isValid } = await this.otpProvider.verifyOTP(selector, code);\n\n if (!isValid) {\n await this.activityLogger.logActivity(twoFactorState.accountId, AuthActivityAction.TwoFactorFailed, this.req, false, {\n mechanism: mechanism === TwoFactorMechanism.EMAIL ? \"email\" : \"sms\",\n reason: \"invalid_code\",\n });\n throw new InvalidTwoFactorCodeError();\n }\n\n // update last used\n await this.queries.updateTwoFactorMethod(method.id, {\n last_used_at: new Date(),\n });\n\n await this.activityLogger.logActivity(twoFactorState.accountId, AuthActivityAction.TwoFactorVerified, this.req, true, { mechanism: mechanism === TwoFactorMechanism.EMAIL ? \"email\" : \"sms\" });\n }\n\n // management\n\n async disable(mechanism: TwoFactorMechanism): Promise<void> {\n const accountId = this.getAccountId();\n\n if (!accountId) {\n throw new UserNotLoggedInError();\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, mechanism);\n\n if (!method) {\n throw new TwoFactorNotSetupError();\n }\n\n await this.queries.deleteTwoFactorMethod(method.id);\n\n await this.activityLogger.logActivity(accountId, AuthActivityAction.TwoFactorDisabled, this.req, true, {\n mechanism: mechanism === TwoFactorMechanism.TOTP ? \"totp\" : mechanism === TwoFactorMechanism.EMAIL ? \"email\" : \"sms\",\n });\n }\n\n async generateNewBackupCodes(): Promise<string[]> {\n const accountId = this.getAccountId();\n\n if (!accountId) {\n throw new UserNotLoggedInError();\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.TOTP);\n\n if (!method || !method.verified) {\n throw new TwoFactorNotSetupError();\n }\n\n const backupCodesCount = this.config.twoFactor?.backupCodesCount || 10;\n const backupCodes = this.totpProvider.generateBackupCodes(backupCodesCount);\n const hashedBackupCodes = this.totpProvider.hashBackupCodes(backupCodes);\n\n await this.queries.updateTwoFactorMethod(method.id, {\n backup_codes: hashedBackupCodes,\n });\n\n return backupCodes;\n }\n\n async getContact(mechanism: TwoFactorMechanism.EMAIL | TwoFactorMechanism.SMS): Promise<string | null> {\n const accountId = this.getAccountId();\n\n if (!accountId) {\n return null;\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, mechanism);\n\n return method?.secret || null;\n }\n\n async getTotpUri(): Promise<string | null> {\n const accountId = this.getAccountId();\n const email = this.getEmail();\n\n if (!accountId || !email) {\n return null;\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.TOTP);\n\n if (!method?.secret) {\n return null;\n }\n\n return this.totpProvider.generateQRCode(email, method.secret);\n }\n\n // challenge creation (used during login)\n\n async createChallenge(accountId: number): Promise<TwoFactorChallenge> {\n const methods = await this.queries.findTwoFactorMethodsByAccountId(accountId);\n const verifiedMethods = methods.filter((method) => method.verified);\n\n const challenge: TwoFactorChallenge = {\n selectors: {},\n };\n\n for (const method of verifiedMethods) {\n switch (method.mechanism) {\n case TwoFactorMechanism.TOTP:\n challenge.totp = true;\n break;\n\n case TwoFactorMechanism.EMAIL:\n if (method.secret) {\n const { otp, selector } = await this.otpProvider.createAndStoreOTP(accountId, method.mechanism);\n challenge.email = {\n otpValue: otp,\n maskedContact: this.otpProvider.maskEmail(method.secret),\n };\n challenge.selectors!.email = selector;\n }\n break;\n\n case TwoFactorMechanism.SMS:\n if (method.secret) {\n const { otp, selector } = await this.otpProvider.createAndStoreOTP(accountId, method.mechanism);\n challenge.sms = {\n otpValue: otp,\n maskedContact: this.otpProvider.maskPhone(method.secret),\n };\n challenge.selectors!.sms = selector;\n }\n break;\n }\n }\n\n return challenge;\n }\n}\n","import { hash } from \"@prsm/hash\";\nimport ms from \"@prsm/ms\";\nimport type { AuthConfig, AuthAccount, TokenCallback } from \"./types.js\";\nimport { AuthQueries } from \"./queries.js\";\nimport { validateEmail } from \"./util.js\";\nimport { EmailTakenError, InvalidPasswordError, UserNotFoundError, EmailNotVerifiedError, ResetDisabledError, TooManyResetsError, ResetNotFoundError, ResetExpiredError, InvalidTokenError } from \"./errors.js\";\nimport { AuthStatus } from \"./types.js\";\n\nfunction validatePassword(password: string, config: AuthConfig): void {\n const minLength = config.minPasswordLength || 8;\n const maxLength = config.maxPasswordLength || 64;\n\n if (typeof password !== \"string\") {\n throw new InvalidPasswordError();\n }\n\n if (password.length < minLength) {\n throw new InvalidPasswordError();\n }\n\n if (password.length > maxLength) {\n throw new InvalidPasswordError();\n }\n}\n\nfunction generateAutoUserId(): string {\n return crypto.randomUUID();\n}\n\nasync function findAccountByIdentifier(queries: AuthQueries, identifier: { accountId?: number; email?: string; userId?: string }): Promise<AuthAccount | null> {\n if (identifier.accountId !== undefined) {\n return await queries.findAccountById(identifier.accountId);\n } else if (identifier.email !== undefined) {\n return await queries.findAccountByEmail(identifier.email);\n } else if (identifier.userId !== undefined) {\n return await queries.findAccountByUserId(identifier.userId);\n }\n return null;\n}\n\nasync function createConfirmationToken(queries: AuthQueries, account: AuthAccount, email: string, callback: TokenCallback): Promise<void> {\n const token = hash.encode(email);\n const expires = new Date(Date.now() + 1000 * 60 * 60 * 24 * 7); // 1 week\n\n await queries.createConfirmation({\n accountId: account.id,\n token,\n email,\n expires,\n });\n\n if (callback) {\n callback(token);\n }\n}\n\nexport async function createUser(config: AuthConfig, credentials: { email: string; password: string }, userId?: string | number, callback?: TokenCallback): Promise<AuthAccount> {\n validateEmail(credentials.email);\n validatePassword(credentials.password, config);\n\n const queries = new AuthQueries(config);\n\n const existing = await queries.findAccountByEmail(credentials.email);\n if (existing) {\n throw new EmailTakenError();\n }\n\n const finalUserId = userId || generateAutoUserId();\n const hashedPassword = hash.encode(credentials.password);\n const verified = typeof callback !== \"function\";\n\n const account = await queries.createAccount({\n userId: finalUserId,\n email: credentials.email,\n password: hashedPassword,\n verified,\n status: AuthStatus.Normal,\n rolemask: 0,\n });\n\n if (!verified && callback) {\n await createConfirmationToken(queries, account, credentials.email, callback);\n }\n\n return account;\n}\n\nexport async function register(config: AuthConfig, email: string, password: string, userId?: string | number, callback?: TokenCallback): Promise<AuthAccount> {\n validateEmail(email);\n validatePassword(password, config);\n\n const queries = new AuthQueries(config);\n\n const existing = await queries.findAccountByEmail(email);\n if (existing) {\n throw new EmailTakenError();\n }\n\n const finalUserId = userId || generateAutoUserId();\n const hashedPassword = hash.encode(password);\n const verified = typeof callback !== \"function\";\n\n const account = await queries.createAccount({\n userId: finalUserId,\n email,\n password: hashedPassword,\n verified,\n status: AuthStatus.Normal,\n rolemask: 0,\n });\n\n if (!verified && callback) {\n await createConfirmationToken(queries, account, email, callback);\n }\n\n return account;\n}\n\nexport async function deleteUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n await queries.deleteAccount(account.id);\n}\n\nexport async function addRoleForUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n const rolemask = account.rolemask | role;\n await queries.updateAccount(account.id, { rolemask });\n}\n\nexport async function removeRoleForUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n const rolemask = account.rolemask & ~role;\n await queries.updateAccount(account.id, { rolemask });\n}\n\nexport async function hasRoleForUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<boolean> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n return (account.rolemask & role) === role;\n}\n\nexport async function changePasswordForUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }, password: string): Promise<void> {\n validatePassword(password, config);\n\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n await queries.updateAccount(account.id, {\n password: hash.encode(password),\n });\n}\n\nexport async function setStatusForUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }, status: number): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n await queries.updateAccount(account.id, { status });\n}\n\nexport async function initiatePasswordResetForUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }, expiresAfter: string | number | null = null, callback?: TokenCallback): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n if (!account.verified) {\n throw new EmailNotVerifiedError();\n }\n\n const expiry = !expiresAfter ? ms(\"6h\") : ms(expiresAfter);\n const token = hash.encode(account.email);\n const expires = new Date(Date.now() + expiry);\n\n await queries.createResetToken({\n accountId: account.id,\n token,\n expires,\n });\n\n if (callback) {\n callback(token);\n }\n}\n\nexport async function resetPassword(config: AuthConfig, email: string, expiresAfter: string | number | null = null, maxOpenRequests: number | null = null, callback?: TokenCallback): Promise<void> {\n validateEmail(email);\n\n const expiry = !expiresAfter ? ms(\"6h\") : ms(expiresAfter);\n const maxRequests = maxOpenRequests === null ? 2 : Math.max(1, maxOpenRequests);\n\n const queries = new AuthQueries(config);\n const account = await queries.findAccountByEmail(email);\n\n if (!account || !account.verified) {\n throw new EmailNotVerifiedError();\n }\n\n if (!account.resettable) {\n throw new ResetDisabledError();\n }\n\n const openRequests = await queries.countActiveResetTokensForAccount(account.id);\n\n if (openRequests >= maxRequests) {\n throw new TooManyResetsError();\n }\n\n const token = hash.encode(email);\n const expires = new Date(Date.now() + expiry);\n\n await queries.createResetToken({\n accountId: account.id,\n token,\n expires,\n });\n\n if (callback) {\n callback(token);\n }\n}\n\nexport async function confirmResetPassword(config: AuthConfig, token: string, password: string): Promise<{ accountId: number; email: string }> {\n const queries = new AuthQueries(config);\n const reset = await queries.findResetToken(token);\n\n if (!reset) {\n throw new ResetNotFoundError();\n }\n\n if (new Date(reset.expires) < new Date()) {\n throw new ResetExpiredError();\n }\n\n const account = await queries.findAccountById(reset.account_id);\n if (!account) {\n throw new UserNotFoundError();\n }\n\n if (!account.resettable) {\n throw new ResetDisabledError();\n }\n\n validatePassword(password, config);\n\n if (!hash.verify(token, account.email)) {\n throw new InvalidTokenError();\n }\n\n await queries.updateAccount(account.id, {\n password: hash.encode(password),\n });\n\n await queries.deleteResetToken(token);\n\n return { accountId: account.id, email: account.email };\n}\n\nexport async function userExistsByEmail(config: AuthConfig, email: string): Promise<boolean> {\n validateEmail(email);\n\n const queries = new AuthQueries(config);\n const account = await queries.findAccountByEmail(email);\n\n return account !== null;\n}\n\nexport async function forceLogoutForUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }): Promise<{ accountId: number }> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n await queries.incrementForceLogout(account.id);\n\n return { accountId: account.id };\n}\n","import type { NextFunction, Request, Response } from \"express\";\nimport { AuthManager } from \"./auth-manager.js\";\nimport type { AuthConfig } from \"./types.js\";\n\nexport function createAuthMiddleware(config: AuthConfig) {\n return async (req: Request, res: Response, next: NextFunction) => {\n try {\n const authManager = new AuthManager(req, res, config);\n\n req.auth = authManager;\n\n // initialize session and process remember directive\n await authManager.resyncSession();\n await authManager.processRememberDirective();\n\n next();\n } catch (error) {\n next(error);\n }\n };\n}\n","import type { AuthConfig } from \"./types.js\";\n\nexport async function createAuthTables(config: AuthConfig): Promise<void> {\n const prefix = config.tablePrefix || \"user_\";\n const { db } = config;\n\n const accountsTable = `${prefix}accounts`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${accountsTable} (\n id SERIAL PRIMARY KEY,\n user_id VARCHAR(255) NOT NULL,\n email VARCHAR(255) NOT NULL UNIQUE,\n password VARCHAR(255),\n verified BOOLEAN DEFAULT FALSE,\n status INTEGER DEFAULT 0,\n rolemask INTEGER DEFAULT 0,\n last_login TIMESTAMPTZ,\n force_logout INTEGER DEFAULT 0,\n resettable BOOLEAN DEFAULT TRUE,\n registered TIMESTAMPTZ DEFAULT NOW(),\n CONSTRAINT ${prefix}unique_user_id_per_account UNIQUE(user_id)\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}accounts_user_id ON ${accountsTable}(user_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}accounts_email ON ${accountsTable}(email)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}accounts_status ON ${accountsTable}(status)`);\n\n const confirmationsTable = `${prefix}confirmations`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${confirmationsTable} (\n id SERIAL PRIMARY KEY,\n account_id INTEGER NOT NULL,\n token VARCHAR(255) NOT NULL,\n email VARCHAR(255) NOT NULL,\n expires TIMESTAMPTZ NOT NULL,\n CONSTRAINT fk_${prefix}confirmations_account \n FOREIGN KEY (account_id) REFERENCES ${accountsTable}(id) ON DELETE CASCADE\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}confirmations_token ON ${confirmationsTable}(token)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}confirmations_email ON ${confirmationsTable}(email)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}confirmations_account_id ON ${confirmationsTable}(account_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}confirmations_expires ON ${confirmationsTable}(expires)`);\n\n const remembersTable = `${prefix}remembers`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${remembersTable} (\n id SERIAL PRIMARY KEY,\n account_id INTEGER NOT NULL,\n token VARCHAR(255) NOT NULL,\n expires TIMESTAMPTZ NOT NULL,\n CONSTRAINT fk_${prefix}remembers_account \n FOREIGN KEY (account_id) REFERENCES ${accountsTable}(id) ON DELETE CASCADE\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}remembers_token ON ${remembersTable}(token)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}remembers_account_id ON ${remembersTable}(account_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}remembers_expires ON ${remembersTable}(expires)`);\n\n const resetsTable = `${prefix}resets`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${resetsTable} (\n id SERIAL PRIMARY KEY,\n account_id INTEGER NOT NULL,\n token VARCHAR(255) NOT NULL,\n expires TIMESTAMPTZ NOT NULL,\n CONSTRAINT fk_${prefix}resets_account \n FOREIGN KEY (account_id) REFERENCES ${accountsTable}(id) ON DELETE CASCADE\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}resets_token ON ${resetsTable}(token)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}resets_account_id ON ${resetsTable}(account_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}resets_expires ON ${resetsTable}(expires)`);\n\n const providersTable = `${prefix}providers`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${providersTable} (\n id SERIAL PRIMARY KEY,\n account_id INTEGER NOT NULL,\n provider VARCHAR(50) NOT NULL,\n provider_id VARCHAR(255) NOT NULL,\n provider_email VARCHAR(255),\n provider_username VARCHAR(255),\n provider_name VARCHAR(255),\n provider_avatar VARCHAR(500),\n created_at TIMESTAMPTZ DEFAULT NOW(),\n updated_at TIMESTAMPTZ DEFAULT NOW(),\n CONSTRAINT fk_${prefix}providers_account \n FOREIGN KEY (account_id) REFERENCES ${accountsTable}(id) ON DELETE CASCADE,\n CONSTRAINT ${prefix}unique_provider_identity \n UNIQUE(provider, provider_id)\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}providers_account_id ON ${providersTable}(account_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}providers_provider ON ${providersTable}(provider)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}providers_provider_id ON ${providersTable}(provider_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}providers_email ON ${providersTable}(provider_email)`);\n\n const activityTable = `${prefix}activity_log`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${activityTable} (\n id SERIAL PRIMARY KEY,\n account_id INTEGER,\n action VARCHAR(255) NOT NULL,\n ip_address INET,\n user_agent TEXT,\n browser VARCHAR(255),\n os VARCHAR(255),\n device VARCHAR(255),\n success BOOLEAN DEFAULT TRUE,\n metadata JSONB,\n created_at TIMESTAMPTZ DEFAULT NOW(),\n CONSTRAINT fk_${prefix}activity_log_account \n FOREIGN KEY (account_id) REFERENCES ${accountsTable}(id) ON DELETE CASCADE\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}activity_log_created_at ON ${activityTable}(created_at DESC)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}activity_log_account_id ON ${activityTable}(account_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}activity_log_action ON ${activityTable}(action)`);\n\n const twoFactorMethodsTable = `${prefix}2fa_methods`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${twoFactorMethodsTable} (\n id SERIAL PRIMARY KEY,\n account_id INTEGER NOT NULL,\n mechanism INTEGER NOT NULL,\n secret VARCHAR(255),\n backup_codes TEXT[],\n verified BOOLEAN DEFAULT FALSE,\n created_at TIMESTAMPTZ DEFAULT NOW(),\n last_used_at TIMESTAMPTZ,\n CONSTRAINT fk_${prefix}2fa_methods_account \n FOREIGN KEY (account_id) REFERENCES ${accountsTable}(id) ON DELETE CASCADE,\n CONSTRAINT ${prefix}unique_account_mechanism \n UNIQUE(account_id, mechanism)\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}2fa_methods_account_id ON ${twoFactorMethodsTable}(account_id)`);\n\n const twoFactorTokensTable = `${prefix}2fa_tokens`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${twoFactorTokensTable} (\n id SERIAL PRIMARY KEY,\n account_id INTEGER NOT NULL,\n mechanism INTEGER NOT NULL,\n selector VARCHAR(32) NOT NULL,\n token_hash VARCHAR(255) NOT NULL,\n expires_at TIMESTAMPTZ NOT NULL,\n created_at TIMESTAMPTZ DEFAULT NOW(),\n CONSTRAINT fk_${prefix}2fa_tokens_account \n FOREIGN KEY (account_id) REFERENCES ${accountsTable}(id) ON DELETE CASCADE\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}2fa_tokens_selector ON ${twoFactorTokensTable}(selector)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}2fa_tokens_account_id ON ${twoFactorTokensTable}(account_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}2fa_tokens_expires ON ${twoFactorTokensTable}(expires_at)`);\n}\n\nexport async function dropAuthTables(config: AuthConfig): Promise<void> {\n const prefix = config.tablePrefix || \"user_\";\n const { db } = config;\n\n await db.query(`DROP TABLE IF EXISTS ${prefix}2fa_tokens CASCADE`);\n await db.query(`DROP TABLE IF EXISTS ${prefix}2fa_methods CASCADE`);\n await db.query(`DROP TABLE IF EXISTS ${prefix}activity_log CASCADE`);\n await db.query(`DROP TABLE IF EXISTS ${prefix}providers CASCADE`);\n await db.query(`DROP TABLE IF EXISTS ${prefix}resets CASCADE`);\n await db.query(`DROP TABLE IF EXISTS ${prefix}remembers CASCADE`);\n await db.query(`DROP TABLE IF EXISTS ${prefix}confirmations CASCADE`);\n await db.query(`DROP TABLE IF EXISTS ${prefix}accounts CASCADE`);\n}\n\nexport async function cleanupExpiredTokens(config: AuthConfig): Promise<void> {\n const prefix = config.tablePrefix || \"user_\";\n const { db } = config;\n\n await db.query(`DELETE FROM ${prefix}confirmations WHERE expires < NOW()`);\n await db.query(`DELETE FROM ${prefix}remembers WHERE expires < NOW()`);\n await db.query(`DELETE FROM ${prefix}resets WHERE expires < NOW()`);\n await db.query(`DELETE FROM ${prefix}2fa_tokens WHERE expires_at < NOW()`);\n}\n\nexport async function getAuthTableStats(config: AuthConfig): Promise<{\n accounts: number;\n providers: number;\n confirmations: number;\n remembers: number;\n resets: number;\n twoFactorMethods: number;\n twoFactorTokens: number;\n expiredConfirmations: number;\n expiredRemembers: number;\n expiredResets: number;\n expiredTwoFactorTokens: number;\n}> {\n const prefix = config.tablePrefix || \"user_\";\n const { db } = config;\n\n const [accountsResult, providersResult, confirmationsResult, remembersResult, resetsResult, twoFactorMethodsResult, twoFactorTokensResult, expiredConfirmationsResult, expiredRemembersResult, expiredResetsResult, expiredTwoFactorTokensResult] =\n await Promise.all([\n db.query(`SELECT COUNT(*) as count FROM ${prefix}accounts`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}providers`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}confirmations`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}remembers`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}resets`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}2fa_methods`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}2fa_tokens`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}confirmations WHERE expires < NOW()`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}remembers WHERE expires < NOW()`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}resets WHERE expires < NOW()`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}2fa_tokens WHERE expires_at < NOW()`),\n ]);\n\n return {\n accounts: parseInt(accountsResult.rows[0]?.count || \"0\"),\n providers: parseInt(providersResult.rows[0]?.count || \"0\"),\n confirmations: parseInt(confirmationsResult.rows[0]?.count || \"0\"),\n remembers: parseInt(remembersResult.rows[0]?.count || \"0\"),\n resets: parseInt(resetsResult.rows[0]?.count || \"0\"),\n twoFactorMethods: parseInt(twoFactorMethodsResult.rows[0]?.count || \"0\"),\n twoFactorTokens: parseInt(twoFactorTokensResult.rows[0]?.count || \"0\"),\n expiredConfirmations: parseInt(expiredConfirmationsResult.rows[0]?.count || \"0\"),\n expiredRemembers: parseInt(expiredRemembersResult.rows[0]?.count || \"0\"),\n expiredResets: parseInt(expiredResetsResult.rows[0]?.count || \"0\"),\n expiredTwoFactorTokens: parseInt(expiredTwoFactorTokensResult.rows[0]?.count || \"0\"),\n };\n}\n","import type { AuthConfig, TokenCallback, AuthAccount } from \"./types.js\";\nimport * as authFunctions from \"./auth-functions.js\";\n\nexport interface AuthContext {\n createUser: (credentials: { email: string; password: string }, userId?: string | number, callback?: TokenCallback) => Promise<AuthAccount>;\n register: (email: string, password: string, userId?: string | number, callback?: TokenCallback) => Promise<AuthAccount>;\n deleteUserBy: (identifier: { accountId?: number; email?: string; userId?: string }) => Promise<void>;\n addRoleForUserBy: (identifier: { accountId?: number; email?: string; userId?: string }, role: number) => Promise<void>;\n removeRoleForUserBy: (identifier: { accountId?: number; email?: string; userId?: string }, role: number) => Promise<void>;\n hasRoleForUserBy: (identifier: { accountId?: number; email?: string; userId?: string }, role: number) => Promise<boolean>;\n changePasswordForUserBy: (identifier: { accountId?: number; email?: string; userId?: string }, password: string) => Promise<void>;\n setStatusForUserBy: (identifier: { accountId?: number; email?: string; userId?: string }, status: number) => Promise<void>;\n initiatePasswordResetForUserBy: (identifier: { accountId?: number; email?: string; userId?: string }, expiresAfter?: string | number | null, callback?: TokenCallback) => Promise<void>;\n resetPassword: (email: string, expiresAfter?: string | number | null, maxOpenRequests?: number | null, callback?: TokenCallback) => Promise<void>;\n confirmResetPassword: (token: string, password: string) => Promise<{ accountId: number; email: string }>;\n userExistsByEmail: (email: string) => Promise<boolean>;\n forceLogoutForUserBy: (identifier: { accountId?: number; email?: string; userId?: string }) => Promise<{ accountId: number }>;\n}\n\nexport function createAuthContext(config: AuthConfig): AuthContext {\n return {\n createUser: (credentials, userId?, callback?) => authFunctions.createUser(config, credentials, userId, callback),\n register: (email, password, userId?, callback?) => authFunctions.register(config, email, password, userId, callback),\n deleteUserBy: (identifier) => authFunctions.deleteUserBy(config, identifier),\n addRoleForUserBy: (identifier, role) => authFunctions.addRoleForUserBy(config, identifier, role),\n removeRoleForUserBy: (identifier, role) => authFunctions.removeRoleForUserBy(config, identifier, role),\n hasRoleForUserBy: (identifier, role) => authFunctions.hasRoleForUserBy(config, identifier, role),\n changePasswordForUserBy: (identifier, password) => authFunctions.changePasswordForUserBy(config, identifier, password),\n setStatusForUserBy: (identifier, status) => authFunctions.setStatusForUserBy(config, identifier, status),\n initiatePasswordResetForUserBy: (identifier, expiresAfter?, callback?) => authFunctions.initiatePasswordResetForUserBy(config, identifier, expiresAfter, callback),\n resetPassword: (email, expiresAfter?, maxOpenRequests?, callback?) => authFunctions.resetPassword(config, email, expiresAfter, maxOpenRequests, callback),\n confirmResetPassword: (token, password) => authFunctions.confirmResetPassword(config, token, password),\n userExistsByEmail: (email) => authFunctions.userExistsByEmail(config, email),\n forceLogoutForUserBy: (identifier) => authFunctions.forceLogoutForUserBy(config, identifier),\n };\n}\n","import type { AuthConfig, AuthAccount } from \"./types.js\";\nimport { AuthQueries } from \"./queries.js\";\nimport { UserNotFoundError } from \"./errors.js\";\n\nexport type UserIdentifier = {\n accountId?: number;\n email?: string;\n userId?: string;\n};\n\nasync function findAccountByIdentifier(queries: AuthQueries, identifier: UserIdentifier): Promise<AuthAccount> {\n let account: AuthAccount | null = null;\n\n if (identifier.accountId !== undefined) {\n account = await queries.findAccountById(identifier.accountId);\n } else if (identifier.email !== undefined) {\n account = await queries.findAccountByEmail(identifier.email);\n } else if (identifier.userId !== undefined) {\n account = await queries.findAccountByUserId(identifier.userId);\n }\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n return account;\n}\n\n/**\n * Add a role to a user's account.\n * Uses bitwise OR to add role to existing rolemask.\n *\n * @param config - Auth configuration containing database connection\n * @param identifier - Find user by accountId, email, or userId\n * @param role - Role bitmask to add (e.g., AuthRole.Admin)\n * @throws {UserNotFoundError} No account matches the identifier\n */\nexport async function addRoleToUser(config: AuthConfig, identifier: UserIdentifier, role: number): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n \n const rolemask = account.rolemask | role;\n await queries.updateAccount(account.id, { rolemask });\n}\n\n/**\n * Remove a role from a user's account.\n * Uses bitwise operations to remove role from rolemask.\n *\n * @param config - Auth configuration containing database connection\n * @param identifier - Find user by accountId, email, or userId\n * @param role - Role bitmask to remove (e.g., AuthRole.Admin)\n * @throws {UserNotFoundError} No account matches the identifier\n */\nexport async function removeRoleFromUser(config: AuthConfig, identifier: UserIdentifier, role: number): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n \n const rolemask = account.rolemask & ~role;\n await queries.updateAccount(account.id, { rolemask });\n}\n\n/**\n * Set a user's complete role mask, replacing any existing roles.\n *\n * @param config - Auth configuration containing database connection\n * @param identifier - Find user by accountId, email, or userId\n * @param rolemask - Complete role bitmask to set\n * @throws {UserNotFoundError} No account matches the identifier\n */\nexport async function setUserRoles(config: AuthConfig, identifier: UserIdentifier, rolemask: number): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n \n await queries.updateAccount(account.id, { rolemask });\n}\n\n/**\n * Get a user's current role mask.\n *\n * @param config - Auth configuration containing database connection\n * @param identifier - Find user by accountId, email, or userId\n * @returns The user's current role bitmask\n * @throws {UserNotFoundError} No account matches the identifier\n */\nexport async function getUserRoles(config: AuthConfig, identifier: UserIdentifier): Promise<number> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n \n return account.rolemask;\n}"],"mappings":"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","names":["import_hash","import_ms","TwoFactorMechanism","Bowser","account","Otp","import_hash","ms","import_hash","import_ms","ms","ms","err","findAccountByIdentifier"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/auth-manager.ts","../src/types.ts","../src/queries.ts","../src/activity-logger.ts","../src/errors.ts","../src/util.ts","../src/providers/base-provider.ts","../src/providers/github-provider.ts","../src/providers/google-provider.ts","../src/providers/azure-provider.ts","../src/two-factor/totp-provider.ts","../src/two-factor/otp-provider.ts","../src/two-factor/two-factor-manager.ts","../src/auth-functions.ts","../src/middleware.ts","../src/schema.ts","../src/auth-context.ts","../src/user-roles.ts"],"sourcesContent":["export { createAuthMiddleware } from \"./middleware.js\";\nexport { createAuthTables, dropAuthTables, cleanupExpiredTokens, getAuthTableStats } from \"./schema.js\";\nexport { createAuthContext, type AuthContext } from \"./auth-context.js\";\nexport * as authFunctions from \"./auth-functions.js\";\nexport * from \"./auth-functions.js\";\nexport { addRoleToUser, removeRoleFromUser, setUserRoles, getUserRoles, type UserIdentifier } from \"./user-roles.js\";\n\nexport type {\n AuthConfig,\n AuthAccount,\n AuthProvider,\n AuthConfirmation,\n AuthRemember,\n AuthReset,\n AuthActivity,\n AuthSession,\n TokenCallback,\n AuthManager,\n OAuthProvider,\n OAuthUserData,\n OAuthCallbackResult,\n OAuthProviderConfig,\n GitHubProviderConfig,\n GoogleProviderConfig,\n AzureProviderConfig,\n AuthActivityActionType,\n TwoFactorMethod,\n TwoFactorToken,\n TwoFactorSetupResult,\n TwoFactorChallenge,\n AuthenticateRequestResult,\n} from \"./types.js\";\n\nexport { AuthStatus, AuthRole, AuthActivityAction, TwoFactorMechanism } from \"./types.js\";\n\nexport {\n AuthError,\n ConfirmationExpiredError,\n ConfirmationNotFoundError,\n EmailNotVerifiedError,\n EmailTakenError,\n InvalidEmailError,\n InvalidPasswordError,\n InvalidTokenError,\n ResetDisabledError,\n ResetExpiredError,\n ResetNotFoundError,\n TooManyResetsError,\n UserInactiveError,\n UserNotFoundError,\n UserNotLoggedInError,\n SecondFactorRequiredError,\n InvalidTwoFactorCodeError,\n TwoFactorExpiredError,\n TwoFactorNotSetupError,\n TwoFactorAlreadyEnabledError,\n InvalidBackupCodeError,\n TwoFactorSetupIncompleteError,\n} from \"./errors.js\";\n\nexport { isValidEmail, validateEmail } from \"./util.js\";\n\nexport { ActivityLogger } from \"./activity-logger.js\";\n\nexport { TwoFactorManager, TotpProvider, OtpProvider } from \"./two-factor/index.js\";\n\nexport { GitHubProvider, GoogleProvider, AzureProvider, BaseOAuthProvider } from \"./providers/index.js\";\n","import { hash } from \"@prsm/hash\";\nimport ms from \"@prsm/ms\";\nimport type { Request, Response } from \"express\";\nimport type { AuthConfig, AuthAccount, AuthSession, TokenCallback, AuthManager as IAuthManager, OAuthProvider } from \"./types.js\";\nimport { AuthStatus, AuthRole, AuthActivityAction } from \"./types.js\";\nimport { AuthQueries } from \"./queries.js\";\nimport { ActivityLogger } from \"./activity-logger.js\";\nimport { validateEmail, createMapFromEnum } from \"./util.js\";\nimport {\n ConfirmationExpiredError,\n ConfirmationNotFoundError,\n EmailNotVerifiedError,\n EmailTakenError,\n InvalidPasswordError,\n InvalidTokenError,\n ResetDisabledError,\n ResetExpiredError,\n ResetNotFoundError,\n TooManyResetsError,\n UserInactiveError,\n UserNotFoundError,\n UserNotLoggedInError,\n SecondFactorRequiredError,\n TwoFactorExpiredError,\n} from \"./errors.js\";\nimport { GitHubProvider, GoogleProvider, AzureProvider } from \"./providers/index.js\";\nimport { TwoFactorManager } from \"./two-factor/index.js\";\nimport * as authFunctions from \"./auth-functions.js\";\n\nexport class AuthManager implements IAuthManager {\n private req: Request;\n private res: Response;\n private config: AuthConfig;\n private queries: AuthQueries;\n private activityLogger: ActivityLogger;\n public providers: {\n github?: OAuthProvider;\n google?: OAuthProvider;\n azure?: OAuthProvider;\n };\n\n public twoFactor: TwoFactorManager;\n\n constructor(req: Request, res: Response, config: AuthConfig) {\n this.req = req;\n this.res = res;\n this.config = config;\n this.queries = new AuthQueries(config);\n this.activityLogger = new ActivityLogger(config);\n this.providers = this.initializeProviders();\n this.twoFactor = new TwoFactorManager(req, res, config);\n }\n\n private initializeProviders(): {\n github?: OAuthProvider;\n google?: OAuthProvider;\n azure?: OAuthProvider;\n } {\n const providers: any = {};\n\n if (this.config.providers?.github) {\n providers.github = new GitHubProvider(this.config.providers.github, this.config, this);\n }\n\n if (this.config.providers?.google) {\n providers.google = new GoogleProvider(this.config.providers.google, this.config, this);\n }\n\n if (this.config.providers?.azure) {\n providers.azure = new AzureProvider(this.config.providers.azure, this.config, this);\n }\n\n return providers;\n }\n\n private generateAutoUserId(): string {\n // Generate a UUID for auto users\n return crypto.randomUUID();\n }\n\n private async shouldRequire2FA(account: AuthAccount): Promise<boolean> {\n // skip 2FA for OAuth users unless explicitly configured\n const providers = await this.queries.findProvidersByAccountId(account.id);\n const hasOAuthProviders = providers.length > 0;\n\n if (hasOAuthProviders && !this.config.twoFactor?.requireForOAuth) {\n return false;\n }\n return true;\n }\n\n private validatePassword(password: string): void {\n const minLength = this.config.minPasswordLength || 8;\n const maxLength = this.config.maxPasswordLength || 64;\n\n if (typeof password !== \"string\") {\n throw new InvalidPasswordError();\n }\n\n if (password.length < minLength) {\n throw new InvalidPasswordError();\n }\n\n if (password.length > maxLength) {\n throw new InvalidPasswordError();\n }\n }\n\n private getRoleMap(): Record<number, string> {\n return createMapFromEnum(AuthRole);\n }\n\n private getStatusMap(): Record<number, string> {\n return createMapFromEnum(AuthStatus);\n }\n\n private async getAuthAccount(): Promise<AuthAccount | null> {\n if (!this.req.session?.auth?.accountId) {\n return null;\n }\n\n return await this.queries.findAccountById(this.req.session.auth.accountId);\n }\n\n private setRememberCookie(token: string | null, expires: Date): void {\n const cookieName = this.config.rememberCookieName || \"remember_token\";\n const cookieConfig = this.config.cookie || {};\n\n if (token === null) {\n this.res.clearCookie(cookieName, {\n domain: cookieConfig.domain,\n secure: cookieConfig.secure ?? this.req.secure,\n sameSite: cookieConfig.sameSite,\n });\n } else {\n this.res.cookie(cookieName, token, {\n expires,\n httpOnly: true,\n secure: cookieConfig.secure ?? this.req.secure,\n domain: cookieConfig.domain,\n sameSite: cookieConfig.sameSite,\n });\n }\n }\n\n private getRememberToken(): { token: string | null } {\n const { cookies } = this.req as any;\n if (!cookies) {\n return { token: null };\n }\n\n const cookieName = this.config.rememberCookieName || \"remember_token\";\n const token = cookies[cookieName];\n\n return { token: token || null };\n }\n\n private async regenerateSession(): Promise<void> {\n const { auth } = this.req.session;\n\n return new Promise<void>((resolve, reject) => {\n this.req.session.regenerate((err: any) => {\n if (err) {\n reject(err);\n return;\n }\n this.req.session.auth = auth;\n resolve();\n });\n });\n }\n\n async resyncSession(force = false): Promise<void> {\n if (!this.isLoggedIn()) {\n return;\n }\n\n if (this.req.session.auth!.shouldForceLogout) {\n await this.logout();\n return;\n }\n\n const interval = ms(this.config.resyncInterval || \"30s\");\n const lastResync = new Date(this.req.session.auth!.lastResync);\n\n if (!force && lastResync && lastResync.getTime() > Date.now() - interval) {\n return;\n }\n\n const account = await this.getAuthAccount();\n\n if (!account) {\n await this.logout();\n return;\n }\n\n if (account.force_logout > this.req.session.auth!.forceLogout) {\n await this.logout();\n return;\n }\n\n this.req.session.auth!.shouldForceLogout = false;\n this.req.session.auth!.email = account.email;\n this.req.session.auth!.status = account.status;\n this.req.session.auth!.rolemask = account.rolemask;\n this.req.session.auth!.verified = account.verified;\n this.req.session.auth!.hasPassword = account.password !== null;\n this.req.session.auth!.lastResync = new Date();\n }\n\n async processRememberDirective(): Promise<void> {\n if (this.isLoggedIn()) {\n return;\n }\n\n const { token } = this.getRememberToken();\n if (!token) {\n return;\n }\n\n const remember = await this.queries.findRememberToken(token);\n if (!remember) {\n this.setRememberCookie(null, new Date(0));\n return;\n }\n\n // expired?\n if (new Date() > remember.expires) {\n await this.queries.deleteRememberToken(token);\n this.setRememberCookie(null, new Date(0));\n return;\n }\n\n // clean up expired tokens for this account\n await this.queries.deleteExpiredRememberTokensForAccount(remember.account_id);\n\n // get the account and log in\n const account = await this.queries.findAccountById(remember.account_id);\n if (!account) {\n await this.queries.deleteRememberToken(token);\n this.setRememberCookie(null, new Date(0));\n return;\n }\n\n // pass false to avoid creating a new remember token - we're restoring from an existing one\n await this.onLoginSuccessful(account, false);\n }\n\n private async onLoginSuccessful(account: AuthAccount, remember = false): Promise<void> {\n await this.queries.updateAccountLastLogin(account.id);\n\n return new Promise<void>((resolve, reject) => {\n if (!this.req.session?.regenerate) {\n resolve();\n return;\n }\n\n this.req.session.regenerate(async (err: any) => {\n if (err) {\n reject(err);\n return;\n }\n\n const session: AuthSession = {\n loggedIn: true,\n accountId: account.id,\n userId: account.user_id,\n email: account.email,\n status: account.status,\n rolemask: account.rolemask,\n remembered: remember,\n lastResync: new Date(),\n lastRememberCheck: new Date(),\n forceLogout: account.force_logout,\n verified: account.verified,\n hasPassword: account.password !== null,\n shouldForceLogout: false,\n };\n\n this.req.session.auth = session;\n\n if (remember) {\n await this.createRememberDirective(account);\n }\n\n this.req.session.save((err: any) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n });\n }\n\n private async createRememberDirective(account: AuthAccount): Promise<string> {\n const token = hash.encode(account.email);\n const duration = this.config.rememberDuration || \"30d\";\n const expires = new Date(Date.now() + ms(duration));\n\n await this.queries.createRememberToken({\n accountId: account.id,\n token,\n expires,\n });\n\n this.setRememberCookie(token, expires);\n\n await this.activityLogger.logActivity(account.id, AuthActivityAction.RememberTokenCreated, this.req, true, { email: account.email, duration });\n\n return token;\n }\n\n /**\n * Check if the current user is logged in.\n * @returns true if user has an active authenticated session\n */\n isLoggedIn(): boolean {\n return this.req.session?.auth?.loggedIn ?? false;\n }\n\n /**\n * Authenticate user with email and password.\n * Creates a new session and optionally sets a remember token for persistent login.\n *\n * @param email - User's email address\n * @param password - Plain text password\n * @param remember - If true, sets a persistent cookie for auto-login on future visits\n * @throws {UserNotFoundError} Account with this email doesn't exist\n * @throws {InvalidPasswordError} Password is incorrect\n * @throws {EmailNotVerifiedError} Account exists but email is not verified\n * @throws {UserInactiveError} Account is banned, locked, or otherwise inactive\n */\n async login(email: string, password: string, remember = false): Promise<void> {\n try {\n const account = await this.queries.findAccountByEmail(email);\n\n if (!account) {\n await this.activityLogger.logActivity(null, AuthActivityAction.FailedLogin, this.req, false, { email, reason: \"account_not_found\" });\n throw new UserNotFoundError();\n }\n\n if (!account.password || !hash.verify(account.password, password)) {\n await this.activityLogger.logActivity(account.id, AuthActivityAction.FailedLogin, this.req, false, { email, reason: \"invalid_password\" });\n throw new InvalidPasswordError();\n }\n\n if (!account.verified) {\n await this.activityLogger.logActivity(account.id, AuthActivityAction.FailedLogin, this.req, false, { email, reason: \"email_not_verified\" });\n throw new EmailNotVerifiedError();\n }\n\n if (account.status !== AuthStatus.Normal) {\n await this.activityLogger.logActivity(account.id, AuthActivityAction.FailedLogin, this.req, false, { email, reason: \"account_inactive\", status: account.status });\n throw new UserInactiveError();\n }\n\n // check if 2FA is enabled and required for this user\n if (this.config.twoFactor?.enabled && (await this.shouldRequire2FA(account))) {\n const twoFactorMethods = await this.queries.findTwoFactorMethodsByAccountId(account.id);\n const enabledMethods = twoFactorMethods.filter((method) => method.verified);\n\n if (enabledMethods.length > 0) {\n // create 2FA challenge\n const challenge = await this.twoFactor.createChallenge(account.id);\n\n // set 2FA session state (user NOT logged in yet)\n const expiryDuration = this.config.twoFactor?.tokenExpiry || \"5m\";\n const expiresAt = new Date(Date.now() + ms(expiryDuration));\n\n this.req.session.auth = {\n loggedIn: false,\n accountId: 0,\n userId: \"\",\n email: \"\",\n status: 0,\n rolemask: 0,\n remembered: false,\n lastResync: new Date(),\n lastRememberCheck: new Date(),\n forceLogout: 0,\n verified: false,\n hasPassword: false,\n awaitingTwoFactor: {\n accountId: account.id,\n expiresAt,\n remember,\n availableMechanisms: enabledMethods.map((m) => m.mechanism),\n attemptedMechanisms: [],\n originalEmail: account.email,\n selectors: challenge.selectors,\n },\n };\n\n await this.activityLogger.logActivity(account.id, AuthActivityAction.TwoFactorFailed, this.req, true, { prompt: true, mechanisms: enabledMethods.map((m) => m.mechanism) });\n\n throw new SecondFactorRequiredError(challenge);\n }\n }\n\n await this.onLoginSuccessful(account, remember);\n await this.activityLogger.logActivity(account.id, AuthActivityAction.Login, this.req, true, { email, remember });\n } catch (error) {\n // re-throw the error after logging\n throw error;\n }\n }\n\n /**\n * Complete two-factor authentication and log in the user.\n * This should be called after receiving a SecondFactorRequiredError.\n */\n async completeTwoFactorLogin(): Promise<void> {\n const twoFactorState = this.req.session?.auth?.awaitingTwoFactor;\n\n if (!twoFactorState) {\n throw new TwoFactorExpiredError();\n }\n\n // check if the 2FA session has expired\n if (twoFactorState.expiresAt <= new Date()) {\n // clear expired 2FA state\n delete this.req.session.auth!.awaitingTwoFactor;\n throw new TwoFactorExpiredError();\n }\n\n // get the account that was awaiting 2FA\n const account = await this.queries.findAccountById(twoFactorState.accountId);\n if (!account) {\n delete this.req.session.auth!.awaitingTwoFactor;\n throw new UserNotFoundError();\n }\n\n // complete the login process\n await this.onLoginSuccessful(account, twoFactorState.remember);\n\n // clear the 2FA state\n delete this.req.session.auth!.awaitingTwoFactor;\n\n await this.activityLogger.logActivity(account.id, AuthActivityAction.Login, this.req, true, { email: account.email, remember: twoFactorState.remember, twoFactorCompleted: true });\n }\n\n /**\n * Log out the current user.\n * Clears the session and removes any remember tokens.\n */\n async logout(): Promise<void> {\n if (!this.isLoggedIn()) {\n return;\n }\n\n const accountId = this.getId();\n const email = this.getEmail();\n const { token } = this.getRememberToken();\n\n if (token) {\n await this.queries.deleteRememberToken(token);\n this.setRememberCookie(null, new Date(0));\n }\n\n this.req.session.auth = undefined;\n\n if (accountId && email) {\n await this.activityLogger.logActivity(accountId, AuthActivityAction.Logout, this.req, true, { email });\n }\n }\n\n /**\n * Register a new account.\n *\n * @param email - Email address for the new account\n * @param password - Plain text password (will be hashed)\n * @param userId - Optional user ID to link this auth account to. If not provided, a UUID will be generated automatically.\n * @param callback - If provided, account is created unverified and callback receives confirmation token. Create a URL like /confirm/{token} and call confirmEmail() in that handler. If omitted, account is immediately verified.\n * @returns The created account record\n * @throws {EmailTakenError} Email is already registered\n * @throws {InvalidPasswordError} Password doesn't meet length requirements\n */\n async register(email: string, password: string, userId?: string | number, callback?: TokenCallback): Promise<AuthAccount> {\n validateEmail(email);\n this.validatePassword(password);\n\n const existing = await this.queries.findAccountByEmail(email);\n if (existing) {\n throw new EmailTakenError();\n }\n\n const finalUserId = userId || this.generateAutoUserId();\n\n const hashedPassword = hash.encode(password);\n const verified = typeof callback !== \"function\";\n\n const account = await this.queries.createAccount({\n userId: finalUserId,\n email,\n password: hashedPassword,\n verified,\n status: AuthStatus.Normal,\n rolemask: 0,\n });\n\n if (!verified && callback) {\n await this.createConfirmationToken(account, email, callback);\n }\n\n await this.activityLogger.logActivity(account.id, AuthActivityAction.Register, this.req, true, { email, verified, userId: finalUserId });\n\n return account;\n }\n\n private async createConfirmationToken(account: AuthAccount, email: string, callback: TokenCallback): Promise<void> {\n const token = hash.encode(email);\n const expires = new Date(Date.now() + 1000 * 60 * 60 * 24 * 7); // 1 week\n\n await this.queries.createConfirmation({\n accountId: account.id,\n token,\n email,\n expires,\n });\n\n if (callback) {\n callback(token);\n }\n }\n\n /**\n * Get the current user's account ID.\n * @returns Account ID if logged in, null otherwise\n */\n getId(): number | null {\n return this.req.session?.auth?.accountId || null;\n }\n\n /**\n * Get the current user's email address.\n * @returns Email if logged in, null otherwise\n */\n getEmail(): string | null {\n return this.req.session?.auth?.email || null;\n }\n\n /**\n * Get the current user's account status.\n * @returns Status number (0=Normal, 1=Archived, 2=Banned, etc.) if logged in, null otherwise\n */\n getStatus(): number | null {\n return this.req.session?.auth?.status ?? null;\n }\n\n /**\n * Check if the current user's email is verified.\n * @returns true if verified, false if unverified, null if not logged in\n */\n getVerified(): boolean | null {\n return this.req.session?.auth?.verified ?? null;\n }\n\n /**\n * Check if the current user has a password set.\n * OAuth-only users will return false.\n * @returns true if user has a password, false if OAuth-only, null if not logged in\n */\n hasPassword(): boolean | null {\n return this.req.session?.auth?.hasPassword ?? null;\n }\n\n /**\n * Get human-readable role names for the current user or a specific rolemask.\n * @param rolemask - Optional specific rolemask to check. If omitted, uses current user's roles\n * @returns Array of role names (e.g., ['Admin', 'Editor'])\n */\n getRoleNames(rolemask?: number): string[] {\n const mask = rolemask !== undefined ? rolemask : (this.req.session?.auth?.rolemask ?? 0);\n\n if (!mask && mask !== 0) {\n return [];\n }\n\n return Object.entries(this.getRoleMap())\n .filter(([key]) => mask & parseInt(key))\n .map(([, value]) => value);\n }\n\n /**\n * Get human-readable status name for the current user.\n * @returns Status name (e.g., 'Normal', 'Banned', 'Locked') if logged in, null otherwise\n */\n getStatusName(): string | null {\n const status = this.getStatus();\n if (status === null) return null;\n return this.getStatusMap()[status] || null;\n }\n\n /**\n * Check if the current user has a specific role.\n * @param role - Role bitmask to check (e.g., AuthRole.Admin)\n * @returns true if user has the role, false otherwise\n */\n async hasRole(role: number): Promise<boolean> {\n if (this.req.session?.auth) {\n return (this.req.session.auth.rolemask & role) === role;\n }\n\n const account = await this.getAuthAccount();\n return account ? (account.rolemask & role) === role : false;\n }\n\n /**\n * Check if the current user has admin privileges.\n * @returns true if user has Admin role, false otherwise\n */\n async isAdmin(): Promise<boolean> {\n return this.hasRole(AuthRole.Admin);\n }\n\n /**\n * Check if the current user was automatically logged in via remember token.\n * @returns true if auto-logged in from persistent cookie, false if manual login or not logged in\n */\n isRemembered(): boolean {\n return this.req.session?.auth?.remembered ?? false;\n }\n\n /**\n * Request an email change for the current user.\n * Sends a confirmation token to verify the new email before changing it.\n *\n * @param newEmail - New email address\n * @param callback - Called with confirmation token. Create a URL like /confirm/{token} and call confirmEmail() in that handler\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {EmailTakenError} New email is already registered\n * @throws {UserNotFoundError} Current user account not found\n * @throws {EmailNotVerifiedError} Current account's email is not verified\n */\n async changeEmail(newEmail: string, callback: TokenCallback): Promise<void> {\n if (!this.isLoggedIn()) {\n throw new UserNotLoggedInError();\n }\n\n validateEmail(newEmail);\n\n const existing = await this.queries.findAccountByEmail(newEmail);\n if (existing) {\n throw new EmailTakenError();\n }\n\n const account = await this.getAuthAccount();\n if (!account) {\n throw new UserNotFoundError();\n }\n\n if (!account.verified) {\n throw new EmailNotVerifiedError();\n }\n\n await this.createConfirmationToken(account, newEmail, callback);\n }\n\n /**\n * Confirm an email address using a token from registration or email change.\n * Updates the account to verified status and changes email if this was from changeEmail.\n *\n * @param token - Confirmation token from registration or email change\n * @returns The confirmed email address\n * @throws {ConfirmationNotFoundError} Token is invalid or doesn't exist\n * @throws {ConfirmationExpiredError} Token has expired\n * @throws {InvalidTokenError} Token format is invalid\n */\n async confirmEmail(token: string): Promise<string> {\n const confirmation = await this.queries.findConfirmation(token);\n\n if (!confirmation) {\n throw new ConfirmationNotFoundError();\n }\n\n if (new Date(confirmation.expires) < new Date()) {\n throw new ConfirmationExpiredError();\n }\n\n if (!hash.verify(token, confirmation.email)) {\n throw new InvalidTokenError();\n }\n\n await this.queries.updateAccount(confirmation.account_id, {\n verified: true,\n email: confirmation.email,\n });\n\n if (this.isLoggedIn() && this.req.session?.auth?.accountId === confirmation.account_id) {\n this.req.session.auth.verified = true;\n this.req.session.auth.email = confirmation.email;\n }\n\n await this.queries.deleteConfirmation(token);\n\n await this.activityLogger.logActivity(confirmation.account_id, AuthActivityAction.EmailConfirmed, this.req, true, { email: confirmation.email });\n\n return confirmation.email;\n }\n\n /**\n * Confirm email and automatically log in the user.\n * Useful for \"click to verify and login\" flows.\n *\n * @param token - Confirmation token from registration\n * @param remember - Whether to set persistent login cookie\n * @throws {ConfirmationNotFoundError} Token is invalid or doesn't exist\n * @throws {ConfirmationExpiredError} Token has expired\n * @throws {InvalidTokenError} Token format is invalid\n * @throws {UserNotFoundError} Associated account no longer exists\n */\n async confirmEmailAndLogin(token: string, remember = false): Promise<void> {\n const email = await this.confirmEmail(token);\n\n if (this.isLoggedIn()) {\n return;\n }\n\n const account = await this.queries.findAccountByEmail(email);\n if (!account) {\n throw new UserNotFoundError();\n }\n\n // check if 2FA is enabled and required for this user\n if (this.config.twoFactor?.enabled && (await this.shouldRequire2FA(account))) {\n const twoFactorMethods = await this.queries.findTwoFactorMethodsByAccountId(account.id);\n const enabledMethods = twoFactorMethods.filter((method) => method.verified);\n\n if (enabledMethods.length > 0) {\n // create 2FA challenge\n const challenge = await this.twoFactor.createChallenge(account.id);\n\n // set 2FA session state (user NOT logged in yet)\n const expiryDuration = this.config.twoFactor?.tokenExpiry || \"5m\";\n const expiresAt = new Date(Date.now() + ms(expiryDuration));\n\n this.req.session.auth = {\n loggedIn: false,\n accountId: 0,\n userId: \"\",\n email: \"\",\n status: 0,\n rolemask: 0,\n remembered: false,\n lastResync: new Date(),\n lastRememberCheck: new Date(),\n forceLogout: 0,\n verified: false,\n hasPassword: false,\n awaitingTwoFactor: {\n accountId: account.id,\n expiresAt,\n remember,\n availableMechanisms: enabledMethods.map((m) => m.mechanism),\n attemptedMechanisms: [],\n originalEmail: account.email,\n selectors: challenge.selectors,\n },\n };\n\n await this.activityLogger.logActivity(account.id, AuthActivityAction.TwoFactorFailed, this.req, true, { prompt: true, mechanisms: enabledMethods.map((m) => m.mechanism) });\n\n throw new SecondFactorRequiredError(challenge);\n }\n }\n\n await this.onLoginSuccessful(account, remember);\n }\n\n /**\n * Initiate a password reset for a user.\n * Creates a reset token and calls the callback to send reset email.\n *\n * @param email - Email address of account to reset\n * @param expiresAfter - Token expiration (default: 6h). Accepts ms format like '1h', '30m'\n * @param maxOpenRequests - Maximum concurrent reset tokens (default: 2)\n * @param callback - Called with reset token. Create a URL like /reset/{token} and call confirmResetPassword() in that handler\n * @throws {EmailNotVerifiedError} Account doesn't exist or email not verified\n * @throws {ResetDisabledError} Account has password reset disabled\n * @throws {TooManyResetsError} Too many active reset requests\n */\n async resetPassword(email: string, expiresAfter: string | number | null = null, maxOpenRequests: number | null = null, callback?: TokenCallback): Promise<void> {\n validateEmail(email);\n\n const expiry = !expiresAfter ? ms(\"6h\") : ms(expiresAfter);\n const maxRequests = maxOpenRequests === null ? 2 : Math.max(1, maxOpenRequests);\n\n const account = await this.queries.findAccountByEmail(email);\n\n if (!account || !account.verified) {\n throw new EmailNotVerifiedError();\n }\n\n if (!account.resettable) {\n throw new ResetDisabledError();\n }\n\n const openRequests = await this.queries.countActiveResetTokensForAccount(account.id);\n\n if (openRequests >= maxRequests) {\n throw new TooManyResetsError();\n }\n\n const token = hash.encode(email);\n const expires = new Date(Date.now() + expiry);\n\n await this.queries.createResetToken({\n accountId: account.id,\n token,\n expires,\n });\n\n await this.activityLogger.logActivity(account.id, AuthActivityAction.PasswordResetRequested, this.req, true, { email });\n\n if (callback) {\n callback(token);\n }\n }\n\n /**\n * Complete a password reset using a reset token.\n * Changes the password and optionally logs out all sessions.\n *\n * @param token - Reset token from resetPassword callback\n * @param password - New password (will be hashed)\n * @param logout - Whether to force logout all sessions (default: true)\n * @throws {ResetNotFoundError} Token is invalid or doesn't exist\n * @throws {ResetExpiredError} Token has expired\n * @throws {UserNotFoundError} Associated account no longer exists\n * @throws {ResetDisabledError} Account has password reset disabled\n * @throws {InvalidPasswordError} New password doesn't meet requirements\n * @throws {InvalidTokenError} Token format is invalid\n */\n async confirmResetPassword(token: string, password: string, logout = true): Promise<void> {\n const reset = await this.queries.findResetToken(token);\n\n if (!reset) {\n throw new ResetNotFoundError();\n }\n\n if (new Date(reset.expires) < new Date()) {\n throw new ResetExpiredError();\n }\n\n const account = await this.queries.findAccountById(reset.account_id);\n if (!account) {\n throw new UserNotFoundError();\n }\n\n if (!account.resettable) {\n throw new ResetDisabledError();\n }\n\n this.validatePassword(password);\n\n if (!hash.verify(token, account.email)) {\n throw new InvalidTokenError();\n }\n\n await this.queries.updateAccount(account.id, {\n password: hash.encode(password),\n });\n\n if (logout) {\n await this.forceLogoutForAccountById(account.id);\n }\n\n await this.queries.deleteResetToken(token);\n\n await this.activityLogger.logActivity(account.id, AuthActivityAction.PasswordResetCompleted, this.req, true, { email: account.email });\n }\n\n /**\n * Verify if a password matches the current user's password.\n * Useful for \"confirm current password\" flows before sensitive operations.\n *\n * @param password - Password to verify\n * @returns true if password matches, false otherwise\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {UserNotFoundError} Current user account not found\n */\n async verifyPassword(password: string): Promise<boolean> {\n if (!this.isLoggedIn()) {\n throw new UserNotLoggedInError();\n }\n\n const account = await this.getAuthAccount();\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n if (!account.password) {\n return false; // OAuth users don't have passwords\n }\n\n return hash.verify(account.password, password);\n }\n\n private async forceLogoutForAccountById(accountId: number): Promise<void> {\n await this.queries.deleteRememberTokensForAccount(accountId);\n await this.queries.incrementForceLogout(accountId);\n }\n\n /**\n * Force logout all OTHER sessions while keeping current session active.\n * Useful for \"logout other devices\" functionality.\n */\n async logoutEverywhereElse(): Promise<void> {\n if (!this.isLoggedIn()) {\n return;\n }\n\n const accountId = this.getId();\n if (!accountId) {\n return;\n }\n\n const account = await this.queries.findAccountById(accountId);\n if (!account) {\n await this.logout();\n return;\n }\n\n await this.forceLogoutForAccountById(accountId);\n\n this.req.session.auth!.forceLogout += 1;\n\n await this.regenerateSession();\n }\n\n /**\n * Force logout ALL sessions including the current one.\n * Logs out everywhere else, then logs out current session.\n */\n async logoutEverywhere(): Promise<void> {\n if (!this.isLoggedIn()) {\n return;\n }\n\n await this.logoutEverywhereElse();\n await this.logout();\n }\n\n private async findAccountByIdentifier(identifier: { accountId?: number; email?: string; userId?: string }): Promise<AuthAccount | null> {\n if (identifier.accountId !== undefined) {\n return await this.queries.findAccountById(identifier.accountId);\n } else if (identifier.email !== undefined) {\n return await this.queries.findAccountByEmail(identifier.email);\n } else if (identifier.userId !== undefined) {\n return await this.queries.findAccountByUserId(identifier.userId);\n }\n\n return null;\n }\n\n // admin/standalone functions (delegated to auth-functions.js due to lack of need for request context)\n async createUser(credentials: { email: string; password: string }, userId?: string | number, callback?: TokenCallback): Promise<AuthAccount> {\n return authFunctions.createUser(this.config, credentials, userId, callback);\n }\n\n async deleteUserBy(identifier: { accountId?: number; email?: string; userId?: string }): Promise<void> {\n return authFunctions.deleteUserBy(this.config, identifier);\n }\n\n async addRoleForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<void> {\n return authFunctions.addRoleForUserBy(this.config, identifier, role);\n }\n\n async removeRoleForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<void> {\n return authFunctions.removeRoleForUserBy(this.config, identifier, role);\n }\n\n async hasRoleForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<boolean> {\n return authFunctions.hasRoleForUserBy(this.config, identifier, role);\n }\n\n async changePasswordForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, password: string): Promise<void> {\n return authFunctions.changePasswordForUserBy(this.config, identifier, password);\n }\n\n async setStatusForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, status: number): Promise<void> {\n return authFunctions.setStatusForUserBy(this.config, identifier, status);\n }\n\n async initiatePasswordResetForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, expiresAfter?: string | number | null, callback?: TokenCallback): Promise<void> {\n return authFunctions.initiatePasswordResetForUserBy(this.config, identifier, expiresAfter, callback);\n }\n\n async userExistsByEmail(email: string): Promise<boolean> {\n return authFunctions.userExistsByEmail(this.config, email);\n }\n\n async forceLogoutForUserBy(identifier: { accountId?: number; email?: string; userId?: string }): Promise<void> {\n const result = await authFunctions.forceLogoutForUserBy(this.config, identifier);\n\n if (this.getId() === result.accountId) {\n this.req.session.auth!.shouldForceLogout = true;\n }\n }\n\n /**\n * Log in as another user (admin function).\n * Creates a new session as the target user without requiring their password.\n *\n * @param identifier - Find user by accountId, email, or userId\n * @throws {UserNotFoundError} No account matches the identifier\n */\n async loginAsUserBy(identifier: { accountId?: number; email?: string; userId?: string }): Promise<void> {\n const account = await this.findAccountByIdentifier(identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n await this.onLoginSuccessful(account, false);\n }\n}\n","import type { Request, Response } from \"express\";\nimport type { Pool } from \"pg\";\nimport \"express-session\";\n\nexport interface OAuthProviderConfig {\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n}\n\nexport interface GitHubProviderConfig extends OAuthProviderConfig {}\n\nexport interface GoogleProviderConfig extends OAuthProviderConfig {}\n\nexport interface AzureProviderConfig extends OAuthProviderConfig {\n tenantId: string;\n}\n\nexport interface AuthConfig {\n db: Pool;\n\n /**\n * If a user logs in with an OAuth provider, but a matching account (identified by the OAuth user's email address) doesn't\n * exist, createUser will be called:\n *\n * @example:\n *\n * if (this.authConfig.createUser) {\n * userId = await this.authConfig.createUser(userData);\n * } else {\n * // Generate UUID for OAuth users when no createUser function is provided\n * userId = crypto.randomUUID();\n * }\n *\n * This callback is your opportunity to create a user account in *your* database, and return\n * the user ID of the newly-created user for this provider account to be linked to.\n * @param userData\n * @returns\n */\n createUser?: (userData: OAuthUserData) => string | number | Promise<string | number>;\n\n tablePrefix?: string; // defaults to 'user_'\n\n minPasswordLength?: number; // defaults to 8\n maxPasswordLength?: number; // defaults to 64\n\n rememberDuration?: string; // defaults to \"30d\"\n rememberCookieName?: string; // defaults to \"remember_token\"\n\n cookie?: {\n domain?: string;\n secure?: boolean;\n sameSite?: \"strict\" | \"lax\" | \"none\";\n };\n\n resyncInterval?: string; // defaults to \"30s\"\n\n activityLog?: {\n enabled?: boolean; // defaults to true\n maxEntries?: number; // defaults to 10000\n actions?: AuthActivityActionType[]; // which actions to log, defaults to all\n };\n\n providers?: {\n github?: GitHubProviderConfig;\n google?: GoogleProviderConfig;\n azure?: AzureProviderConfig;\n };\n\n githubUserAgent?: string;\n\n twoFactor?: {\n enabled?: boolean; // defaults to false\n requireForOAuth?: boolean; // defaults to false\n issuer?: string; // for TOTP QR codes, defaults to \"EasyAccess\"\n codeLength?: number; // defaults to 6\n tokenExpiry?: string; // defaults to \"5m\"\n totpWindow?: number; // defaults to 1\n backupCodesCount?: number; // defaults to 10\n };\n}\n\nexport interface AuthAccount {\n id: number;\n user_id: string;\n email: string;\n password: string | null;\n verified: boolean;\n status: number;\n rolemask: number;\n last_login: Date | null;\n force_logout: number;\n resettable: boolean;\n registered: Date;\n}\n\nexport interface AuthProvider {\n id: number;\n account_id: number;\n provider: string;\n provider_id: string;\n provider_email: string | null;\n provider_username: string | null;\n provider_name: string | null;\n provider_avatar: string | null;\n created_at: Date;\n updated_at: Date;\n}\n\nexport interface OAuthUserData {\n id: string;\n email: string;\n username?: string;\n name?: string;\n avatar?: string;\n}\n\nexport interface OAuthCallbackResult {\n isNewUser: boolean;\n}\n\nexport interface OAuthProvider {\n getAuthUrl(state?: string, scopes?: string[]): string;\n handleCallback(req: Request): Promise<OAuthCallbackResult>;\n getUserData(req: Request): Promise<OAuthUserData>;\n}\n\nexport interface AuthConfirmation {\n id: number;\n account_id: number;\n token: string;\n email: string;\n expires: Date;\n}\n\nexport interface AuthRemember {\n id: number;\n account_id: number;\n token: string;\n expires: Date;\n}\n\nexport interface AuthenticateRequestResult {\n account: AuthAccount | null;\n source: \"session\" | \"remember\" | null;\n}\n\nexport interface AuthReset {\n id: number;\n account_id: number;\n token: string;\n expires: Date;\n}\n\nexport interface AuthActivity {\n id: number;\n account_id: number | null;\n action: string;\n ip_address: string | null;\n user_agent: string | null;\n browser: string | null;\n os: string | null;\n device: string | null;\n success: boolean;\n metadata: Record<string, any> | null;\n created_at: Date;\n}\n\nexport interface AuthSession {\n loggedIn: boolean;\n accountId: number;\n userId: string;\n email: string;\n status: number;\n rolemask: number;\n remembered: boolean;\n lastResync: Date;\n lastRememberCheck: Date;\n forceLogout: number;\n verified: boolean;\n hasPassword: boolean;\n shouldForceLogout?: boolean;\n awaitingTwoFactor?: {\n accountId: number;\n expiresAt: Date;\n remember: boolean;\n availableMechanisms: TwoFactorMechanism[];\n attemptedMechanisms: TwoFactorMechanism[];\n originalEmail: string;\n selectors?: {\n email?: string;\n sms?: string;\n };\n };\n}\n\nexport enum TwoFactorMechanism {\n TOTP = 1,\n EMAIL = 2,\n SMS = 3,\n}\n\nexport interface TwoFactorMethod {\n id: number;\n account_id: number;\n mechanism: TwoFactorMechanism;\n secret: string | null;\n backup_codes: string[] | null;\n verified: boolean;\n created_at: Date;\n last_used_at: Date | null;\n}\n\nexport interface TwoFactorToken {\n id: number;\n account_id: number;\n mechanism: TwoFactorMechanism;\n selector: string;\n token_hash: string;\n expires_at: Date;\n created_at: Date;\n}\n\nexport interface TwoFactorSetupResult {\n secret: string;\n qrCode: string;\n backupCodes?: string[];\n}\n\nexport interface TwoFactorChallenge {\n totp?: boolean;\n email?: {\n otpValue: string;\n maskedContact: string;\n };\n sms?: {\n otpValue: string;\n maskedContact: string;\n };\n selectors?: {\n email?: string;\n sms?: string;\n };\n}\n\nexport const AuthStatus = {\n Normal: 0,\n Archived: 1,\n Banned: 2,\n Locked: 3,\n PendingReview: 4,\n Suspended: 5,\n} as const;\n\nexport const AuthRole = {\n Admin: 1,\n Author: 2,\n Collaborator: 4,\n Consultant: 8,\n Consumer: 16,\n Contributor: 32,\n Owner: 64,\n Creator: 128,\n Developer: 256,\n Director: 512,\n Editor: 1024,\n Employee: 2048,\n Member: 4096,\n Manager: 8192,\n Moderator: 16384,\n Publisher: 32768,\n Reviewer: 65536,\n Subscriber: 131072,\n SuperAdmin: 262144,\n SuperEditor: 524288,\n SuperModerator: 1048576,\n Translator: 2097152,\n} as const;\n\nexport const AuthActivityAction = {\n Login: \"login\",\n Logout: \"logout\",\n FailedLogin: \"failed_login\",\n Register: \"register\",\n EmailConfirmed: \"email_confirmed\",\n PasswordResetRequested: \"password_reset_requested\",\n PasswordResetCompleted: \"password_reset_completed\",\n PasswordChanged: \"password_changed\",\n EmailChanged: \"email_changed\",\n RoleChanged: \"role_changed\",\n StatusChanged: \"status_changed\",\n ForceLogout: \"force_logout\",\n OAuthConnected: \"oauth_connected\",\n RememberTokenCreated: \"remember_token_created\",\n TwoFactorSetup: \"two_factor_setup\",\n TwoFactorVerified: \"two_factor_verified\",\n TwoFactorFailed: \"two_factor_failed\",\n TwoFactorDisabled: \"two_factor_disabled\",\n BackupCodeUsed: \"backup_code_used\",\n} as const;\n\nexport type AuthActivityActionType = (typeof AuthActivityAction)[keyof typeof AuthActivityAction];\n\nexport type TokenCallback = (token: string) => void;\n\ndeclare module \"express-session\" {\n interface SessionData {\n auth?: AuthSession;\n }\n}\n\ndeclare global {\n namespace Express {\n interface Request {\n auth: AuthManager;\n }\n }\n}\n\nexport interface AuthManager {\n isLoggedIn(): boolean;\n login(email: string, password: string, remember?: boolean): Promise<void>;\n completeTwoFactorLogin(): Promise<void>;\n logout(): Promise<void>;\n register(email: string, password: string, userId?: string | number, callback?: TokenCallback): Promise<AuthAccount>;\n resyncSession(force?: boolean): Promise<void>;\n\n getId(): number | null;\n getEmail(): string | null;\n getStatus(): number | null;\n getVerified(): boolean | null;\n hasPassword(): boolean | null;\n getRoleNames(rolemask?: number): string[];\n getStatusName(): string | null;\n\n hasRole(role: number): Promise<boolean>;\n isAdmin(): Promise<boolean>;\n isRemembered(): boolean;\n\n changeEmail(newEmail: string, callback: TokenCallback): Promise<void>;\n confirmEmail(token: string): Promise<string>;\n confirmEmailAndLogin(token: string, remember?: boolean): Promise<void>;\n\n resetPassword(email: string, expiresAfter?: string | number | null, maxOpenRequests?: number | null, callback?: TokenCallback): Promise<void>;\n confirmResetPassword(token: string, password: string, logout?: boolean): Promise<void>;\n\n verifyPassword(password: string): Promise<boolean>;\n\n logoutEverywhere(): Promise<void>;\n logoutEverywhereElse(): Promise<void>;\n\n // admin/standalone functions from AuthContext\n createUser(credentials: { email: string; password: string }, userId?: string | number, callback?: TokenCallback): Promise<AuthAccount>;\n deleteUserBy(identifier: { accountId?: number; email?: string; userId?: string }): Promise<void>;\n addRoleForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<void>;\n removeRoleForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<void>;\n hasRoleForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<boolean>;\n changePasswordForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, password: string): Promise<void>;\n setStatusForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, status: number): Promise<void>;\n initiatePasswordResetForUserBy(identifier: { accountId?: number; email?: string; userId?: string }, expiresAfter?: string | number | null, callback?: TokenCallback): Promise<void>;\n userExistsByEmail(email: string): Promise<boolean>;\n forceLogoutForUserBy(identifier: { accountId?: number; email?: string; userId?: string }): Promise<void>;\n\n // session-dependent admin functions\n loginAsUserBy(identifier: { accountId?: number; email?: string; userId?: string }): Promise<void>;\n\n providers: {\n github?: OAuthProvider;\n google?: OAuthProvider;\n azure?: OAuthProvider;\n };\n\n twoFactor: TwoFactorManager;\n}\n\nexport interface TwoFactorManager {\n isEnabled(): Promise<boolean>;\n totpEnabled(): Promise<boolean>;\n emailEnabled(): Promise<boolean>;\n smsEnabled(): Promise<boolean>;\n getEnabledMethods(): Promise<TwoFactorMechanism[]>;\n getTotpUri(): Promise<string | null>;\n\n setup: {\n /**\n * Setup TOTP authentication using an authenticator app.\n * Generates a secret, QR code for easy setup, and optionally backup codes.\n *\n * @param requireVerification - If true, method is created in unverified state and requires calling complete.totp() with a valid code. If false (default), method is immediately enabled and backup codes are generated.\n * @returns Promise resolving to setup result containing secret (for manual entry), QR code URL (for scanning), and backup codes (if verification not required)\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorAlreadyEnabledError} TOTP is already enabled for this user\n */\n totp(requireVerification?: boolean): Promise<TwoFactorSetupResult>;\n\n /**\n * Setup email-based two-factor authentication.\n * Uses the user's account email or a specified email address for OTP delivery.\n *\n * @param email - Email address to use for 2FA. If not provided, uses the current user's account email\n * @param requireVerification - If true, method is created in unverified state and requires calling complete.email() with a valid code. If false (default), method is immediately enabled\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorAlreadyEnabledError} Email 2FA is already enabled for this user\n */\n email(email?: string, requireVerification?: boolean): Promise<void>;\n\n /**\n * Setup SMS-based two-factor authentication.\n * Uses the provided phone number for OTP delivery via SMS.\n *\n * @param phone - Phone number to use for SMS OTP delivery (should include country code, e.g., \"+1234567890\")\n * @param requireVerification - If true (default), method is created in unverified state and requires calling complete.sms() with a valid code. If false, method is immediately enabled\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorAlreadyEnabledError} SMS 2FA is already enabled for this user\n */\n sms(phone: string, requireVerification?: boolean): Promise<void>;\n };\n\n complete: {\n /**\n * Complete TOTP setup by verifying a code from the user's authenticator app.\n * This is only required if setup.totp() was called with requireVerification: true.\n * Upon successful verification, the method is enabled and backup codes are generated.\n *\n * @param code - The 6-digit TOTP code from the user's authenticator app\n * @returns Promise resolving to an array of backup codes that should be securely stored by the user\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorNotSetupError} TOTP method was not previously set up or doesn't exist\n * @throws {TwoFactorAlreadyEnabledError} TOTP method is already verified/enabled\n * @throws {InvalidTwoFactorCodeError} The provided TOTP code is invalid or expired\n */\n totp(code: string): Promise<string[]>;\n\n /**\n * Complete email 2FA setup by verifying an OTP code sent to the user's email.\n * This is only required if setup.email() was called with requireVerification: true.\n * Upon successful verification, the email 2FA method is enabled.\n *\n * @param code - The OTP code that was sent to the user's email address\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorNotSetupError} Email 2FA method was not previously set up or doesn't exist\n * @throws {TwoFactorAlreadyEnabledError} Email 2FA method is already verified/enabled\n * @throws {InvalidTwoFactorCodeError} The provided email OTP code is invalid or expired\n */\n email(code: string): Promise<void>;\n\n /**\n * Complete SMS 2FA setup by verifying an OTP code sent to the user's phone.\n * This is only required if setup.sms() was called with requireVerification: true.\n * Upon successful verification, the SMS 2FA method is enabled.\n *\n * @param code - The OTP code that was sent to the user's phone number via SMS\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorNotSetupError} SMS 2FA method was not previously set up or doesn't exist\n * @throws {TwoFactorAlreadyEnabledError} SMS 2FA method is already verified/enabled\n * @throws {InvalidTwoFactorCodeError} The provided SMS OTP code is invalid or expired\n */\n sms(code: string): Promise<void>;\n };\n\n // challenge verification (during login flow)\n verify: {\n /**\n * Verifies a TOTP code during the login flow when two-factor authentication is required.\n * This is used after a login attempt triggers a SecondFactorRequiredError and the user\n * provides a code from their authenticator app. After successful verification, call\n * completeTwoFactorLogin() to finish the login process.\n *\n * @param code - The 6-digit TOTP code from the user's authenticator app\n * @throws {UserNotLoggedInError} No active two-factor authentication session\n * @throws {TwoFactorNotSetupError} TOTP method is not enabled for this user\n * @throws {InvalidTwoFactorCodeError} The provided TOTP code is invalid or expired\n */\n totp(code: string): Promise<void>;\n /**\n * Verifies an email OTP code during the login flow when two-factor authentication is required.\n * This is used after a login attempt triggers a SecondFactorRequiredError and the user\n * provides the OTP code that was sent to their email. After successful verification, call\n * completeTwoFactorLogin() to finish the login process.\n *\n * @param code - The OTP code that was sent to the user's email address\n * @throws {UserNotLoggedInError} No active two-factor authentication session\n * @throws {TwoFactorNotSetupError} Email 2FA method is not enabled for this user\n * @throws {InvalidTwoFactorCodeError} The provided email OTP code is invalid or expired\n */\n email(code: string): Promise<void>;\n\n /**\n * Verifies an SMS OTP code during the login flow when two-factor authentication is required.\n * This is used after a login attempt triggers a SecondFactorRequiredError and the user\n * provides the OTP code that was sent to their phone. After successful verification, call\n * completeTwoFactorLogin() to finish the login process.\n *\n * @param code - The OTP code that was sent to the user's phone number via SMS\n * @throws {UserNotLoggedInError} No active two-factor authentication session\n * @throws {TwoFactorNotSetupError} SMS 2FA method is not enabled for this user\n * @throws {InvalidTwoFactorCodeError} The provided SMS OTP code is invalid or expired\n */\n sms(code: string): Promise<void>;\n\n /**\n * Verifies a TOTP backup code during the login flow when two-factor authentication is required.\n * Backup codes are generated when TOTP is first set up and can be used as an alternative to\n * the authenticator app. Each backup code can only be used once and is automatically removed\n * after successful verification. After successful verification, call completeTwoFactorLogin()\n * to finish the login process.\n *\n * @param code - A backup code that was generated during TOTP setup (8-character alphanumeric)\n * @throws {UserNotLoggedInError} No active two-factor authentication session\n * @throws {TwoFactorNotSetupError} TOTP method is not enabled for this user or no backup codes exist\n * @throws {InvalidBackupCodeError} The provided backup code is invalid, expired, or already used\n */\n backupCode(code: string): Promise<void>;\n\n /**\n * Smart OTP verification that works with both email and SMS codes during the login flow.\n * This method automatically determines whether the provided code is an email or SMS OTP\n * by trying to verify it against all available OTP methods. Use this when you want to\n * provide a single input field for users who may have multiple OTP methods enabled.\n * After successful verification, call completeTwoFactorLogin() to finish the login process.\n *\n * @param code - Either an email or SMS OTP code\n * @throws {UserNotLoggedInError} No active two-factor authentication session\n * @throws {TwoFactorNotSetupError} No email or SMS 2FA methods are enabled for this user\n * @throws {InvalidTwoFactorCodeError} The provided code doesn't match any available OTP methods or is expired\n */\n otp(code: string): Promise<void>;\n };\n\n /**\n * Disable a TwoFactorMechanism for the session user.\n * @param mechanism - The TwoFactorMechanism to disable for the session user\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorNotSetupError} The specified method is not enabled for this user\n */\n disable(mechanism: TwoFactorMechanism): Promise<void>;\n\n /**\n * Generates and stores new TOTP backup codes for the session user, invalidating the old ones in the process.\n * @returns Promise resolving to an array of new backup codes that should be securely stored by the user\n * @throws {UserNotLoggedInError} User is not logged in\n * @throws {TwoFactorNotSetupError} TOTP method is not enabled for this user\n */\n generateNewBackupCodes(): Promise<string[]>;\n\n /**\n * Returns either the email or mobile number for the session user depending on the provided TwoFactorMechanism.\n * @param mechanism - The TwoFactorMechanism for which to return the contact information\n * @returns Promise resolving to the contact information (email or phone number) or null if not found\n * @throws {UserNotLoggedInError} User is not logged in (returns null instead of throwing in implementation)\n */\n getContact(mechanism: TwoFactorMechanism.EMAIL | TwoFactorMechanism.SMS): Promise<string | null>;\n}\n","import type { Pool } from \"pg\";\nimport type { AuthConfig, AuthAccount, AuthConfirmation, AuthRemember, AuthReset, AuthProvider, TwoFactorMethod, TwoFactorToken, TwoFactorMechanism } from \"./types.js\";\n\nexport class AuthQueries {\n private db: Pool;\n private tablePrefix: string;\n\n constructor(config: AuthConfig) {\n this.db = config.db;\n this.tablePrefix = config.tablePrefix || \"user_\";\n }\n\n private get accountsTable() {\n return `${this.tablePrefix}accounts`;\n }\n\n private get confirmationsTable() {\n return `${this.tablePrefix}confirmations`;\n }\n\n private get remembersTable() {\n return `${this.tablePrefix}remembers`;\n }\n\n private get resetsTable() {\n return `${this.tablePrefix}resets`;\n }\n\n private get providersTable() {\n return `${this.tablePrefix}providers`;\n }\n\n private get twoFactorMethodsTable() {\n return `${this.tablePrefix}2fa_methods`;\n }\n\n private get twoFactorTokensTable() {\n return `${this.tablePrefix}2fa_tokens`;\n }\n\n async findAccountById(id: number): Promise<AuthAccount | null> {\n const sql = `SELECT * FROM ${this.accountsTable} WHERE id = $1`;\n const result = await this.db.query(sql, [id]);\n return result.rows[0] || null;\n }\n\n async findAccountByUserId(userId: string | number): Promise<AuthAccount | null> {\n const sql = `SELECT * FROM ${this.accountsTable} WHERE user_id = $1`;\n const result = await this.db.query(sql, [userId]);\n return result.rows[0] || null;\n }\n\n async findAccountByEmail(email: string): Promise<AuthAccount | null> {\n const sql = `SELECT * FROM ${this.accountsTable} WHERE email = $1`;\n const result = await this.db.query(sql, [email]);\n return result.rows[0] || null;\n }\n\n async createAccount(data: { userId: string | number; email: string; password: string | null; verified: boolean; status: number; rolemask: number }): Promise<AuthAccount> {\n const sql = `\n INSERT INTO ${this.accountsTable} (\n user_id, email, password, verified, status, rolemask, \n force_logout, resettable, registered\n )\n VALUES ($1, $2, $3, $4, $5, $6, 0, true, NOW())\n RETURNING *\n `;\n\n const result = await this.db.query(sql, [data.userId, data.email, data.password, data.verified, data.status, data.rolemask]);\n\n return result.rows[0];\n }\n\n async updateAccount(id: number, updates: Partial<AuthAccount>): Promise<void> {\n const fields = [];\n const values = [];\n let paramIndex = 1;\n\n for (const [key, value] of Object.entries(updates)) {\n if (key === \"id\") continue; // don't update id\n fields.push(`${key} = $${paramIndex++}`);\n values.push(value);\n }\n\n if (fields.length === 0) return;\n\n values.push(id);\n const sql = `UPDATE ${this.accountsTable} SET ${fields.join(\", \")} WHERE id = $${paramIndex}`;\n await this.db.query(sql, values);\n }\n\n async updateAccountLastLogin(id: number): Promise<void> {\n const sql = `UPDATE ${this.accountsTable} SET last_login = NOW() WHERE id = $1`;\n await this.db.query(sql, [id]);\n }\n\n async incrementForceLogout(id: number): Promise<void> {\n const sql = `UPDATE ${this.accountsTable} SET force_logout = force_logout + 1 WHERE id = $1`;\n await this.db.query(sql, [id]);\n }\n\n async deleteAccount(id: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.twoFactorTokensTable} WHERE account_id = $1`, [id]);\n await this.db.query(`DELETE FROM ${this.twoFactorMethodsTable} WHERE account_id = $1`, [id]);\n await this.db.query(`DELETE FROM ${this.providersTable} WHERE account_id = $1`, [id]);\n await this.db.query(`DELETE FROM ${this.confirmationsTable} WHERE account_id = $1`, [id]);\n await this.db.query(`DELETE FROM ${this.remembersTable} WHERE account_id = $1`, [id]);\n await this.db.query(`DELETE FROM ${this.resetsTable} WHERE account_id = $1`, [id]);\n\n await this.db.query(`DELETE FROM ${this.accountsTable} WHERE id = $1`, [id]);\n }\n\n async createConfirmation(data: { accountId: number; token: string; email: string; expires: Date }): Promise<void> {\n await this.db.query(`DELETE FROM ${this.confirmationsTable} WHERE account_id = $1`, [data.accountId]);\n\n const sql = `\n INSERT INTO ${this.confirmationsTable} (account_id, token, email, expires)\n VALUES ($1, $2, $3, $4)\n `;\n\n await this.db.query(sql, [data.accountId, data.token, data.email, data.expires]);\n }\n\n async findConfirmation(token: string): Promise<AuthConfirmation | null> {\n const sql = `SELECT * FROM ${this.confirmationsTable} WHERE token = $1`;\n const result = await this.db.query(sql, [token]);\n return result.rows[0] || null;\n }\n\n async findLatestConfirmationForAccount(accountId: number): Promise<AuthConfirmation | null> {\n const sql = `\n SELECT * FROM ${this.confirmationsTable} \n WHERE account_id = $1 \n ORDER BY expires DESC \n LIMIT 1\n `;\n const result = await this.db.query(sql, [accountId]);\n return result.rows[0] || null;\n }\n\n async deleteConfirmation(token: string): Promise<void> {\n await this.db.query(`DELETE FROM ${this.confirmationsTable} WHERE token = $1`, [token]);\n }\n\n async createRememberToken(data: { accountId: number; token: string; expires: Date }): Promise<void> {\n await this.db.query(`DELETE FROM ${this.remembersTable} WHERE account_id = $1`, [data.accountId]);\n\n const sql = `\n INSERT INTO ${this.remembersTable} (account_id, token, expires)\n VALUES ($1, $2, $3)\n `;\n\n await this.db.query(sql, [data.accountId, data.token, data.expires]);\n }\n\n async findRememberToken(token: string): Promise<AuthRemember | null> {\n const sql = `SELECT * FROM ${this.remembersTable} WHERE token = $1`;\n const result = await this.db.query(sql, [token]);\n return result.rows[0] || null;\n }\n\n async deleteRememberToken(token: string): Promise<void> {\n await this.db.query(`DELETE FROM ${this.remembersTable} WHERE token = $1`, [token]);\n }\n\n async deleteRememberTokensForAccount(accountId: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.remembersTable} WHERE account_id = $1`, [accountId]);\n }\n\n async deleteExpiredRememberTokensForAccount(accountId: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.remembersTable} WHERE account_id = $1 AND expires <= NOW()`, [accountId]);\n }\n\n async createResetToken(data: { accountId: number; token: string; expires: Date }): Promise<void> {\n const sql = `\n INSERT INTO ${this.resetsTable} (account_id, token, expires)\n VALUES ($1, $2, $3)\n `;\n\n await this.db.query(sql, [data.accountId, data.token, data.expires]);\n }\n\n async findResetToken(token: string): Promise<AuthReset | null> {\n const sql = `\n SELECT * FROM ${this.resetsTable} \n WHERE token = $1 \n ORDER BY expires DESC \n LIMIT 1\n `;\n const result = await this.db.query(sql, [token]);\n return result.rows[0] || null;\n }\n\n async countActiveResetTokensForAccount(accountId: number): Promise<number> {\n const sql = `\n SELECT COUNT(*) as count FROM ${this.resetsTable} \n WHERE account_id = $1 AND expires >= NOW()\n `;\n const result = await this.db.query(sql, [accountId]);\n return parseInt(result.rows[0]?.count || \"0\");\n }\n\n async deleteResetToken(token: string): Promise<void> {\n await this.db.query(`DELETE FROM ${this.resetsTable} WHERE token = $1`, [token]);\n }\n\n async deleteResetTokensForAccount(accountId: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.resetsTable} WHERE account_id = $1`, [accountId]);\n }\n\n async createProvider(data: { accountId: number; provider: string; providerId: string; providerEmail: string | null; providerUsername: string | null; providerName: string | null; providerAvatar: string | null }): Promise<AuthProvider> {\n const sql = `\n INSERT INTO ${this.providersTable} (\n account_id, provider, provider_id, provider_email, \n provider_username, provider_name, provider_avatar\n )\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n RETURNING *\n `;\n\n const result = await this.db.query(sql, [data.accountId, data.provider, data.providerId, data.providerEmail, data.providerUsername, data.providerName, data.providerAvatar]);\n\n return result.rows[0];\n }\n\n async findProviderByProviderIdAndType(providerId: string, provider: string): Promise<AuthProvider | null> {\n const sql = `SELECT * FROM ${this.providersTable} WHERE provider_id = $1 AND provider = $2`;\n const result = await this.db.query(sql, [providerId, provider]);\n return result.rows[0] || null;\n }\n\n async findProvidersByAccountId(accountId: number): Promise<AuthProvider[]> {\n const sql = `SELECT * FROM ${this.providersTable} WHERE account_id = $1 ORDER BY created_at DESC`;\n const result = await this.db.query(sql, [accountId]);\n return result.rows;\n }\n\n async deleteProvider(id: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.providersTable} WHERE id = $1`, [id]);\n }\n\n async deleteProvidersByAccountId(accountId: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.providersTable} WHERE account_id = $1`, [accountId]);\n }\n\n // two-factor authentication methods\n\n async findTwoFactorMethodsByAccountId(accountId: number): Promise<TwoFactorMethod[]> {\n const sql = `SELECT * FROM ${this.twoFactorMethodsTable} WHERE account_id = $1 ORDER BY created_at DESC`;\n const result = await this.db.query(sql, [accountId]);\n return result.rows;\n }\n\n async findTwoFactorMethodByAccountAndMechanism(accountId: number, mechanism: TwoFactorMechanism): Promise<TwoFactorMethod | null> {\n const sql = `SELECT * FROM ${this.twoFactorMethodsTable} WHERE account_id = $1 AND mechanism = $2`;\n const result = await this.db.query(sql, [accountId, mechanism]);\n return result.rows[0] || null;\n }\n\n async createTwoFactorMethod(data: { accountId: number; mechanism: TwoFactorMechanism; secret?: string; backupCodes?: string[]; verified?: boolean }): Promise<TwoFactorMethod> {\n const sql = `\n INSERT INTO ${this.twoFactorMethodsTable} (\n account_id, mechanism, secret, backup_codes, verified\n )\n VALUES ($1, $2, $3, $4, $5)\n RETURNING *\n `;\n\n const result = await this.db.query(sql, [data.accountId, data.mechanism, data.secret || null, data.backupCodes || null, data.verified || false]);\n\n return result.rows[0];\n }\n\n async updateTwoFactorMethod(id: number, updates: Partial<Pick<TwoFactorMethod, \"secret\" | \"backup_codes\" | \"verified\" | \"last_used_at\">>): Promise<void> {\n const fields = [];\n const values = [];\n let paramIndex = 1;\n\n for (const [key, value] of Object.entries(updates)) {\n if (key === \"id\") continue;\n fields.push(`${key} = $${paramIndex++}`);\n values.push(value);\n }\n\n if (fields.length === 0) return;\n\n values.push(id);\n const sql = `UPDATE ${this.twoFactorMethodsTable} SET ${fields.join(\", \")} WHERE id = $${paramIndex}`;\n await this.db.query(sql, values);\n }\n\n async deleteTwoFactorMethod(id: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.twoFactorMethodsTable} WHERE id = $1`, [id]);\n }\n\n async deleteTwoFactorMethodsByAccountId(accountId: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.twoFactorMethodsTable} WHERE account_id = $1`, [accountId]);\n }\n\n // two-factor authentication tokens\n\n async createTwoFactorToken(data: { accountId: number; mechanism: TwoFactorMechanism; selector: string; tokenHash: string; expiresAt: Date }): Promise<TwoFactorToken> {\n const sql = `\n INSERT INTO ${this.twoFactorTokensTable} (\n account_id, mechanism, selector, token_hash, expires_at\n )\n VALUES ($1, $2, $3, $4, $5)\n RETURNING *\n `;\n\n const result = await this.db.query(sql, [data.accountId, data.mechanism, data.selector, data.tokenHash, data.expiresAt]);\n\n return result.rows[0];\n }\n\n async findTwoFactorTokenBySelector(selector: string): Promise<TwoFactorToken | null> {\n const sql = `SELECT * FROM ${this.twoFactorTokensTable} WHERE selector = $1 AND expires_at > NOW()`;\n const result = await this.db.query(sql, [selector]);\n return result.rows[0] || null;\n }\n\n async deleteTwoFactorToken(id: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.twoFactorTokensTable} WHERE id = $1`, [id]);\n }\n\n async deleteTwoFactorTokensByAccountId(accountId: number): Promise<void> {\n await this.db.query(`DELETE FROM ${this.twoFactorTokensTable} WHERE account_id = $1`, [accountId]);\n }\n\n async deleteTwoFactorTokensByAccountAndMechanism(accountId: number, mechanism: TwoFactorMechanism): Promise<void> {\n await this.db.query(`DELETE FROM ${this.twoFactorTokensTable} WHERE account_id = $1 AND mechanism = $2`, [accountId, mechanism]);\n }\n}\n","import type { Request } from \"express\";\nimport type { AuthConfig, AuthActivity, AuthActivityActionType } from \"./types.js\";\nimport Bowser from \"bowser\";\n\nexport class ActivityLogger {\n private config: AuthConfig;\n private enabled: boolean;\n private maxEntries: number;\n private allowedActions: AuthActivityActionType[] | null;\n private tablePrefix: string;\n\n constructor(config: AuthConfig) {\n this.config = config;\n this.enabled = config.activityLog?.enabled !== false; // default true\n this.maxEntries = config.activityLog?.maxEntries || 10000;\n this.allowedActions = config.activityLog?.actions || null; // null means all actions\n this.tablePrefix = config.tablePrefix || \"user_\";\n }\n\n private get activityTable() {\n return `${this.tablePrefix}activity_log`;\n }\n\n private parseUserAgent(userAgent: string | null): {\n browser: string | null;\n os: string | null;\n device: string | null;\n } {\n if (!userAgent) {\n return { browser: null, os: null, device: null };\n }\n\n try {\n const browser = Bowser.getParser(userAgent);\n const result = browser.getResult();\n\n return {\n browser: result.browser.name || null,\n os: result.os.name || null,\n device: result.platform.type || \"desktop\",\n };\n } catch (error) {\n // fallback to simple parsing if bowser fails\n return this.parseUserAgentSimple(userAgent);\n }\n }\n\n private parseUserAgentSimple(userAgent: string): {\n browser: string | null;\n os: string | null;\n device: string | null;\n } {\n let browser = null;\n if (userAgent.includes(\"Chrome\")) browser = \"Chrome\";\n else if (userAgent.includes(\"Firefox\")) browser = \"Firefox\";\n else if (userAgent.includes(\"Safari\")) browser = \"Safari\";\n else if (userAgent.includes(\"Edge\")) browser = \"Edge\";\n\n let os = null;\n if (userAgent.includes(\"Windows\")) os = \"Windows\";\n else if (userAgent.includes(\"Mac OS\")) os = \"macOS\";\n else if (userAgent.includes(\"Linux\")) os = \"Linux\";\n else if (userAgent.includes(\"Android\")) os = \"Android\";\n else if (userAgent.includes(\"iOS\")) os = \"iOS\";\n\n let device = \"desktop\";\n if (userAgent.includes(\"Mobile\")) device = \"mobile\";\n else if (userAgent.includes(\"Tablet\")) device = \"tablet\";\n\n return { browser, os, device };\n }\n\n private getIpAddress(req: Request): string | null {\n return req.ip || req.connection?.remoteAddress || req.socket?.remoteAddress || (req.connection as any)?.socket?.remoteAddress || null;\n }\n\n async logActivity(accountId: number | null, action: AuthActivityActionType, req: Request, success = true, metadata: Record<string, any> = {}): Promise<void> {\n if (!this.enabled) return;\n\n // check if this action is allowed\n if (this.allowedActions && !this.allowedActions.includes(action)) {\n return;\n }\n\n const userAgent = (typeof req.get === \"function\" ? req.get(\"User-Agent\") : req.headers?.[\"user-agent\"]) || null;\n const ip = this.getIpAddress(req);\n const parsed = this.parseUserAgent(userAgent);\n\n try {\n // insert new activity log entry\n await this.config.db.query(\n `\n INSERT INTO ${this.activityTable} \n (account_id, action, ip_address, user_agent, browser, os, device, success, metadata)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)\n `,\n [accountId, action, ip, userAgent, parsed.browser, parsed.os, parsed.device, success, Object.keys(metadata).length > 0 ? JSON.stringify(metadata) : null],\n );\n\n // occasionally cleanup old entries (1% chance per insert to avoid performance impact)\n if (Math.random() < 0.01) {\n await this.cleanup();\n }\n } catch (error) {\n // don't throw on logging errors - just log to console\n console.error(\"ActivityLogger: Failed to log activity:\", error);\n }\n }\n\n async cleanup(): Promise<void> {\n if (!this.enabled) return;\n\n try {\n // delete entries beyond maxEntries limit\n await this.config.db.query(\n `\n DELETE FROM ${this.activityTable} \n WHERE id NOT IN (\n SELECT id FROM ${this.activityTable} \n ORDER BY created_at DESC \n LIMIT $1\n )\n `,\n [this.maxEntries],\n );\n } catch (error) {\n console.error(\"ActivityLogger: Failed to cleanup old entries:\", error);\n }\n }\n\n async getRecentActivity(limit = 100, accountId?: number): Promise<AuthActivity[]> {\n if (!this.enabled) return [];\n\n try {\n let sql = `\n SELECT \n al.*,\n a.email \n FROM ${this.activityTable} al\n LEFT JOIN ${this.tablePrefix}accounts a ON al.account_id = a.id\n `;\n const params: any[] = [];\n\n if (accountId !== undefined) {\n sql += \" WHERE al.account_id = $1\";\n params.push(accountId);\n }\n\n sql += ` ORDER BY al.created_at DESC LIMIT $${params.length + 1}`;\n params.push(Math.min(limit, 1000)); // cap at 1000 entries max\n\n const result = await this.config.db.query(sql, params);\n return result.rows.map((row: any) => ({\n ...row,\n metadata: row.metadata ? JSON.parse(row.metadata) : null,\n }));\n } catch (error) {\n console.error(\"ActivityLogger: Failed to get recent activity:\", error);\n return [];\n }\n }\n\n async getActivityStats(): Promise<{\n totalEntries: number;\n uniqueUsers: number;\n recentLogins: number;\n failedAttempts: number;\n }> {\n if (!this.enabled) {\n return {\n totalEntries: 0,\n uniqueUsers: 0,\n recentLogins: 0,\n failedAttempts: 0,\n };\n }\n\n try {\n const [total, unique, recent, failed] = await Promise.all([\n this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable}`),\n this.config.db.query(`SELECT COUNT(DISTINCT account_id) as count FROM ${this.activityTable} WHERE account_id IS NOT NULL`),\n this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable} WHERE action = 'login' AND created_at > NOW() - INTERVAL '24 hours'`),\n this.config.db.query(`SELECT COUNT(*) as count FROM ${this.activityTable} WHERE success = false AND created_at > NOW() - INTERVAL '24 hours'`),\n ]);\n\n return {\n totalEntries: parseInt(total.rows[0]?.count || \"0\"),\n uniqueUsers: parseInt(unique.rows[0]?.count || \"0\"),\n recentLogins: parseInt(recent.rows[0]?.count || \"0\"),\n failedAttempts: parseInt(failed.rows[0]?.count || \"0\"),\n };\n } catch (error) {\n console.error(\"ActivityLogger: Failed to get activity stats:\", error);\n return {\n totalEntries: 0,\n uniqueUsers: 0,\n recentLogins: 0,\n failedAttempts: 0,\n };\n }\n }\n}\n","export class AuthError extends Error {\n constructor(message: string) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n\nexport class ConfirmationExpiredError extends AuthError {\n constructor() {\n super(\"Confirmation token has expired\");\n }\n}\n\nexport class ConfirmationNotFoundError extends AuthError {\n constructor() {\n super(\"Confirmation token not found\");\n }\n}\n\nexport class EmailNotVerifiedError extends AuthError {\n constructor() {\n super(\"Email address has not been verified\");\n }\n}\n\nexport class EmailTakenError extends AuthError {\n constructor() {\n super(\"Email address is already in use\");\n }\n}\n\nexport class InvalidEmailError extends AuthError {\n constructor() {\n super(\"Invalid email address format\");\n }\n}\n\nexport class InvalidPasswordError extends AuthError {\n constructor() {\n super(\"Invalid password\");\n }\n}\n\nexport class InvalidTokenError extends AuthError {\n constructor() {\n super(\"Invalid token\");\n }\n}\n\nexport class ResetDisabledError extends AuthError {\n constructor() {\n super(\"Password reset is disabled for this account\");\n }\n}\n\nexport class ResetExpiredError extends AuthError {\n constructor() {\n super(\"Password reset token has expired\");\n }\n}\n\nexport class ResetNotFoundError extends AuthError {\n constructor() {\n super(\"Password reset token not found\");\n }\n}\n\nexport class TooManyResetsError extends AuthError {\n constructor() {\n super(\"Too many password reset requests\");\n }\n}\n\nexport class UserInactiveError extends AuthError {\n constructor() {\n super(\"User account is inactive\");\n }\n}\n\nexport class UserNotFoundError extends AuthError {\n constructor() {\n super(\"User not found\");\n }\n}\n\nexport class UserNotLoggedInError extends AuthError {\n constructor() {\n super(\"User is not logged in\");\n }\n}\n\n// two-factor authentication errors\n\nexport class SecondFactorRequiredError extends AuthError {\n public availableMethods: {\n totp?: boolean;\n email?: { otpValue: string; maskedContact: string };\n sms?: { otpValue: string; maskedContact: string };\n };\n\n constructor(availableMethods: SecondFactorRequiredError[\"availableMethods\"]) {\n super(\"Second factor authentication required\");\n this.availableMethods = availableMethods;\n }\n}\n\nexport class InvalidTwoFactorCodeError extends AuthError {\n constructor() {\n super(\"Invalid two-factor authentication code\");\n }\n}\n\nexport class TwoFactorExpiredError extends AuthError {\n constructor() {\n super(\"Two-factor authentication session has expired\");\n }\n}\n\nexport class TwoFactorNotSetupError extends AuthError {\n constructor() {\n super(\"Two-factor authentication is not set up for this account\");\n }\n}\n\nexport class TwoFactorAlreadyEnabledError extends AuthError {\n constructor() {\n super(\"Two-factor authentication is already enabled for this mechanism\");\n }\n}\n\nexport class InvalidBackupCodeError extends AuthError {\n constructor() {\n super(\"Invalid backup code\");\n }\n}\n\nexport class TwoFactorSetupIncompleteError extends AuthError {\n constructor() {\n super(\"Two-factor authentication setup is not complete\");\n }\n}\n","import { InvalidEmailError } from \"./errors.js\";\n\nexport const isValidEmail = (email: string): boolean => {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(email);\n};\n\nexport const validateEmail = (email: string): void => {\n if (typeof email !== \"string\") {\n throw new InvalidEmailError();\n }\n if (!email.trim()) {\n throw new InvalidEmailError();\n }\n if (!isValidEmail(email)) {\n throw new InvalidEmailError();\n }\n};\n\nexport const createMapFromEnum = (enumObj: Record<string, number>) => Object.fromEntries(Object.entries(enumObj).map(([key, value]) => [value, key]));\n","import type { Request } from \"express\";\nimport type { OAuthProvider, OAuthUserData, OAuthProviderConfig, AuthConfig, OAuthCallbackResult } from \"../types.js\";\nimport { AuthManager } from \"../auth-manager.js\";\n\nexport abstract class BaseOAuthProvider implements OAuthProvider {\n protected config: OAuthProviderConfig;\n protected authConfig: AuthConfig;\n protected authManager: AuthManager;\n\n constructor(config: OAuthProviderConfig, authConfig: AuthConfig, authManager: AuthManager) {\n this.config = config;\n this.authConfig = authConfig;\n this.authManager = authManager;\n }\n\n abstract getAuthUrl(state?: string, scopes?: string[]): string;\n abstract getUserData(req: Request): Promise<OAuthUserData>;\n\n async handleCallback(req: Request): Promise<OAuthCallbackResult> {\n const userData = await this.getUserData(req);\n return this.processOAuthLogin(userData, req);\n }\n\n protected async processOAuthLogin(userData: OAuthUserData, req: Request): Promise<OAuthCallbackResult> {\n const { queries } = this.authManager as any;\n const providerName = this.getProviderName();\n\n const existingProvider = await queries.findProviderByProviderIdAndType(userData.id, providerName);\n\n if (existingProvider) {\n const account = await queries.findAccountById(existingProvider.account_id);\n if (account) {\n await (this.authManager as any).onLoginSuccessful(account, true);\n return { isNewUser: false };\n }\n }\n\n // new OAuth user - check if email already exists\n if (userData.email) {\n const existingAccount = await queries.findAccountByEmail(userData.email);\n if (existingAccount) {\n throw new Error(\"You already have an account associated with this email address.\");\n }\n }\n\n // create new user and account\n let userId: string | number;\n\n if (this.authConfig.createUser) {\n userId = await this.authConfig.createUser(userData);\n } else {\n // Generate UUID for OAuth users when no createUser function is provided\n userId = crypto.randomUUID();\n }\n\n // create the auth account (no password for OAuth)\n const account = await queries.createAccount({\n userId,\n email: userData.email,\n password: null,\n verified: true, // OAuth providers are pre-verified\n status: 0, // AuthStatus.Normal\n rolemask: 0,\n });\n\n // create the provider record\n await queries.createProvider({\n accountId: account.id,\n provider: providerName,\n providerId: userData.id,\n providerEmail: userData.email,\n providerUsername: userData.username || null,\n providerName: userData.name || null,\n providerAvatar: userData.avatar || null,\n });\n\n await (this.authManager as any).onLoginSuccessful(account, true);\n return { isNewUser: true };\n }\n\n protected abstract getProviderName(): string;\n\n protected async exchangeCodeForToken(code: string, tokenUrl: string): Promise<string> {\n const response = await fetch(tokenUrl, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: new URLSearchParams({\n client_id: this.config.clientId,\n client_secret: this.config.clientSecret,\n code,\n redirect_uri: this.config.redirectUri,\n grant_type: \"authorization_code\",\n }),\n });\n\n if (!response.ok) {\n throw new Error(`OAuth token exchange failed: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n if (!data.access_token) {\n throw new Error(\"No access token received from OAuth provider\");\n }\n\n return data.access_token;\n }\n\n protected async fetchUserFromAPI(accessToken: string, apiUrl: string, headers: Record<string, string> = {}): Promise<any> {\n const response = await fetch(apiUrl, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n Accept: \"application/json\",\n ...headers,\n },\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch user data: ${response.status} ${response.statusText}`);\n }\n\n return response.json();\n }\n}\n","import type { Request } from \"express\";\nimport type { OAuthUserData, GitHubProviderConfig, AuthConfig } from \"../types.js\";\nimport { BaseOAuthProvider } from \"./base-provider.js\";\nimport { AuthManager } from \"../auth-manager.js\";\n\nexport class GitHubProvider extends BaseOAuthProvider {\n constructor(config: GitHubProviderConfig, authConfig: AuthConfig, authManager: AuthManager) {\n super(config, authConfig, authManager);\n }\n\n getAuthUrl(state?: string, scopes?: string[]): string {\n const params = new URLSearchParams({\n client_id: this.config.clientId,\n redirect_uri: this.config.redirectUri,\n scope: scopes?.join(\" \") || \"user:email\",\n state: state || Math.random().toString(36).substring(2),\n response_type: \"code\",\n });\n\n return `https://github.com/login/oauth/authorize?${params}`;\n }\n\n async getUserData(req: Request): Promise<OAuthUserData> {\n const code = req.query.code as string;\n if (!code) {\n throw new Error(\"No authorization code provided\");\n }\n\n // exchange code for access token\n const accessToken = await this.exchangeCodeForToken(code, \"https://github.com/login/oauth/access_token\");\n\n const apiHeaders = {\n Accept: \"application/vnd.github+json\",\n \"User-Agent\": this.authConfig.githubUserAgent || \"EasyAccess\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n };\n\n const [user, emails] = await Promise.all([\n this.fetchUserFromAPI(accessToken, \"https://api.github.com/user\", apiHeaders),\n this.fetchUserFromAPI(accessToken, \"https://api.github.com/user/emails\", apiHeaders),\n ]);\n\n const verifiedEmails = Array.isArray(emails) ? emails.filter((email: any) => email.verified) : [];\n const primaryEmail = verifiedEmails.find((email: any) => email.primary)?.email;\n const fallbackEmail = primaryEmail || verifiedEmails[0]?.email;\n\n if (!fallbackEmail) {\n throw new Error(\"No verified email found in GitHub account\");\n }\n\n return {\n id: user.id.toString(),\n email: fallbackEmail,\n username: user.login,\n name: user.name || user.login,\n avatar: user.avatar_url,\n };\n }\n\n protected getProviderName(): string {\n return \"github\";\n }\n}\n","import type { Request } from \"express\";\nimport type { OAuthUserData, GoogleProviderConfig, AuthConfig } from \"../types.js\";\nimport { BaseOAuthProvider } from \"./base-provider.js\";\nimport { AuthManager } from \"../auth-manager.js\";\n\nexport class GoogleProvider extends BaseOAuthProvider {\n constructor(config: GoogleProviderConfig, authConfig: AuthConfig, authManager: AuthManager) {\n super(config, authConfig, authManager);\n }\n\n getAuthUrl(state?: string, scopes?: string[]): string {\n const params = new URLSearchParams({\n client_id: this.config.clientId,\n redirect_uri: this.config.redirectUri,\n scope: scopes?.join(\" \") || \"openid profile email\",\n state: state || Math.random().toString(36).substring(2),\n response_type: \"code\",\n access_type: \"offline\",\n prompt: \"consent\",\n });\n\n return `https://accounts.google.com/o/oauth2/v2/auth?${params}`;\n }\n\n async getUserData(req: Request): Promise<OAuthUserData> {\n const code = req.query.code as string;\n if (!code) {\n throw new Error(\"No authorization code provided\");\n }\n\n // exchange code for access token\n const accessToken = await this.exchangeCodeForToken(code, \"https://oauth2.googleapis.com/token\");\n\n // fetch user data\n const user = await this.fetchUserFromAPI(accessToken, \"https://www.googleapis.com/oauth2/v2/userinfo\");\n\n if (!user.email) {\n throw new Error(\"No email found in Google account\");\n }\n\n return {\n id: user.id,\n email: user.email,\n username: user.email.split(\"@\")[0], // use email prefix as username\n name: user.name,\n avatar: user.picture,\n };\n }\n\n protected getProviderName(): string {\n return \"google\";\n }\n}\n","import type { Request } from \"express\";\nimport type { OAuthUserData, AzureProviderConfig, AuthConfig } from \"../types.js\";\nimport { BaseOAuthProvider } from \"./base-provider.js\";\nimport { AuthManager } from \"../auth-manager.js\";\n\nexport class AzureProvider extends BaseOAuthProvider {\n constructor(config: AzureProviderConfig, authConfig: AuthConfig, authManager: AuthManager) {\n super(config, authConfig, authManager);\n }\n\n getAuthUrl(state?: string, scopes?: string[]): string {\n const azureConfig = this.config as AzureProviderConfig;\n const params = new URLSearchParams({\n client_id: azureConfig.clientId,\n redirect_uri: azureConfig.redirectUri,\n scope: scopes?.join(\" \") || \"openid profile email User.Read\",\n state: state || Math.random().toString(36).substring(2),\n response_type: \"code\",\n response_mode: \"query\",\n });\n\n return `https://login.microsoftonline.com/${azureConfig.tenantId}/oauth2/v2.0/authorize?${params}`;\n }\n\n async getUserData(req: Request): Promise<OAuthUserData> {\n const code = req.query.code as string;\n if (!code) {\n throw new Error(\"No authorization code provided\");\n }\n\n // exchange code for access token\n const azureConfig = this.config as AzureProviderConfig;\n const accessToken = await this.exchangeCodeForToken(code, `https://login.microsoftonline.com/${azureConfig.tenantId}/oauth2/v2.0/token`);\n\n // fetch user data from Microsoft Graph\n const user = await this.fetchUserFromAPI(accessToken, \"https://graph.microsoft.com/v1.0/me\");\n\n if (!user.mail && !user.userPrincipalName) {\n throw new Error(\"No email found in Azure account\");\n }\n\n return {\n id: user.id,\n email: user.mail || user.userPrincipalName,\n username: user.mailNickname || user.userPrincipalName?.split(\"@\")[0],\n name: user.displayName,\n avatar: undefined, // Azure doesn't provide avatar in basic profile\n };\n }\n\n protected getProviderName(): string {\n return \"azure\";\n }\n\n protected async exchangeCodeForToken(code: string, tokenUrl: string): Promise<string> {\n const azureConfig = this.config as AzureProviderConfig;\n const response = await fetch(tokenUrl, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: new URLSearchParams({\n client_id: azureConfig.clientId,\n client_secret: azureConfig.clientSecret,\n code,\n redirect_uri: azureConfig.redirectUri,\n grant_type: \"authorization_code\",\n scope: \"openid profile email User.Read\",\n }),\n });\n\n if (!response.ok) {\n throw new Error(`OAuth token exchange failed: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n if (!data.access_token) {\n throw new Error(\"No access token received from Azure\");\n }\n\n return data.access_token;\n }\n}\n","import Otp from \"@eaccess/totp\";\nimport { hash } from \"@prsm/hash\";\nimport type { AuthConfig } from \"../types.js\";\nimport type { Request } from \"express\";\n\nexport class TotpProvider {\n private config: AuthConfig;\n\n constructor(config: AuthConfig) {\n this.config = config;\n }\n\n generateSecret(): string {\n return Otp.createSecret();\n }\n\n generateQRCode(email: string, secret: string): string {\n const issuer = this.config.twoFactor?.issuer || \"EasyAccess\";\n return Otp.createTotpKeyUriForQrCode(issuer, email, secret);\n }\n\n verify(secret: string, code: string): boolean {\n const window = this.config.twoFactor?.totpWindow || 1;\n return Otp.verifyTotp(secret, code, window);\n }\n\n generateBackupCodes(count: number = 10): string[] {\n const codes: string[] = [];\n for (let i = 0; i < count; i++) {\n // generate 8-character backup codes (numbers + letters, avoiding confusing characters)\n const chars = \"23456789ABCDEFGHJKLMNPQRSTUVWXYZ\";\n let code = \"\";\n for (let j = 0; j < 8; j++) {\n code += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n codes.push(code);\n }\n return codes;\n }\n\n hashBackupCodes(codes: string[]): string[] {\n return codes.map((code) => hash.encode(code));\n }\n\n verifyBackupCode(hashedCodes: string[], inputCode: string): { isValid: boolean; index: number } {\n for (let i = 0; i < hashedCodes.length; i++) {\n if (hash.verify(hashedCodes[i], inputCode.toUpperCase())) {\n return { isValid: true, index: i };\n }\n }\n\n return { isValid: false, index: -1 };\n }\n\n maskEmail(email: string): string {\n const [username, domain] = email.split(\"@\");\n if (username.length <= 2) {\n return `${username[0]}***@${domain}`;\n }\n return `${username[0]}${\"*\".repeat(username.length - 2)}${username[username.length - 1]}@${domain}`;\n }\n}\n","import ms from \"@prsm/ms\";\nimport { hash } from \"@prsm/hash\";\nimport type { AuthConfig, TwoFactorMechanism, TwoFactorToken } from \"../types.js\";\nimport { AuthQueries } from \"../queries.js\";\n\nexport class OtpProvider {\n private config: AuthConfig;\n private queries: AuthQueries;\n\n constructor(config: AuthConfig) {\n this.config = config;\n this.queries = new AuthQueries(config);\n }\n\n generateOTP(): string {\n const length = this.config.twoFactor?.codeLength || 6;\n let otp = \"\";\n for (let i = 0; i < length; i++) {\n otp += Math.floor(Math.random() * 10).toString();\n }\n return otp;\n }\n\n generateSelector(): string {\n // generate a random 32-character selector for security\n const chars = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\";\n let selector = \"\";\n for (let i = 0; i < 32; i++) {\n selector += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return selector;\n }\n\n async createAndStoreOTP(accountId: number, mechanism: TwoFactorMechanism.EMAIL | TwoFactorMechanism.SMS): Promise<{ otp: string; selector: string }> {\n const otp = this.generateOTP();\n const selector = this.generateSelector();\n const tokenHash = hash.encode(otp);\n\n const expiryDuration = this.config.twoFactor?.tokenExpiry || \"5m\";\n const expiresAt = new Date(Date.now() + ms(expiryDuration));\n\n // delete any existing tokens for this account and mechanism\n await this.queries.deleteTwoFactorTokensByAccountAndMechanism(accountId, mechanism);\n\n // store the new token\n await this.queries.createTwoFactorToken({\n accountId,\n mechanism,\n selector,\n tokenHash,\n expiresAt,\n });\n\n return { otp, selector };\n }\n\n async verifyOTP(selector: string, inputCode: string): Promise<{ isValid: boolean; token?: TwoFactorToken }> {\n const token = await this.queries.findTwoFactorTokenBySelector(selector);\n\n if (!token) {\n return { isValid: false };\n }\n\n // check if token has expired (extra check, even though query filters expired tokens)\n if (token.expires_at <= new Date()) {\n // clean up expired token\n await this.queries.deleteTwoFactorToken(token.id);\n return { isValid: false };\n }\n\n const isValid = hash.verify(token.token_hash, inputCode);\n\n if (isValid) {\n // clean up used token\n await this.queries.deleteTwoFactorToken(token.id);\n return { isValid: true, token };\n }\n\n return { isValid: false };\n }\n\n maskPhone(phone: string): string {\n if (phone.length < 4) {\n return phone.replace(/./g, \"*\");\n }\n\n // show first digit and last 2 digits: +1234567890 -> +1*****90\n if (phone.startsWith(\"+\")) {\n return phone[0] + phone[1] + \"*\".repeat(phone.length - 3) + phone.slice(-2);\n }\n\n // for regular numbers: 1234567890 -> 1*****90\n return phone[0] + \"*\".repeat(phone.length - 3) + phone.slice(-2);\n }\n\n maskEmail(email: string): string {\n const [username, domain] = email.split(\"@\");\n if (username.length <= 2) {\n return `${username[0]}***@${domain}`;\n }\n return `${username[0]}${\"*\".repeat(username.length - 2)}${username[username.length - 1]}@${domain}`;\n }\n}\n","import type { Request, Response } from \"express\";\nimport type { AuthConfig, TwoFactorManager as ITwoFactorManager, TwoFactorSetupResult, TwoFactorChallenge } from \"../types.js\";\nimport { TwoFactorMechanism } from \"../types.js\";\nimport { AuthQueries } from \"../queries.js\";\nimport { ActivityLogger } from \"../activity-logger.js\";\nimport { AuthActivityAction } from \"../types.js\";\nimport { TotpProvider } from \"./totp-provider.js\";\nimport { OtpProvider } from \"./otp-provider.js\";\nimport { TwoFactorNotSetupError, TwoFactorAlreadyEnabledError, TwoFactorSetupIncompleteError, InvalidTwoFactorCodeError, InvalidBackupCodeError, UserNotLoggedInError } from \"../errors.js\";\n\nexport class TwoFactorManager implements ITwoFactorManager {\n private req: Request;\n private res: Response;\n private config: AuthConfig;\n private queries: AuthQueries;\n private activityLogger: ActivityLogger;\n private totpProvider: TotpProvider;\n private otpProvider: OtpProvider;\n\n constructor(req: Request, res: Response, config: AuthConfig) {\n this.req = req;\n this.res = res;\n this.config = config;\n this.queries = new AuthQueries(config);\n this.activityLogger = new ActivityLogger(config);\n this.totpProvider = new TotpProvider(config);\n this.otpProvider = new OtpProvider(config);\n }\n\n private getAccountId(): number | null {\n return this.req.session?.auth?.accountId || null;\n }\n\n private getEmail(): string | null {\n return this.req.session?.auth?.email || null;\n }\n\n // status queries\n\n async isEnabled(): Promise<boolean> {\n const accountId = this.getAccountId();\n if (!accountId) return false;\n\n const methods = await this.queries.findTwoFactorMethodsByAccountId(accountId);\n return methods.some((method) => method.verified);\n }\n\n async totpEnabled(): Promise<boolean> {\n const accountId = this.getAccountId();\n if (!accountId) return false;\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.TOTP);\n return method?.verified || false;\n }\n\n async emailEnabled(): Promise<boolean> {\n const accountId = this.getAccountId();\n if (!accountId) return false;\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.EMAIL);\n return method?.verified || false;\n }\n\n async smsEnabled(): Promise<boolean> {\n const accountId = this.getAccountId();\n if (!accountId) return false;\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.SMS);\n return method?.verified || false;\n }\n\n async getEnabledMethods(): Promise<TwoFactorMechanism[]> {\n const accountId = this.getAccountId();\n if (!accountId) return [];\n\n const methods = await this.queries.findTwoFactorMethodsByAccountId(accountId);\n return methods.filter((method) => method.verified).map((method) => method.mechanism);\n }\n\n // setup & management\n\n setup = {\n totp: async (requireVerification = false): Promise<TwoFactorSetupResult> => {\n const accountId = this.getAccountId();\n const email = this.getEmail();\n\n if (!accountId || !email) {\n throw new UserNotLoggedInError();\n }\n\n // check if TOTP is already enabled\n const existingMethod = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.TOTP);\n\n if (existingMethod?.verified) {\n throw new TwoFactorAlreadyEnabledError();\n }\n\n const secret = this.totpProvider.generateSecret();\n const qrCode = this.totpProvider.generateQRCode(email, secret);\n\n // generate backup codes immediately if no verification required\n let backupCodes: string[] | undefined;\n if (!requireVerification) {\n const backupCodesCount = this.config.twoFactor?.backupCodesCount || 10;\n backupCodes = this.totpProvider.generateBackupCodes(backupCodesCount);\n }\n\n const hashedBackupCodes = backupCodes ? this.totpProvider.hashBackupCodes(backupCodes) : undefined;\n const verified = !requireVerification;\n\n // create or update the TOTP method\n if (existingMethod) {\n await this.queries.updateTwoFactorMethod(existingMethod.id, {\n secret,\n backup_codes: hashedBackupCodes || null,\n verified,\n });\n } else {\n await this.queries.createTwoFactorMethod({\n accountId,\n mechanism: TwoFactorMechanism.TOTP,\n secret,\n backupCodes: hashedBackupCodes,\n verified,\n });\n }\n\n if (verified) {\n await this.activityLogger.logActivity(accountId, AuthActivityAction.TwoFactorSetup, this.req, true, { mechanism: \"totp\" });\n }\n\n return { secret, qrCode, backupCodes };\n },\n\n email: async (email?: string, requireVerification = false): Promise<void> => {\n const accountId = this.getAccountId();\n const userEmail = email || this.getEmail();\n\n if (!accountId || !userEmail) {\n throw new UserNotLoggedInError();\n }\n\n // check if email 2FA is already enabled\n const existingMethod = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.EMAIL);\n\n if (existingMethod?.verified) {\n throw new TwoFactorAlreadyEnabledError();\n }\n\n const verified = !requireVerification;\n\n // create or update the email method\n if (existingMethod) {\n await this.queries.updateTwoFactorMethod(existingMethod.id, {\n secret: userEmail,\n verified,\n });\n } else {\n await this.queries.createTwoFactorMethod({\n accountId,\n mechanism: TwoFactorMechanism.EMAIL,\n secret: userEmail,\n verified,\n });\n }\n\n if (verified) {\n await this.activityLogger.logActivity(accountId, AuthActivityAction.TwoFactorSetup, this.req, true, { mechanism: \"email\" });\n }\n },\n\n sms: async (phone: string, requireVerification = true): Promise<void> => {\n const accountId = this.getAccountId();\n\n if (!accountId) {\n throw new UserNotLoggedInError();\n }\n\n // check if SMS 2FA is already enabled\n const existingMethod = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.SMS);\n\n if (existingMethod?.verified) {\n throw new TwoFactorAlreadyEnabledError();\n }\n\n const verified = !requireVerification;\n\n // create or update the SMS method\n if (existingMethod) {\n await this.queries.updateTwoFactorMethod(existingMethod.id, {\n secret: phone,\n verified,\n });\n } else {\n await this.queries.createTwoFactorMethod({\n accountId,\n mechanism: TwoFactorMechanism.SMS,\n secret: phone,\n verified,\n });\n }\n\n if (verified) {\n await this.activityLogger.logActivity(accountId, AuthActivityAction.TwoFactorSetup, this.req, true, { mechanism: \"sms\" });\n }\n },\n };\n\n complete = {\n totp: async (code: string): Promise<string[]> => {\n const accountId = this.getAccountId();\n\n if (!accountId) {\n throw new UserNotLoggedInError();\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.TOTP);\n\n if (!method || !method.secret) {\n throw new TwoFactorNotSetupError();\n }\n\n if (method.verified) {\n throw new TwoFactorAlreadyEnabledError();\n }\n\n // verify the TOTP code\n const isValid = this.totpProvider.verify(method.secret, code);\n if (!isValid) {\n await this.activityLogger.logActivity(accountId, AuthActivityAction.TwoFactorFailed, this.req, false, { mechanism: \"totp\", reason: \"invalid_code\" });\n throw new InvalidTwoFactorCodeError();\n }\n\n // generate backup codes\n const backupCodesCount = this.config.twoFactor?.backupCodesCount || 10;\n const backupCodes = this.totpProvider.generateBackupCodes(backupCodesCount);\n const hashedBackupCodes = this.totpProvider.hashBackupCodes(backupCodes);\n\n // mark as verified and store backup codes\n await this.queries.updateTwoFactorMethod(method.id, {\n verified: true,\n backup_codes: hashedBackupCodes,\n last_used_at: new Date(),\n });\n\n await this.activityLogger.logActivity(accountId, AuthActivityAction.TwoFactorSetup, this.req, true, { mechanism: \"totp\" });\n\n return backupCodes;\n },\n\n email: async (code: string): Promise<void> => {\n await this.completeOtpSetup(TwoFactorMechanism.EMAIL, code);\n },\n\n sms: async (code: string): Promise<void> => {\n await this.completeOtpSetup(TwoFactorMechanism.SMS, code);\n },\n };\n\n private async completeOtpSetup(mechanism: TwoFactorMechanism.EMAIL | TwoFactorMechanism.SMS, code: string): Promise<void> {\n const accountId = this.getAccountId();\n\n if (!accountId) {\n throw new UserNotLoggedInError();\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, mechanism);\n\n if (!method) {\n throw new TwoFactorNotSetupError();\n }\n\n if (method.verified) {\n throw new TwoFactorAlreadyEnabledError();\n }\n\n // for setup completion, we need a temporary OTP that was sent during setup\n // this should be handled by the application calling this method after sending an OTP\n // for now, we'll assume the code is valid if provided (in a real implementation,\n // you'd generate and store a temporary OTP during the setup process)\n\n // mark as verified\n await this.queries.updateTwoFactorMethod(method.id, {\n verified: true,\n last_used_at: new Date(),\n });\n\n await this.activityLogger.logActivity(accountId, AuthActivityAction.TwoFactorSetup, this.req, true, { mechanism: mechanism === TwoFactorMechanism.EMAIL ? \"email\" : \"sms\" });\n }\n\n // verification during login flow\n\n verify = {\n totp: async (code: string): Promise<void> => {\n const twoFactorState = this.req.session?.auth?.awaitingTwoFactor;\n\n if (!twoFactorState) {\n throw new UserNotLoggedInError();\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(twoFactorState.accountId, TwoFactorMechanism.TOTP);\n\n if (!method || !method.verified || !method.secret) {\n throw new TwoFactorNotSetupError();\n }\n\n const isValid = this.totpProvider.verify(method.secret, code);\n if (!isValid) {\n await this.activityLogger.logActivity(twoFactorState.accountId, AuthActivityAction.TwoFactorFailed, this.req, false, { mechanism: \"totp\", reason: \"invalid_code\" });\n throw new InvalidTwoFactorCodeError();\n }\n\n // update last used\n await this.queries.updateTwoFactorMethod(method.id, {\n last_used_at: new Date(),\n });\n\n await this.activityLogger.logActivity(twoFactorState.accountId, AuthActivityAction.TwoFactorVerified, this.req, true, { mechanism: \"totp\" });\n },\n\n email: async (code: string): Promise<void> => {\n await this.verifyOtp(TwoFactorMechanism.EMAIL, code);\n },\n\n sms: async (code: string): Promise<void> => {\n await this.verifyOtp(TwoFactorMechanism.SMS, code);\n },\n\n backupCode: async (code: string): Promise<void> => {\n const twoFactorState = this.req.session?.auth?.awaitingTwoFactor;\n\n if (!twoFactorState) {\n throw new UserNotLoggedInError();\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(twoFactorState.accountId, TwoFactorMechanism.TOTP);\n\n if (!method || !method.verified || !method.backup_codes) {\n throw new TwoFactorNotSetupError();\n }\n\n const { isValid, index } = this.totpProvider.verifyBackupCode(method.backup_codes, code);\n\n if (!isValid) {\n await this.activityLogger.logActivity(twoFactorState.accountId, AuthActivityAction.TwoFactorFailed, this.req, false, { mechanism: \"backup_code\", reason: \"invalid_code\" });\n throw new InvalidBackupCodeError();\n }\n\n // remove the used backup code\n const updatedBackupCodes = [...method.backup_codes];\n updatedBackupCodes.splice(index, 1);\n\n await this.queries.updateTwoFactorMethod(method.id, {\n backup_codes: updatedBackupCodes,\n last_used_at: new Date(),\n });\n\n await this.activityLogger.logActivity(twoFactorState.accountId, AuthActivityAction.BackupCodeUsed, this.req, true, { remaining_codes: updatedBackupCodes.length });\n },\n\n otp: async (code: string): Promise<void> => {\n const twoFactorState = this.req.session?.auth?.awaitingTwoFactor;\n\n if (!twoFactorState) {\n throw new UserNotLoggedInError();\n }\n\n // try to find which mechanism this OTP is for based on available methods\n const availableMechanisms = twoFactorState.availableMechanisms.filter((m) => m === TwoFactorMechanism.EMAIL || m === TwoFactorMechanism.SMS);\n\n if (availableMechanisms.length === 0) {\n throw new TwoFactorNotSetupError();\n }\n\n // try each available OTP mechanism\n for (const mechanism of availableMechanisms) {\n try {\n await this.verifyOtp(mechanism, code);\n return; // success, exit early\n } catch (error) {\n // continue to next mechanism\n continue;\n }\n }\n\n // if we get here, none of the mechanisms worked\n await this.activityLogger.logActivity(twoFactorState.accountId, AuthActivityAction.TwoFactorFailed, this.req, false, { mechanism: \"otp\", reason: \"invalid_code\" });\n throw new InvalidTwoFactorCodeError();\n },\n };\n\n private async verifyOtp(mechanism: TwoFactorMechanism.EMAIL | TwoFactorMechanism.SMS, code: string): Promise<void> {\n const twoFactorState = this.req.session?.auth?.awaitingTwoFactor;\n\n if (!twoFactorState) {\n throw new UserNotLoggedInError();\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(twoFactorState.accountId, mechanism);\n\n if (!method || !method.verified) {\n throw new TwoFactorNotSetupError();\n }\n\n // find the selector that was stored during login attempt\n const selector = mechanism === TwoFactorMechanism.EMAIL ? this.req.session?.auth?.awaitingTwoFactor?.selectors?.email : this.req.session?.auth?.awaitingTwoFactor?.selectors?.sms;\n\n if (!selector) {\n throw new InvalidTwoFactorCodeError();\n }\n\n const { isValid } = await this.otpProvider.verifyOTP(selector, code);\n\n if (!isValid) {\n await this.activityLogger.logActivity(twoFactorState.accountId, AuthActivityAction.TwoFactorFailed, this.req, false, {\n mechanism: mechanism === TwoFactorMechanism.EMAIL ? \"email\" : \"sms\",\n reason: \"invalid_code\",\n });\n throw new InvalidTwoFactorCodeError();\n }\n\n // update last used\n await this.queries.updateTwoFactorMethod(method.id, {\n last_used_at: new Date(),\n });\n\n await this.activityLogger.logActivity(twoFactorState.accountId, AuthActivityAction.TwoFactorVerified, this.req, true, { mechanism: mechanism === TwoFactorMechanism.EMAIL ? \"email\" : \"sms\" });\n }\n\n // management\n\n async disable(mechanism: TwoFactorMechanism): Promise<void> {\n const accountId = this.getAccountId();\n\n if (!accountId) {\n throw new UserNotLoggedInError();\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, mechanism);\n\n if (!method) {\n throw new TwoFactorNotSetupError();\n }\n\n await this.queries.deleteTwoFactorMethod(method.id);\n\n await this.activityLogger.logActivity(accountId, AuthActivityAction.TwoFactorDisabled, this.req, true, {\n mechanism: mechanism === TwoFactorMechanism.TOTP ? \"totp\" : mechanism === TwoFactorMechanism.EMAIL ? \"email\" : \"sms\",\n });\n }\n\n async generateNewBackupCodes(): Promise<string[]> {\n const accountId = this.getAccountId();\n\n if (!accountId) {\n throw new UserNotLoggedInError();\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.TOTP);\n\n if (!method || !method.verified) {\n throw new TwoFactorNotSetupError();\n }\n\n const backupCodesCount = this.config.twoFactor?.backupCodesCount || 10;\n const backupCodes = this.totpProvider.generateBackupCodes(backupCodesCount);\n const hashedBackupCodes = this.totpProvider.hashBackupCodes(backupCodes);\n\n await this.queries.updateTwoFactorMethod(method.id, {\n backup_codes: hashedBackupCodes,\n });\n\n return backupCodes;\n }\n\n async getContact(mechanism: TwoFactorMechanism.EMAIL | TwoFactorMechanism.SMS): Promise<string | null> {\n const accountId = this.getAccountId();\n\n if (!accountId) {\n return null;\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, mechanism);\n\n return method?.secret || null;\n }\n\n async getTotpUri(): Promise<string | null> {\n const accountId = this.getAccountId();\n const email = this.getEmail();\n\n if (!accountId || !email) {\n return null;\n }\n\n const method = await this.queries.findTwoFactorMethodByAccountAndMechanism(accountId, TwoFactorMechanism.TOTP);\n\n if (!method?.secret) {\n return null;\n }\n\n return this.totpProvider.generateQRCode(email, method.secret);\n }\n\n // challenge creation (used during login)\n\n async createChallenge(accountId: number): Promise<TwoFactorChallenge> {\n const methods = await this.queries.findTwoFactorMethodsByAccountId(accountId);\n const verifiedMethods = methods.filter((method) => method.verified);\n\n const challenge: TwoFactorChallenge = {\n selectors: {},\n };\n\n for (const method of verifiedMethods) {\n switch (method.mechanism) {\n case TwoFactorMechanism.TOTP:\n challenge.totp = true;\n break;\n\n case TwoFactorMechanism.EMAIL:\n if (method.secret) {\n const { otp, selector } = await this.otpProvider.createAndStoreOTP(accountId, method.mechanism);\n challenge.email = {\n otpValue: otp,\n maskedContact: this.otpProvider.maskEmail(method.secret),\n };\n challenge.selectors!.email = selector;\n }\n break;\n\n case TwoFactorMechanism.SMS:\n if (method.secret) {\n const { otp, selector } = await this.otpProvider.createAndStoreOTP(accountId, method.mechanism);\n challenge.sms = {\n otpValue: otp,\n maskedContact: this.otpProvider.maskPhone(method.secret),\n };\n challenge.selectors!.sms = selector;\n }\n break;\n }\n }\n\n return challenge;\n }\n}\n","import type { IncomingMessage } from \"http\";\nimport { hash } from \"@prsm/hash\";\nimport ms from \"@prsm/ms\";\nimport type { AuthConfig, AuthAccount, TokenCallback, AuthenticateRequestResult } from \"./types.js\";\nimport { AuthQueries } from \"./queries.js\";\nimport { validateEmail } from \"./util.js\";\nimport { EmailTakenError, InvalidPasswordError, UserNotFoundError, EmailNotVerifiedError, ResetDisabledError, TooManyResetsError, ResetNotFoundError, ResetExpiredError, InvalidTokenError } from \"./errors.js\";\nimport { AuthStatus } from \"./types.js\";\n\nfunction parseCookies(cookieHeader: string): Record<string, string> {\n const cookies: Record<string, string> = {};\n if (!cookieHeader) return cookies;\n\n for (const pair of cookieHeader.split(\";\")) {\n const idx = pair.indexOf(\"=\");\n if (idx === -1) continue;\n const key = pair.slice(0, idx).trim();\n const value = pair.slice(idx + 1).trim();\n if (key) cookies[key] = decodeURIComponent(value);\n }\n\n return cookies;\n}\n\nexport async function authenticateRequest(\n config: AuthConfig,\n req: IncomingMessage,\n sessionMiddleware?: (req: any, res: any, next: () => void) => void\n): Promise<AuthenticateRequestResult> {\n const queries = new AuthQueries(config);\n\n if (sessionMiddleware) {\n await new Promise<void>(resolve => {\n sessionMiddleware(req, {}, resolve);\n });\n }\n\n const session = (req as any).session;\n if (session?.auth?.loggedIn && session.auth.accountId) {\n const account = await queries.findAccountById(session.auth.accountId);\n if (account && account.status === AuthStatus.Normal) {\n return { account, source: \"session\" };\n }\n }\n\n const cookies = parseCookies(req.headers.cookie || \"\");\n const cookieName = config.rememberCookieName || \"remember_token\";\n const token = cookies[cookieName];\n\n if (!token) {\n return { account: null, source: null };\n }\n\n const remember = await queries.findRememberToken(token);\n if (!remember || new Date() > remember.expires) {\n return { account: null, source: null };\n }\n\n const account = await queries.findAccountById(remember.account_id);\n if (!account || account.status !== AuthStatus.Normal) {\n return { account: null, source: null };\n }\n\n return { account, source: \"remember\" };\n}\n\nfunction validatePassword(password: string, config: AuthConfig): void {\n const minLength = config.minPasswordLength || 8;\n const maxLength = config.maxPasswordLength || 64;\n\n if (typeof password !== \"string\") {\n throw new InvalidPasswordError();\n }\n\n if (password.length < minLength) {\n throw new InvalidPasswordError();\n }\n\n if (password.length > maxLength) {\n throw new InvalidPasswordError();\n }\n}\n\nfunction generateAutoUserId(): string {\n return crypto.randomUUID();\n}\n\nasync function findAccountByIdentifier(queries: AuthQueries, identifier: { accountId?: number; email?: string; userId?: string }): Promise<AuthAccount | null> {\n if (identifier.accountId !== undefined) {\n return await queries.findAccountById(identifier.accountId);\n } else if (identifier.email !== undefined) {\n return await queries.findAccountByEmail(identifier.email);\n } else if (identifier.userId !== undefined) {\n return await queries.findAccountByUserId(identifier.userId);\n }\n return null;\n}\n\nasync function createConfirmationToken(queries: AuthQueries, account: AuthAccount, email: string, callback: TokenCallback): Promise<void> {\n const token = hash.encode(email);\n const expires = new Date(Date.now() + 1000 * 60 * 60 * 24 * 7); // 1 week\n\n await queries.createConfirmation({\n accountId: account.id,\n token,\n email,\n expires,\n });\n\n if (callback) {\n callback(token);\n }\n}\n\nexport async function createUser(config: AuthConfig, credentials: { email: string; password: string }, userId?: string | number, callback?: TokenCallback): Promise<AuthAccount> {\n validateEmail(credentials.email);\n validatePassword(credentials.password, config);\n\n const queries = new AuthQueries(config);\n\n const existing = await queries.findAccountByEmail(credentials.email);\n if (existing) {\n throw new EmailTakenError();\n }\n\n const finalUserId = userId || generateAutoUserId();\n const hashedPassword = hash.encode(credentials.password);\n const verified = typeof callback !== \"function\";\n\n const account = await queries.createAccount({\n userId: finalUserId,\n email: credentials.email,\n password: hashedPassword,\n verified,\n status: AuthStatus.Normal,\n rolemask: 0,\n });\n\n if (!verified && callback) {\n await createConfirmationToken(queries, account, credentials.email, callback);\n }\n\n return account;\n}\n\nexport async function register(config: AuthConfig, email: string, password: string, userId?: string | number, callback?: TokenCallback): Promise<AuthAccount> {\n validateEmail(email);\n validatePassword(password, config);\n\n const queries = new AuthQueries(config);\n\n const existing = await queries.findAccountByEmail(email);\n if (existing) {\n throw new EmailTakenError();\n }\n\n const finalUserId = userId || generateAutoUserId();\n const hashedPassword = hash.encode(password);\n const verified = typeof callback !== \"function\";\n\n const account = await queries.createAccount({\n userId: finalUserId,\n email,\n password: hashedPassword,\n verified,\n status: AuthStatus.Normal,\n rolemask: 0,\n });\n\n if (!verified && callback) {\n await createConfirmationToken(queries, account, email, callback);\n }\n\n return account;\n}\n\nexport async function deleteUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n await queries.deleteAccount(account.id);\n}\n\nexport async function addRoleForUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n const rolemask = account.rolemask | role;\n await queries.updateAccount(account.id, { rolemask });\n}\n\nexport async function removeRoleForUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n const rolemask = account.rolemask & ~role;\n await queries.updateAccount(account.id, { rolemask });\n}\n\nexport async function hasRoleForUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }, role: number): Promise<boolean> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n return (account.rolemask & role) === role;\n}\n\nexport async function changePasswordForUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }, password: string): Promise<void> {\n validatePassword(password, config);\n\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n await queries.updateAccount(account.id, {\n password: hash.encode(password),\n });\n}\n\nexport async function setStatusForUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }, status: number): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n await queries.updateAccount(account.id, { status });\n}\n\nexport async function initiatePasswordResetForUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }, expiresAfter: string | number | null = null, callback?: TokenCallback): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n if (!account.verified) {\n throw new EmailNotVerifiedError();\n }\n\n const expiry = !expiresAfter ? ms(\"6h\") : ms(expiresAfter);\n const token = hash.encode(account.email);\n const expires = new Date(Date.now() + expiry);\n\n await queries.createResetToken({\n accountId: account.id,\n token,\n expires,\n });\n\n if (callback) {\n callback(token);\n }\n}\n\nexport async function resetPassword(config: AuthConfig, email: string, expiresAfter: string | number | null = null, maxOpenRequests: number | null = null, callback?: TokenCallback): Promise<void> {\n validateEmail(email);\n\n const expiry = !expiresAfter ? ms(\"6h\") : ms(expiresAfter);\n const maxRequests = maxOpenRequests === null ? 2 : Math.max(1, maxOpenRequests);\n\n const queries = new AuthQueries(config);\n const account = await queries.findAccountByEmail(email);\n\n if (!account || !account.verified) {\n throw new EmailNotVerifiedError();\n }\n\n if (!account.resettable) {\n throw new ResetDisabledError();\n }\n\n const openRequests = await queries.countActiveResetTokensForAccount(account.id);\n\n if (openRequests >= maxRequests) {\n throw new TooManyResetsError();\n }\n\n const token = hash.encode(email);\n const expires = new Date(Date.now() + expiry);\n\n await queries.createResetToken({\n accountId: account.id,\n token,\n expires,\n });\n\n if (callback) {\n callback(token);\n }\n}\n\nexport async function confirmResetPassword(config: AuthConfig, token: string, password: string): Promise<{ accountId: number; email: string }> {\n const queries = new AuthQueries(config);\n const reset = await queries.findResetToken(token);\n\n if (!reset) {\n throw new ResetNotFoundError();\n }\n\n if (new Date(reset.expires) < new Date()) {\n throw new ResetExpiredError();\n }\n\n const account = await queries.findAccountById(reset.account_id);\n if (!account) {\n throw new UserNotFoundError();\n }\n\n if (!account.resettable) {\n throw new ResetDisabledError();\n }\n\n validatePassword(password, config);\n\n if (!hash.verify(token, account.email)) {\n throw new InvalidTokenError();\n }\n\n await queries.updateAccount(account.id, {\n password: hash.encode(password),\n });\n\n await queries.deleteResetToken(token);\n\n return { accountId: account.id, email: account.email };\n}\n\nexport async function userExistsByEmail(config: AuthConfig, email: string): Promise<boolean> {\n validateEmail(email);\n\n const queries = new AuthQueries(config);\n const account = await queries.findAccountByEmail(email);\n\n return account !== null;\n}\n\nexport async function forceLogoutForUserBy(config: AuthConfig, identifier: { accountId?: number; email?: string; userId?: string }): Promise<{ accountId: number }> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n await queries.incrementForceLogout(account.id);\n\n return { accountId: account.id };\n}\n","import type { NextFunction, Request, Response } from \"express\";\nimport { AuthManager } from \"./auth-manager.js\";\nimport type { AuthConfig } from \"./types.js\";\n\nexport function createAuthMiddleware(config: AuthConfig) {\n return async (req: Request, res: Response, next: NextFunction) => {\n try {\n const authManager = new AuthManager(req, res, config);\n\n req.auth = authManager;\n\n // initialize session and process remember directive\n await authManager.resyncSession();\n await authManager.processRememberDirective();\n\n next();\n } catch (error) {\n next(error);\n }\n };\n}\n","import type { AuthConfig } from \"./types.js\";\n\nexport async function createAuthTables(config: AuthConfig): Promise<void> {\n const prefix = config.tablePrefix || \"user_\";\n const { db } = config;\n\n const accountsTable = `${prefix}accounts`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${accountsTable} (\n id SERIAL PRIMARY KEY,\n user_id VARCHAR(255) NOT NULL,\n email VARCHAR(255) NOT NULL UNIQUE,\n password VARCHAR(255),\n verified BOOLEAN DEFAULT FALSE,\n status INTEGER DEFAULT 0,\n rolemask INTEGER DEFAULT 0,\n last_login TIMESTAMPTZ,\n force_logout INTEGER DEFAULT 0,\n resettable BOOLEAN DEFAULT TRUE,\n registered TIMESTAMPTZ DEFAULT NOW(),\n CONSTRAINT ${prefix}unique_user_id_per_account UNIQUE(user_id)\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}accounts_user_id ON ${accountsTable}(user_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}accounts_email ON ${accountsTable}(email)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}accounts_status ON ${accountsTable}(status)`);\n\n const confirmationsTable = `${prefix}confirmations`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${confirmationsTable} (\n id SERIAL PRIMARY KEY,\n account_id INTEGER NOT NULL,\n token VARCHAR(255) NOT NULL,\n email VARCHAR(255) NOT NULL,\n expires TIMESTAMPTZ NOT NULL,\n CONSTRAINT fk_${prefix}confirmations_account \n FOREIGN KEY (account_id) REFERENCES ${accountsTable}(id) ON DELETE CASCADE\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}confirmations_token ON ${confirmationsTable}(token)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}confirmations_email ON ${confirmationsTable}(email)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}confirmations_account_id ON ${confirmationsTable}(account_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}confirmations_expires ON ${confirmationsTable}(expires)`);\n\n const remembersTable = `${prefix}remembers`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${remembersTable} (\n id SERIAL PRIMARY KEY,\n account_id INTEGER NOT NULL,\n token VARCHAR(255) NOT NULL,\n expires TIMESTAMPTZ NOT NULL,\n CONSTRAINT fk_${prefix}remembers_account \n FOREIGN KEY (account_id) REFERENCES ${accountsTable}(id) ON DELETE CASCADE\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}remembers_token ON ${remembersTable}(token)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}remembers_account_id ON ${remembersTable}(account_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}remembers_expires ON ${remembersTable}(expires)`);\n\n const resetsTable = `${prefix}resets`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${resetsTable} (\n id SERIAL PRIMARY KEY,\n account_id INTEGER NOT NULL,\n token VARCHAR(255) NOT NULL,\n expires TIMESTAMPTZ NOT NULL,\n CONSTRAINT fk_${prefix}resets_account \n FOREIGN KEY (account_id) REFERENCES ${accountsTable}(id) ON DELETE CASCADE\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}resets_token ON ${resetsTable}(token)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}resets_account_id ON ${resetsTable}(account_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}resets_expires ON ${resetsTable}(expires)`);\n\n const providersTable = `${prefix}providers`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${providersTable} (\n id SERIAL PRIMARY KEY,\n account_id INTEGER NOT NULL,\n provider VARCHAR(50) NOT NULL,\n provider_id VARCHAR(255) NOT NULL,\n provider_email VARCHAR(255),\n provider_username VARCHAR(255),\n provider_name VARCHAR(255),\n provider_avatar VARCHAR(500),\n created_at TIMESTAMPTZ DEFAULT NOW(),\n updated_at TIMESTAMPTZ DEFAULT NOW(),\n CONSTRAINT fk_${prefix}providers_account \n FOREIGN KEY (account_id) REFERENCES ${accountsTable}(id) ON DELETE CASCADE,\n CONSTRAINT ${prefix}unique_provider_identity \n UNIQUE(provider, provider_id)\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}providers_account_id ON ${providersTable}(account_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}providers_provider ON ${providersTable}(provider)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}providers_provider_id ON ${providersTable}(provider_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}providers_email ON ${providersTable}(provider_email)`);\n\n const activityTable = `${prefix}activity_log`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${activityTable} (\n id SERIAL PRIMARY KEY,\n account_id INTEGER,\n action VARCHAR(255) NOT NULL,\n ip_address INET,\n user_agent TEXT,\n browser VARCHAR(255),\n os VARCHAR(255),\n device VARCHAR(255),\n success BOOLEAN DEFAULT TRUE,\n metadata JSONB,\n created_at TIMESTAMPTZ DEFAULT NOW(),\n CONSTRAINT fk_${prefix}activity_log_account \n FOREIGN KEY (account_id) REFERENCES ${accountsTable}(id) ON DELETE CASCADE\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}activity_log_created_at ON ${activityTable}(created_at DESC)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}activity_log_account_id ON ${activityTable}(account_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}activity_log_action ON ${activityTable}(action)`);\n\n const twoFactorMethodsTable = `${prefix}2fa_methods`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${twoFactorMethodsTable} (\n id SERIAL PRIMARY KEY,\n account_id INTEGER NOT NULL,\n mechanism INTEGER NOT NULL,\n secret VARCHAR(255),\n backup_codes TEXT[],\n verified BOOLEAN DEFAULT FALSE,\n created_at TIMESTAMPTZ DEFAULT NOW(),\n last_used_at TIMESTAMPTZ,\n CONSTRAINT fk_${prefix}2fa_methods_account \n FOREIGN KEY (account_id) REFERENCES ${accountsTable}(id) ON DELETE CASCADE,\n CONSTRAINT ${prefix}unique_account_mechanism \n UNIQUE(account_id, mechanism)\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}2fa_methods_account_id ON ${twoFactorMethodsTable}(account_id)`);\n\n const twoFactorTokensTable = `${prefix}2fa_tokens`;\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${twoFactorTokensTable} (\n id SERIAL PRIMARY KEY,\n account_id INTEGER NOT NULL,\n mechanism INTEGER NOT NULL,\n selector VARCHAR(32) NOT NULL,\n token_hash VARCHAR(255) NOT NULL,\n expires_at TIMESTAMPTZ NOT NULL,\n created_at TIMESTAMPTZ DEFAULT NOW(),\n CONSTRAINT fk_${prefix}2fa_tokens_account \n FOREIGN KEY (account_id) REFERENCES ${accountsTable}(id) ON DELETE CASCADE\n )\n `);\n\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}2fa_tokens_selector ON ${twoFactorTokensTable}(selector)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}2fa_tokens_account_id ON ${twoFactorTokensTable}(account_id)`);\n await db.query(`CREATE INDEX IF NOT EXISTS idx_${prefix}2fa_tokens_expires ON ${twoFactorTokensTable}(expires_at)`);\n}\n\nexport async function dropAuthTables(config: AuthConfig): Promise<void> {\n const prefix = config.tablePrefix || \"user_\";\n const { db } = config;\n\n await db.query(`DROP TABLE IF EXISTS ${prefix}2fa_tokens CASCADE`);\n await db.query(`DROP TABLE IF EXISTS ${prefix}2fa_methods CASCADE`);\n await db.query(`DROP TABLE IF EXISTS ${prefix}activity_log CASCADE`);\n await db.query(`DROP TABLE IF EXISTS ${prefix}providers CASCADE`);\n await db.query(`DROP TABLE IF EXISTS ${prefix}resets CASCADE`);\n await db.query(`DROP TABLE IF EXISTS ${prefix}remembers CASCADE`);\n await db.query(`DROP TABLE IF EXISTS ${prefix}confirmations CASCADE`);\n await db.query(`DROP TABLE IF EXISTS ${prefix}accounts CASCADE`);\n}\n\nexport async function cleanupExpiredTokens(config: AuthConfig): Promise<void> {\n const prefix = config.tablePrefix || \"user_\";\n const { db } = config;\n\n await db.query(`DELETE FROM ${prefix}confirmations WHERE expires < NOW()`);\n await db.query(`DELETE FROM ${prefix}remembers WHERE expires < NOW()`);\n await db.query(`DELETE FROM ${prefix}resets WHERE expires < NOW()`);\n await db.query(`DELETE FROM ${prefix}2fa_tokens WHERE expires_at < NOW()`);\n}\n\nexport async function getAuthTableStats(config: AuthConfig): Promise<{\n accounts: number;\n providers: number;\n confirmations: number;\n remembers: number;\n resets: number;\n twoFactorMethods: number;\n twoFactorTokens: number;\n expiredConfirmations: number;\n expiredRemembers: number;\n expiredResets: number;\n expiredTwoFactorTokens: number;\n}> {\n const prefix = config.tablePrefix || \"user_\";\n const { db } = config;\n\n const [accountsResult, providersResult, confirmationsResult, remembersResult, resetsResult, twoFactorMethodsResult, twoFactorTokensResult, expiredConfirmationsResult, expiredRemembersResult, expiredResetsResult, expiredTwoFactorTokensResult] =\n await Promise.all([\n db.query(`SELECT COUNT(*) as count FROM ${prefix}accounts`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}providers`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}confirmations`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}remembers`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}resets`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}2fa_methods`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}2fa_tokens`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}confirmations WHERE expires < NOW()`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}remembers WHERE expires < NOW()`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}resets WHERE expires < NOW()`),\n db.query(`SELECT COUNT(*) as count FROM ${prefix}2fa_tokens WHERE expires_at < NOW()`),\n ]);\n\n return {\n accounts: parseInt(accountsResult.rows[0]?.count || \"0\"),\n providers: parseInt(providersResult.rows[0]?.count || \"0\"),\n confirmations: parseInt(confirmationsResult.rows[0]?.count || \"0\"),\n remembers: parseInt(remembersResult.rows[0]?.count || \"0\"),\n resets: parseInt(resetsResult.rows[0]?.count || \"0\"),\n twoFactorMethods: parseInt(twoFactorMethodsResult.rows[0]?.count || \"0\"),\n twoFactorTokens: parseInt(twoFactorTokensResult.rows[0]?.count || \"0\"),\n expiredConfirmations: parseInt(expiredConfirmationsResult.rows[0]?.count || \"0\"),\n expiredRemembers: parseInt(expiredRemembersResult.rows[0]?.count || \"0\"),\n expiredResets: parseInt(expiredResetsResult.rows[0]?.count || \"0\"),\n expiredTwoFactorTokens: parseInt(expiredTwoFactorTokensResult.rows[0]?.count || \"0\"),\n };\n}\n","import type { AuthConfig, TokenCallback, AuthAccount } from \"./types.js\";\nimport * as authFunctions from \"./auth-functions.js\";\n\nexport interface AuthContext {\n createUser: (credentials: { email: string; password: string }, userId?: string | number, callback?: TokenCallback) => Promise<AuthAccount>;\n register: (email: string, password: string, userId?: string | number, callback?: TokenCallback) => Promise<AuthAccount>;\n deleteUserBy: (identifier: { accountId?: number; email?: string; userId?: string }) => Promise<void>;\n addRoleForUserBy: (identifier: { accountId?: number; email?: string; userId?: string }, role: number) => Promise<void>;\n removeRoleForUserBy: (identifier: { accountId?: number; email?: string; userId?: string }, role: number) => Promise<void>;\n hasRoleForUserBy: (identifier: { accountId?: number; email?: string; userId?: string }, role: number) => Promise<boolean>;\n changePasswordForUserBy: (identifier: { accountId?: number; email?: string; userId?: string }, password: string) => Promise<void>;\n setStatusForUserBy: (identifier: { accountId?: number; email?: string; userId?: string }, status: number) => Promise<void>;\n initiatePasswordResetForUserBy: (identifier: { accountId?: number; email?: string; userId?: string }, expiresAfter?: string | number | null, callback?: TokenCallback) => Promise<void>;\n resetPassword: (email: string, expiresAfter?: string | number | null, maxOpenRequests?: number | null, callback?: TokenCallback) => Promise<void>;\n confirmResetPassword: (token: string, password: string) => Promise<{ accountId: number; email: string }>;\n userExistsByEmail: (email: string) => Promise<boolean>;\n forceLogoutForUserBy: (identifier: { accountId?: number; email?: string; userId?: string }) => Promise<{ accountId: number }>;\n}\n\nexport function createAuthContext(config: AuthConfig): AuthContext {\n return {\n createUser: (credentials, userId?, callback?) => authFunctions.createUser(config, credentials, userId, callback),\n register: (email, password, userId?, callback?) => authFunctions.register(config, email, password, userId, callback),\n deleteUserBy: (identifier) => authFunctions.deleteUserBy(config, identifier),\n addRoleForUserBy: (identifier, role) => authFunctions.addRoleForUserBy(config, identifier, role),\n removeRoleForUserBy: (identifier, role) => authFunctions.removeRoleForUserBy(config, identifier, role),\n hasRoleForUserBy: (identifier, role) => authFunctions.hasRoleForUserBy(config, identifier, role),\n changePasswordForUserBy: (identifier, password) => authFunctions.changePasswordForUserBy(config, identifier, password),\n setStatusForUserBy: (identifier, status) => authFunctions.setStatusForUserBy(config, identifier, status),\n initiatePasswordResetForUserBy: (identifier, expiresAfter?, callback?) => authFunctions.initiatePasswordResetForUserBy(config, identifier, expiresAfter, callback),\n resetPassword: (email, expiresAfter?, maxOpenRequests?, callback?) => authFunctions.resetPassword(config, email, expiresAfter, maxOpenRequests, callback),\n confirmResetPassword: (token, password) => authFunctions.confirmResetPassword(config, token, password),\n userExistsByEmail: (email) => authFunctions.userExistsByEmail(config, email),\n forceLogoutForUserBy: (identifier) => authFunctions.forceLogoutForUserBy(config, identifier),\n };\n}\n","import type { AuthConfig, AuthAccount } from \"./types.js\";\nimport { AuthQueries } from \"./queries.js\";\nimport { UserNotFoundError } from \"./errors.js\";\n\nexport type UserIdentifier = {\n accountId?: number;\n email?: string;\n userId?: string;\n};\n\nasync function findAccountByIdentifier(queries: AuthQueries, identifier: UserIdentifier): Promise<AuthAccount> {\n let account: AuthAccount | null = null;\n\n if (identifier.accountId !== undefined) {\n account = await queries.findAccountById(identifier.accountId);\n } else if (identifier.email !== undefined) {\n account = await queries.findAccountByEmail(identifier.email);\n } else if (identifier.userId !== undefined) {\n account = await queries.findAccountByUserId(identifier.userId);\n }\n\n if (!account) {\n throw new UserNotFoundError();\n }\n\n return account;\n}\n\n/**\n * Add a role to a user's account.\n * Uses bitwise OR to add role to existing rolemask.\n *\n * @param config - Auth configuration containing database connection\n * @param identifier - Find user by accountId, email, or userId\n * @param role - Role bitmask to add (e.g., AuthRole.Admin)\n * @throws {UserNotFoundError} No account matches the identifier\n */\nexport async function addRoleToUser(config: AuthConfig, identifier: UserIdentifier, role: number): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n \n const rolemask = account.rolemask | role;\n await queries.updateAccount(account.id, { rolemask });\n}\n\n/**\n * Remove a role from a user's account.\n * Uses bitwise operations to remove role from rolemask.\n *\n * @param config - Auth configuration containing database connection\n * @param identifier - Find user by accountId, email, or userId\n * @param role - Role bitmask to remove (e.g., AuthRole.Admin)\n * @throws {UserNotFoundError} No account matches the identifier\n */\nexport async function removeRoleFromUser(config: AuthConfig, identifier: UserIdentifier, role: number): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n \n const rolemask = account.rolemask & ~role;\n await queries.updateAccount(account.id, { rolemask });\n}\n\n/**\n * Set a user's complete role mask, replacing any existing roles.\n *\n * @param config - Auth configuration containing database connection\n * @param identifier - Find user by accountId, email, or userId\n * @param rolemask - Complete role bitmask to set\n * @throws {UserNotFoundError} No account matches the identifier\n */\nexport async function setUserRoles(config: AuthConfig, identifier: UserIdentifier, rolemask: number): Promise<void> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n \n await queries.updateAccount(account.id, { rolemask });\n}\n\n/**\n * Get a user's current role mask.\n *\n * @param config - Auth configuration containing database connection\n * @param identifier - Find user by accountId, email, or userId\n * @returns The user's current role bitmask\n * @throws {UserNotFoundError} No account matches the identifier\n */\nexport async function getUserRoles(config: AuthConfig, identifier: UserIdentifier): Promise<number> {\n const queries = new AuthQueries(config);\n const account = await findAccountByIdentifier(queries, identifier);\n \n return account.rolemask;\n}"],"mappings":"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","names":["import_hash","import_ms","TwoFactorMechanism","Bowser","account","Otp","import_hash","ms","import_hash","import_ms","account","ms","ms","err","findAccountByIdentifier"]}
|