import { Request, Response, NextFunction } from 'express' import { prisma } from '../lib/prisma' import { AdminRole } from '@rentaldrivego/database' import { getAuthToken, sendUnauthorized, sendForbidden } from './authHelpers' import { verifyActorToken } from '../security/tokens' import { getSessionCookieName } from '../security/sessionCookies' const ADMIN_ROLE_ALLOWLIST: Record = { SUPER_ADMIN: ['SUPER_ADMIN'], ADMIN: ['SUPER_ADMIN', 'ADMIN'], SUPPORT: ['SUPER_ADMIN', 'ADMIN', 'SUPPORT'], FINANCE: ['SUPER_ADMIN', 'ADMIN', 'FINANCE'], VIEWER: ['SUPER_ADMIN', 'ADMIN', 'SUPPORT', 'FINANCE', 'VIEWER'], } const ADMIN_2FA_ENROLLMENT_EXEMPT_PATHS = new Set([ '/auth/me', '/auth/logout', '/auth/2fa/setup', '/auth/2fa/verify', ]) function is2faEnrollmentExempt(req: Request) { return ADMIN_2FA_ENROLLMENT_EXEMPT_PATHS.has(req.path) } /** * Requires a valid admin session token. * * Guarantees on success: * req.admin — the full AdminUser record */ export async function requireAdminAuth(req: Request, res: Response, next: NextFunction) { const token = getAuthToken(req, getSessionCookieName('admin')) if (!token) return sendUnauthorized(res, 'unauthenticated', 'Admin authentication required') let payload: { sub: string; type: string; last2faAt?: number } try { payload = verifyActorToken(token, 'admin') } catch { return sendUnauthorized(res, 'invalid_token', 'Invalid or expired admin token') } const admin = await prisma.adminUser.findUnique({ where: { id: payload.sub } }) if (!admin || !admin.isActive) { return sendUnauthorized(res, 'unauthenticated', 'Admin account not found or deactivated') } if (!admin.totpEnabled && !is2faEnrollmentExempt(req)) { return sendForbidden(res, 'admin_2fa_required', 'Admin 2FA enrollment is required before using privileged admin routes') } req.admin = admin req.adminAuthLast2faAt = typeof payload.last2faAt === 'number' ? payload.last2faAt : undefined next() } /** * Requires the authenticated admin to have at least `minimumRole`. * Must be applied after `requireAdminAuth`. */ export function requireAdminRole(minimumRole: AdminRole) { return (req: Request, res: Response, next: NextFunction) => { const admin = req.admin if (!admin) return sendUnauthorized(res, 'unauthenticated', 'Admin authentication required') const allowedRoles = ADMIN_ROLE_ALLOWLIST[minimumRole] ?? [] if (!allowedRoles.includes(admin.role)) { return sendForbidden(res, 'forbidden', `This action requires explicit ${minimumRole} permission`) } next() } } export function requireFreshAdmin2FA(req: Request, res: Response, next: NextFunction) { const admin = req.admin if (!admin) return sendUnauthorized(res, 'unauthenticated', 'Admin authentication required') if (!admin.totpEnabled) { return sendForbidden(res, 'admin_2fa_required', 'Admin 2FA enrollment is required for this action') } if (!req.adminAuthLast2faAt) { return sendForbidden(res, 'fresh_2fa_required', 'Admin 2FA verification is required for this session') } next() } export function requireFreshAdmin2FAWhenEnabled(req: Request, res: Response, next: NextFunction) { const admin = req.admin if (!admin) return sendUnauthorized(res, 'unauthenticated', 'Admin authentication required') if (!admin.totpEnabled) return next() return requireFreshAdmin2FA(req, res, next) }