/** * Auth for the internal staff routes (/staff/report, /api/staff/report, * /api/staff/file). * * Preferred: signed, org-bound, expiring tokens minted by the CiviCRM * extension — /staff/report?org=&exp=&sig=. See * lib/staff-token.mjs. The extension only mints a token after checking the * Civi user can view that org, so Civi ACLs carry through. * * Legacy (transitional): ?key=. Still accepted so the app * can deploy before the updated extension reaches the Civi server. Remove * the legacy branch once every Civi install emits signed tokens. * * If STAFF_REPORT_KEY is unset, every request is refused (closed by * default). Stub mode (CIVI_* unset) does NOT bypass this check — for local * dev, set STAFF_REPORT_KEY=dev in .env.local. */ import { safeEqual, verifyStaffToken } from "./staff-token.mjs"; interface StaffAuthParams { org: string | null | undefined; exp?: string | null; sig?: string | null; key?: string | null; } /** * Validate staff credentials for `org`. Returns the query-string fragment * (without `org`) that downstream fetches and file links must carry, or * null when unauthorized. */ export function staffAuthQuery({ org, exp, sig, key }: StaffAuthParams): string | null { const secret = process.env.STAFF_REPORT_KEY; if (!secret) return null; if (exp || sig) { return verifyStaffToken(secret, org, exp, sig) ? `exp=${encodeURIComponent(exp!)}&sig=${encodeURIComponent(sig!)}` : null; } if (key && safeEqual(key, secret)) { console.warn("[staff-auth] legacy ?key= access used; update the CiviCRM extension to signed tokens"); return `key=${encodeURIComponent(key)}`; } return null; }