import { NextRequest, NextResponse } from 'next/server'; import { PrismaClient, Curator } from '@prisma/client'; const prisma = new PrismaClient(); export type StaffContext = | { role: 'admin' } | { role: 'curator'; curator: Curator }; /** * Authentication middleware for admin API routes * Verifies that the request includes a valid admin session token */ export async function requireAdminAuth(request: NextRequest): Promise { const authHeader = request.headers.get('x-admin-auth'); if (!authHeader || authHeader !== 'authenticated') { return NextResponse.json( { error: 'Unauthorized - Admin authentication required' }, { status: 401 } ); } return null; // Auth successful } /** * Resolve current staff (admin or curator) from headers. * * Admin: * - x-admin-auth: 'authenticated' * * Curator: * - x-curator-auth: 'authenticated' * - x-curator-username: */ export async function getStaffContext(request: NextRequest): Promise { const adminHeader = request.headers.get('x-admin-auth'); if (adminHeader === 'authenticated') { return { role: 'admin' }; } const curatorAuth = request.headers.get('x-curator-auth'); const curatorUsername = request.headers.get('x-curator-username'); if (curatorAuth === 'authenticated' && curatorUsername) { const curator = await prisma.curator.findUnique({ where: { username: curatorUsername }, }); if (curator) { return { role: 'curator', curator }; } } return null; } /** * Require that the current request is authenticated as staff (admin or curator). * Returns either an error response or a resolved context. */ export async function requireStaffAuth(request: NextRequest): Promise<{ error?: NextResponse; context?: StaffContext }> { const context = await getStaffContext(request); if (!context) { return { error: NextResponse.json( { error: 'Unauthorized - Staff authentication required' }, { status: 401 } ), }; } return { context }; } /** * Helper to verify admin password */ export async function verifyAdminPassword(password: string): Promise { const bcrypt = await import('bcryptjs'); // Validate that ADMIN_PASSWORD is set (security best practice) if (!process.env.ADMIN_PASSWORD) { console.error('SECURITY WARNING: ADMIN_PASSWORD environment variable is not set!'); // Fallback to default hash only in development if (process.env.NODE_ENV === 'production') { throw new Error('ADMIN_PASSWORD environment variable is required in production'); } } const adminPasswordHash = process.env.ADMIN_PASSWORD || '$2b$10$SHOt9G1qUNIvHoWre7499.eEtp5PtOII0daOQGNV.dhDEuPmOUdsq'; return bcrypt.compare(password, adminPasswordHash); }