kequapp
Version:
DEPRECATED: renamed to @kequtech/arbor
62 lines (61 loc) • 2.04 kB
JavaScript
import { Ex } from "../ex.js";
export function createCookies(req, res) {
const result = {};
let values;
function get(key) {
setup();
return values[key];
}
function set(key, value, options) {
setup();
validateCookieName(key);
result[key] = buildAttrs(key, value, options);
values[key] = value;
res.setHeader('Set-Cookie', Object.values(result));
}
function remove(key) {
setup();
set(key, '', { maxAge: 0 });
delete values[key];
}
function setup() {
if (values === undefined)
values = parseCookieHeader(req.headers.cookie);
}
return { get, set, remove };
}
function buildAttrs(key, value, options) {
const attrs = [`${key}=${encodeURIComponent(value)}`, 'Path=/'];
if (options?.domain !== undefined)
attrs.push(`Domain=${options.domain}`);
if (options?.expires !== undefined)
attrs.push(`Expires=${options.expires.toUTCString()}`);
if (options?.maxAge !== undefined)
attrs.push(`Max-Age=${Math.max(Math.floor(options.maxAge), 0)}`);
if (options?.secure === true || options?.sameSite === 'None')
attrs.push('Secure');
if (options?.httpOnly)
attrs.push('HttpOnly');
if (options?.sameSite !== undefined)
attrs.push(`SameSite=${options.sameSite}`);
return attrs.join('; ');
}
function parseCookieHeader(cookie) {
const result = {};
if (cookie !== undefined) {
for (const part of cookie.split(/; */)) {
const i = part.indexOf('=');
const key = i >= 0 ? part.slice(0, i).trim() : part.trim();
const value = i >= 0 ? part.slice(i + 1).trim() : '';
if (key) {
result[key] = decodeURIComponent(value);
}
}
}
return result;
}
function validateCookieName(name) {
if (!/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/.test(name)) {
throw Ex.InternalServerError(`Cookie name contains invalid characters: ${name}`);
}
}