From df5d12527965fa7dc646c24137e10da5707bb9f9 Mon Sep 17 00:00:00 2001 From: saopig1 <4x7sw862st@gmail.com> Date: Wed, 27 May 2026 13:34:47 +0800 Subject: [PATCH] feat(auth): add shared validateSessionFromHeaders helper --- src/web/auth/validateSession.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/web/auth/validateSession.ts 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; +}