145 lines
3.4 KiB
TypeScript
145 lines
3.4 KiB
TypeScript
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), interest-cohort=()");
|
|
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");
|
|
response.headers.set("X-XSS-Protection", "1; mode=block");
|
|
|
|
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,
|
|
];
|