Replaces the in-memory studentSessions/adminSessions Maps (Phase 2B — gone on every restart) with a sessions table. Browser holds an opaque CSPRNG bearer token; only its SHA-256 hash is ever stored server-side, same principle as password hashing. Each session has an absolute expiry (fixed at creation) and a sliding idle expiry (pushed forward on every authenticated request, capped at the absolute one) — one atomic UPDATE...RETURNING per resolve, no read-then-write race. Student and instructor sessions stay fully separate token namespaces, matching Phase 2B's cookie-name separation. cookies.js centralizes Set-Cookie construction so the Secure attribute (COOKIE_SECURE=1, for real HTTPS deployments) is applied consistently instead of hand-built per call site.
22 lines
878 B
JavaScript
22 lines
878 B
JavaScript
// Cookie construction, centralized so the Secure attribute is set consistently everywhere
|
|
// instead of hand-built per call site. Secure is opt-in via COOKIE_SECURE=1 — off by default
|
|
// because local dev and the current single-VM pilot deployment run over plain HTTP; anything
|
|
// served over real HTTPS should set COOKIE_SECURE=1 (see docs/PHASE3A... "production HTTPS
|
|
// expectations").
|
|
|
|
const SECURE = process.env.COOKIE_SECURE === '1';
|
|
|
|
function buildCookie(name, value, { maxAgeSec, httpOnly = true } = {}) {
|
|
const parts = [`${name}=${value}`, 'Path=/', 'SameSite=Lax'];
|
|
if (httpOnly) parts.push('HttpOnly');
|
|
if (SECURE) parts.push('Secure');
|
|
parts.push(`Max-Age=${maxAgeSec != null ? maxAgeSec : 0}`);
|
|
return parts.join('; ');
|
|
}
|
|
|
|
function clearCookie(name) {
|
|
return buildCookie(name, '', { maxAgeSec: 0 });
|
|
}
|
|
|
|
module.exports = { buildCookie, clearCookie };
|