import { serialize, parse } from 'cookie'; import { createCipheriv, createDecipheriv, randomBytes } from 'crypto'; import type { SessionData } from '~/utils/types'; export class SessionManager { private encryptionKey: Buffer; private cookieName = 'monacousa-session'; constructor(encryptionKey: string) { this.encryptionKey = Buffer.from(encryptionKey, 'hex'); } private encrypt(data: string): string { const iv = randomBytes(16); const cipher = createCipheriv('aes-256-cbc', this.encryptionKey, iv); let encrypted = cipher.update(data, 'utf8', 'hex'); encrypted += cipher.final('hex'); return iv.toString('hex') + ':' + encrypted; } private decrypt(encryptedData: string): string { const [ivHex, encrypted] = encryptedData.split(':'); const iv = Buffer.from(ivHex, 'hex'); const decipher = createDecipheriv('aes-256-cbc', this.encryptionKey, iv); let decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } createSession(sessionData: SessionData, rememberMe: boolean = false): string { const data = JSON.stringify(sessionData); const encrypted = this.encrypt(data); const cookieDomain = process.env.COOKIE_DOMAIN || undefined; const maxAge = rememberMe ? 60 * 60 * 24 * 30 : 60 * 60 * 24 * 7; // 30 days vs 7 days console.log(`🍪 Creating session cookie (Remember Me: ${rememberMe}) with domain:`, cookieDomain); return serialize(this.cookieName, encrypted, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', domain: cookieDomain, maxAge, path: '/', }); } getSession(cookieHeader?: string): SessionData | null { if (!cookieHeader) return null; const cookies = parse(cookieHeader); const sessionCookie = cookies[this.cookieName]; if (!sessionCookie) return null; try { const decrypted = this.decrypt(sessionCookie); const sessionData = JSON.parse(decrypted) as SessionData; // Check if session is expired if (Date.now() > sessionData.tokens.expiresAt) { return null; } return sessionData; } catch (error) { console.error('Failed to decrypt session:', error); return null; } } destroySession(): string { return serialize(this.cookieName, '', { httpOnly: true, secure: true, sameSite: 'lax', maxAge: 0, path: '/', }); } } export function createSessionManager(): SessionManager { const config = useRuntimeConfig(); return new SessionManager(config.encryptionKey); }