import { createHmac } from 'crypto'; import { type NextRequest } from 'next/server'; import { setUserPreferences } from '@/lib/db/queries'; function verifySignature(userId: string, sig: string): boolean { const secret = process.env.UNSUBSCRIBE_SECRET ?? 'dev-secret-change-in-prod'; const expected = createHmac('sha256', secret).update(userId).digest('hex'); // Constant-time comparison to prevent timing attacks if (expected.length !== sig.length) return false; let diff = 0; for (let i = 0; i < expected.length; i++) { diff |= expected.charCodeAt(i) ^ sig.charCodeAt(i); } return diff === 0; } export async function GET(request: NextRequest): Promise { const { searchParams } = new URL(request.url); const userId = searchParams.get('userId') ?? ''; const sig = searchParams.get('sig') ?? ''; if (!userId || !verifySignature(userId, sig)) { return new Response('Invalid or expired unsubscribe link.', { status: 400 }); } await setUserPreferences(userId, { emailDigest: false }); const BASE_URL = process.env.AUTH_URL ?? 'http://localhost:3000'; return new Response( `Unsubscribed

Unsubscribed

You've been removed from Curio review digests. You can re-enable them in Settings.

`, { headers: { 'Content-Type': 'text/html; charset=utf-8' } }, ); }