import { createHmac, timingSafeEqual } from 'node:crypto' import type { H3Event } from 'h3' import { getCookie, setCookie, deleteCookie, createError } from 'h3' import { prisma } from './db' const cookieName = 'money_session' function secret() { return useRuntimeConfig().sessionSecret } function sign(value: string) { return createHmac('sha256', secret()).update(value).digest('hex') } export function createSessionCookie(userId: string) { const payload = Buffer.from(JSON.stringify({ userId })).toString('base64url') return `${payload}.${sign(payload)}` } export function setSession(event: H3Event, userId: string) { setCookie(event, cookieName, createSessionCookie(userId), { httpOnly: true, sameSite: 'lax', secure: process.env.NODE_ENV === 'production', maxAge: 60 * 60 * 24 * 180, path: '/' }) } export function clearAuthSession(event: H3Event) { deleteCookie(event, cookieName, { path: '/' }) } export async function requireUser(event: H3Event) { const raw = getCookie(event, cookieName) if (!raw) throw createError({ statusCode: 401, statusMessage: 'Unauthorized' }) const [payload, signature] = raw.split('.') if (!payload || !signature) throw createError({ statusCode: 401, statusMessage: 'Unauthorized' }) const expected = sign(payload) const isValid = timingSafeEqual(Buffer.from(signature), Buffer.from(expected)) if (!isValid) throw createError({ statusCode: 401, statusMessage: 'Unauthorized' }) const parsed = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8')) as { userId: string } const user = await prisma.user.findUnique({ where: { id: parsed.userId }, select: { id: true, email: true, name: true } }) if (!user) throw createError({ statusCode: 401, statusMessage: 'Unauthorized' }) return user }