async function constructHTML(context: RequestContext) { const { pathname } = new URL(context.request.url); if (pathname.startsWith("/api/")) return await context.next(); if ( pathname.startsWith("/assets/") || ["/app.webmanifest", "/favicon.ico", "/robots.txt"].includes(pathname) || pathname.startsWith("/files/") ) return await context.env.ASSETS.fetch(context.request); return await context.next(); } async function generateTokenHash(token: string) { const hash = await crypto.subtle.digest( "SHA-512", new TextEncoder().encode(token), ); return btoa(String.fromCharCode(...new Uint8Array(hash))) .replace(/\+/g, "-") .replace(/\//g, "_") .replace(/=/g, ""); } async function setAuth(context: RequestContext) { const cookies = context.request.headers.get("cookie"); if (!cookies) return await context.next(); const cookieList = cookies.split(/; /); for (const c of cookieList) { const [name, value] = c.split("="); if (name !== "_s") continue; const userData = await context.env.DATA.get( `auth_${await generateTokenHash(value)}`, ); if (userData) context.data.current_user = JSON.parse(userData); else context.request.headers.append( "set-cookie", "_s=; HttpOnly; Max-Age=0; Path=/; Secure;", ); break; } return await context.next(); } async function setBody(context: RequestContext) { if ( context.request.method === "POST" && !context.request.url.endsWith("/api/infractions/new") ) { if (context.request.headers.get("content-type") !== "application/json") return new Response('{"error":"Invalid content-type"}', { headers: { "content-type": "application/json", }, status: 400, }); let body: { [k: string]: any }; try { body = await context.request.json(); } catch { return new Response('{"error":"Invalid JSON"}', { headers: { "content-type": "application/json", }, status: 400, }); } context.data.body = body; } return await context.next(); } async function setHeaders(context: RequestContext) { const response = await context.next(); const rtvValues = [ "Aldaria", "Altadena", "DEMA", "Dragonborn", "Heaven, Iowa", "Hollywood", "Parkway East", "Parkway North", "Parkway West", "Tokyo", "Wintervale", ]; response.headers.set("Permissions-Policy", "clipboard-write=(self)"); response.headers.set("Referrer-Policy", "same-origin"); response.headers.set( "RTV", rtvValues[Math.round(Math.random() * (rtvValues.length - 1))], ); response.headers.set("X-Frame-Options", "SAMEORIGIN"); return response; } async function setTheme(context: RequestContext) { const cookies = context.request.headers.get("cookie"); if (!cookies) { context.data.theme = "dark"; return await context.next(); } const cookieList = cookies.split("; "); const themeCookie = cookieList.find((c) => c.startsWith("chakra-ui-color-mode"), ); const theme = themeCookie?.split("=").at(1); if (!theme || !["dark", "light"].includes(theme)) context.data.theme = "dark"; else context.data.theme = theme; return await context.next(); } export const onRequest = [ setAuth, setTheme, constructHTML, setBody, setHeaders, ];