diff --git a/src/web/auth/validateSession.ts b/src/web/auth/validateSession.ts new file mode 100644 index 0000000..4a00cb2 --- /dev/null +++ b/src/web/auth/validateSession.ts @@ -0,0 +1,33 @@ +import type { SessionStore, SessionValidation } from "../../data/sessions.js"; + +export const SESSION_COOKIE_NAME = "tsmb_session"; + +/** + * Validate the session cookie carried on an arbitrary HTTP-like header bag. + * Used by Express middleware (req.headers.cookie) AND by the raw WebSocket + * upgrade handler (req.headers.cookie) — they share this exact behavior. + */ +export function validateSessionFromHeaders( + rawCookieHeader: string | undefined, + sessions: SessionStore +): SessionValidation | null { + if (!rawCookieHeader) return null; + const token = parseCookie(rawCookieHeader, SESSION_COOKIE_NAME); + if (!token) return null; + return sessions.validateAndTouch(token); +} + +function parseCookie(header: string, name: string): string | null { + for (const part of header.split(";")) { + const trimmed = part.trim(); + const eq = trimmed.indexOf("="); + if (eq < 1) continue; + if (trimmed.slice(0, eq) !== name) continue; + try { + return decodeURIComponent(trimmed.slice(eq + 1)); + } catch { + return null; + } + } + return null; +}