Files
pedwfrontend/lib/cookies.js
T

120 lines
3.3 KiB
JavaScript

import * as cookie from "cookie";
import setCookieParser from "set-cookie-parser";
const isBrowser = () => typeof window !== "undefined";
const createCookie = (name, value, options) => {
let sameSite = options.sameSite;
if (sameSite === true) {
sameSite = "strict";
}
if (sameSite === undefined || sameSite === false) {
sameSite = "lax";
}
const cookieToSet = { ...options, sameSite };
delete cookieToSet.encode;
return { name, value, ...cookieToSet };
};
const hasSameProperties = (firstCookie, secondCookie) => {
const firstProperties = Object.getOwnPropertyNames(firstCookie);
const secondProperties = Object.getOwnPropertyNames(secondCookie);
if (firstProperties.length !== secondProperties.length) {
return false;
}
return firstProperties.every(
(propertyName) =>
firstCookie[propertyName] === secondCookie[propertyName]
);
};
const areCookiesEqual = (firstCookie, secondCookie) => {
let sameSiteMatches = firstCookie.sameSite === secondCookie.sameSite;
if (
typeof firstCookie.sameSite === "string" &&
typeof secondCookie.sameSite === "string"
) {
sameSiteMatches =
firstCookie.sameSite.toLowerCase() ===
secondCookie.sameSite.toLowerCase();
}
return (
hasSameProperties(
{ ...firstCookie, sameSite: undefined },
{ ...secondCookie, sameSite: undefined }
) && sameSiteMatches
);
};
export const parseCookies = (ctx, options) => {
if (ctx?.req?.headers?.cookie) {
return cookie.parse(ctx.req.headers.cookie, options);
}
if (isBrowser()) {
return cookie.parse(document.cookie, options);
}
return {};
};
export const setCookie = (ctx, name, value, options = {}) => {
if (ctx?.res?.getHeader && ctx.res.setHeader) {
if (ctx?.res?.finished) {
console.warn(`Not setting "${name}" cookie. Response has finished.`);
console.warn("You should set cookie before res.send()");
return {};
}
let cookies = ctx.res.getHeader("Set-Cookie") || [];
if (typeof cookies === "string") {
cookies = [cookies];
}
if (typeof cookies === "number") {
cookies = [];
}
const parsedCookies = setCookieParser.parse(cookies, {
decodeValues: false
});
const newCookie = createCookie(name, value, options);
const cookiesToSet = [];
parsedCookies.forEach((parsedCookie) => {
if (!areCookiesEqual(parsedCookie, newCookie)) {
cookiesToSet.push(
cookie.serialize(parsedCookie.name, parsedCookie.value, {
encode: (cookieValue) => cookieValue,
...parsedCookie
})
);
}
});
cookiesToSet.push(cookie.serialize(name, value, options));
ctx.res.setHeader("Set-Cookie", cookiesToSet);
}
if (isBrowser()) {
if (options?.httpOnly) {
throw new Error("Can not set a httpOnly cookie in the browser.");
}
document.cookie = cookie.serialize(name, value, options);
}
return {};
};
export const destroyCookie = (ctx, name, options) =>
setCookie(ctx, name, "", { ...(options || {}), maxAge: -1 });