File size: 984 Bytes
416bdd1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import { createHash, timingSafeEqual } from "node:crypto";
/**
* Checks `Authorization: Bearer $ADMIN_TOKEN`. Returns "disabled" when no token is
* configured so the admin routes can answer 404 and stay invisible.
*/
export function checkAdmin(request: Request): "ok" | "denied" | "disabled" {
const expected = process.env.ADMIN_TOKEN;
if (!expected) return "disabled";
const header = request.headers.get("authorization") ?? "";
const provided = header.startsWith("Bearer ") ? header.slice(7) : "";
// Hash both sides so the comparison has equal length and does not leak it.
const a = createHash("sha256").update(provided).digest();
const b = createHash("sha256").update(expected).digest();
return timingSafeEqual(a, b) ? "ok" : "denied";
}
export function adminDenied(result: "denied" | "disabled") {
return result === "disabled"
? Response.json({ error: "Not found." }, { status: 404 })
: Response.json({ error: "Unauthorized." }, { status: 401 });
}
|