// Per-route admin guard for mutating endpoints. // // Reads the panel's simple shared password from ADMIN_PASSWORD. GETs are // always public (stats dashboard + list views), so the gate only applies to // the handlers that accept it via `beforeHandle: requireAdmin`. // // If ADMIN_PASSWORD is empty, the gate is a no-op — useful for localhost-only // deployments. import { env } from '../lib/env'; type AuthCtx = { request: Request; set: { status?: number | string; headers: Record; }; }; export function requireAdmin({ request, set }: AuthCtx): string | undefined { if (!env.ADMIN_PASSWORD) return; const header = request.headers.get('authorization') ?? ''; if (header.startsWith('Basic ')) { const decoded = Buffer.from( header.slice('Basic '.length), 'base64' ).toString('utf8'); const idx = decoded.indexOf(':'); if (idx >= 0) { const pwd = decoded.slice(idx + 1); if (pwd === env.ADMIN_PASSWORD) return; } } set.status = 401; set.headers['www-authenticate'] = 'Basic realm="safekeeper"'; return 'authentication required'; } // True when the request is already authenticated. Cheap to call — used by // views that want to hide admin controls from anonymous visitors. export function isAuthed(request: Request): boolean { if (!env.ADMIN_PASSWORD) return true; const header = request.headers.get('authorization') ?? ''; if (!header.startsWith('Basic ')) return false; const decoded = Buffer.from( header.slice('Basic '.length), 'base64' ).toString('utf8'); const idx = decoded.indexOf(':'); if (idx < 0) return false; return decoded.slice(idx + 1) === env.ADMIN_PASSWORD; }