import { sql } from "@/db"; /** Login limiter backed by the DB: 5 failures / 15 min per IP or per e-mail, exponential lockout up to 60 min. */ export async function loginAllowed(ip: string, email: string): Promise<{ ok: true } | { ok: false; retryAfterSec: number }> { const [r] = await sql`SELECT (SELECT count(*) FROM login_attempts WHERE ip = ${ip} AND success = false AND created_at > now() - interval '15 minutes') AS by_ip, (SELECT count(*) FROM login_attempts WHERE email = ${email} AND success = false AND created_at > now() - interval '15 minutes') AS by_user`; const failures = Math.max(Number(r.by_ip), Number(r.by_user)); if (failures < 5) return { ok: true }; return { ok: false, retryAfterSec: Math.min(60, 2 ** (failures - 4)) * 60 }; } export async function recordAttempt(ip: string, email: string | null, success: boolean) { await sql`INSERT INTO login_attempts (ip, email, success) VALUES (${ip}, ${email}, ${success})`; if (Math.random() < 0.05) await sql`DELETE FROM login_attempts WHERE created_at < now() - interval '2 days'`; }