/** * Dashboard session cookies (JWT in an httpOnly cookie). No cookie * library — set via Set-Cookie header, read by parsing the Cookie header. */ import type { FastifyReply, FastifyRequest } from 'fastify'; import { signJwt, verifyJwt } from './crypto.js'; import { config } from '../config.js'; const COOKIE = 'wpide_session'; export function setSession(reply: FastifyReply, userId: string): void { const token = signJwt({ sub: userId }); const secure = config.PUBLIC_BASE_URL.startsWith('https'); const parts = [ `${COOKIE}=${token}`, 'Path=/', 'HttpOnly', 'SameSite=Lax', `Max-Age=${60 * 60 * 24 * 30}`, ]; if (secure) parts.push('Secure'); reply.header('set-cookie', parts.join('; ')); } export function clearSession(reply: FastifyReply): void { reply.header('set-cookie', `${COOKIE}=; Path=/; HttpOnly; Max-Age=0`); } export function getSessionUserId(req: FastifyRequest): string | null { const raw = req.headers.cookie; if (!raw) return null; const match = raw.split(';').map((c) => c.trim()).find((c) => c.startsWith(`${COOKIE}=`)); if (!match) return null; const token = match.slice(COOKIE.length + 1); const payload = verifyJwt<{ sub: string }>(token); return payload?.sub ?? null; }