import crypto from 'node:crypto'; const ONE_DAY_SECONDS = 60 * 60 * 24; const SEVEN_DAYS_SECONDS = ONE_DAY_SECONDS * 7; export const COOKIE_NAMES = { sid: 'pdx_sid', csrf: 'pdx_csrf' }; export function getCookieSecurityConfig(config) { const deploymentTarget = config?.deploymentTarget || process.env.DEPLOYMENT_TARGET; const nodeEnv = config?.nodeEnv || process.env.NODE_ENV; const isProdTarget = deploymentTarget === 'production' || nodeEnv === 'production'; return { secure: isProdTarget, sameSite: 'lax' }; } export function getSidCookieOptions(config) { const { secure, sameSite } = getCookieSecurityConfig(config); return { httpOnly: true, secure, sameSite, path: '/', maxAge: SEVEN_DAYS_SECONDS * 1000 }; } // Legacy cookie options used before widening cookie scope to '/'. // Clearing these prevents browsers from sending multiple cookies with the same // name but different paths (e.g. '/api' and '/'), which can cause session // split-brain. export function getLegacySidCookieOptions(config) { const { secure, sameSite } = getCookieSecurityConfig(config); return { httpOnly: true, secure, sameSite, path: '/api', maxAge: SEVEN_DAYS_SECONDS * 1000 }; } export function getCsrfCookieOptions(config) { const { secure, sameSite } = getCookieSecurityConfig(config); return { httpOnly: false, secure, sameSite, path: '/', maxAge: ONE_DAY_SECONDS * 1000 }; } export function getLegacyCsrfCookieOptions(config) { const { secure, sameSite } = getCookieSecurityConfig(config); return { httpOnly: false, secure, sameSite, path: '/api', maxAge: ONE_DAY_SECONDS * 1000 }; } export function generateToken(bytes = 24) { return crypto.randomBytes(bytes).toString('base64url'); }