auth.ts
1/** Checks HTTP basic auth against the AUTH_USER / AUTH_PASS secrets. Fails closed if unset. */
2export async function isAuthorized(req: Request, env: Env): Promise<boolean> {
3 if (!env.AUTH_USER || !env.AUTH_PASS) return false;
4 const header = req.headers.get("authorization") ?? "";
5 const match = header.match(/^Basic\s+(.+)$/i);
6 if (!match) return false;
7 let supplied: string;
8 try {
9 supplied = atob(match[1]);
10 } catch {
11 return false;
12 }
13 // Compare fixed-length digests so timingSafeEqual never sees mismatched lengths.
14 const [a, b] = await Promise.all([digest(supplied), digest(`${env.AUTH_USER}:${env.AUTH_PASS}`)]);
15 return crypto.subtle.timingSafeEqual(a, b);
16}
17
18async function digest(s: string): Promise<ArrayBuffer> {
19 return crypto.subtle.digest("SHA-256", new TextEncoder().encode(s));
20}
21
22export function unauthorized(): Response {
23 return new Response("Authentication required", {
24 status: 401,
25 headers: { "www-authenticate": 'Basic realm="monitor", charset="UTF-8"' },
26 });
27}