import { createHmac, timingSafeEqual } from 'crypto'; import { cookies } from 'next/headers'; export const CUSTOMER_SESSION_COOKIE = 'shahi_customer_session'; const SESSION_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000; export interface CustomerSession { email: string; name?: string; } function getSessionSecret(): string { return process.env.CUSTOMER_SESSION_SECRET ?? 'shahi-kitchen-customer-dev-secret'; } function encodeEmail(email: string): string { return Buffer.from(email, 'utf8').toString('base64url'); } function decodeEmail(encoded: string): string | null { try { return Buffer.from(encoded, 'base64url').toString('utf8'); } catch { return null; } } export function createCustomerSessionToken(session: CustomerSession): string { const issuedAt = Date.now().toString(); const namePart = session.name ? `:${encodeEmail(session.name)}` : ''; const payload = `customer:${encodeEmail(session.email)}${namePart}:${issuedAt}`; const signature = createHmac('sha256', getSessionSecret()).update(payload).digest('hex'); return `${payload}.${signature}`; } export function verifyCustomerSessionToken(token: string | undefined | null): CustomerSession | null { if (!token) return null; const [payload, signature] = token.split('.'); if (!payload || !signature) return null; const expected = createHmac('sha256', getSessionSecret()).update(payload).digest('hex'); const sigBuffer = Buffer.from(signature); const expectedBuffer = Buffer.from(expected); if (sigBuffer.length !== expectedBuffer.length) return null; if (!timingSafeEqual(sigBuffer, expectedBuffer)) return null; const parts = payload.split(':'); if (parts[0] !== 'customer' || parts.length < 3) return null; const issuedAt = Number(parts[parts.length - 1]); if (!Number.isFinite(issuedAt) || Date.now() - issuedAt > SESSION_MAX_AGE_MS) return null; const email = decodeEmail(parts[1]); if (!email) return null; let name: string | undefined; if (parts.length === 4) { name = decodeEmail(parts[2]) ?? undefined; } return { email, name }; } export async function getCustomerSession(): Promise { const cookieStore = await cookies(); const token = cookieStore.get(CUSTOMER_SESSION_COOKIE)?.value; return verifyCustomerSessionToken(token); } export function getCustomerSessionCookieOptions() { return { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax' as const, path: '/', maxAge: SESSION_MAX_AGE_MS / 1000, }; } export function getClearedCustomerSessionCookieOptions() { return { ...getCustomerSessionCookieOptions(), maxAge: 0, expires: new Date(0), }; }