79 lines
2.0 KiB
JavaScript
79 lines
2.0 KiB
JavaScript
const SESSION_COOKIE = "coaching_session";
|
|
|
|
function parseCookieHeader(header) {
|
|
const cookies = {};
|
|
|
|
for (const part of String(header || "").split(";")) {
|
|
const separator = part.indexOf("=");
|
|
if (separator === -1) continue;
|
|
const name = part.slice(0, separator).trim();
|
|
const value = part.slice(separator + 1).trim();
|
|
if (name) cookies[name] = decodeURIComponent(value);
|
|
}
|
|
|
|
return cookies;
|
|
}
|
|
|
|
function sessionTokenFromRequest(req) {
|
|
return parseCookieHeader(req.headers?.cookie)[SESSION_COOKIE] || null;
|
|
}
|
|
|
|
function cookieOptions() {
|
|
return {
|
|
httpOnly: true,
|
|
secure: process.env.NODE_ENV === "production" || process.env.NODE_ENV === "dev_stage",
|
|
sameSite: "lax",
|
|
path: "/",
|
|
};
|
|
}
|
|
|
|
function setSessionCookie(req, res, token) {
|
|
res.cookie(SESSION_COOKIE, token, { ...cookieOptions(), maxAge: 30 * 60 * 1000 });
|
|
}
|
|
|
|
function clearSessionCookie(req, res) {
|
|
res.clearCookie(SESSION_COOKIE, cookieOptions());
|
|
}
|
|
|
|
function requestOrigin(req) {
|
|
const origin = req.get("origin");
|
|
if (origin) return origin;
|
|
const referer = req.get("referer");
|
|
return referer ? new URL(referer).origin : null;
|
|
}
|
|
|
|
function expectedOrigin(req) {
|
|
const protocol = req.get("x-forwarded-proto") || req.protocol;
|
|
const host = req.get("x-forwarded-host") || req.get("host");
|
|
return `${protocol}://${host}`;
|
|
}
|
|
|
|
function protectCookieMutations(req, res, next) {
|
|
if (["GET", "HEAD", "OPTIONS"].includes(req.method)) {
|
|
next();
|
|
return;
|
|
}
|
|
|
|
if (req.get("authorization") || !sessionTokenFromRequest(req)) {
|
|
next();
|
|
return;
|
|
}
|
|
|
|
let origin;
|
|
try {
|
|
origin = requestOrigin(req);
|
|
} catch {
|
|
res.status(403).send({ error: "csrf_origin_invalid" });
|
|
return;
|
|
}
|
|
|
|
if (!origin || origin !== expectedOrigin(req)) {
|
|
res.status(403).send({ error: "csrf_origin_invalid" });
|
|
return;
|
|
}
|
|
|
|
next();
|
|
}
|
|
|
|
module.exports = { SESSION_COOKIE, parseCookieHeader, sessionTokenFromRequest, setSessionCookie, clearSessionCookie, protectCookieMutations };
|