spb/tools-spboucher-ai
Public
1import { createHash } from "node:crypto";2import { sqlPublic } from "@/db";3import { rateLimit } from "@/lib/auth/ratelimit";4import { z } from "zod";5const body = z.object({ slug: z.string().max(120), message: z.string().min(10).max(2000), contact: z.string().email().max(200).optional().or(z.literal("")), website: z.string().max(0).optional() });6export async function POST(req: Request) {7 const ip = (req.headers.get("x-forwarded-for")?.split(",")[0] ?? "0.0.0.0").trim();8 if (!rateLimit(`report:${ip}`, 5, 60 * 60_000)) return Response.json({ error: "Too many reports from this address; try again later." }, { status: 429 });9 const parsed = body.safeParse(await req.json().catch(() => null));10 if (!parsed.success) return Response.json({ error: "Invalid report" }, { status: 400 });11 const { slug, message, contact } = parsed.data;12 const [t] = await sqlPublic<{ id: string }[]>`SELECT id FROM public_tools WHERE slug = ${slug}`;13 await sqlPublic`INSERT INTO error_reports (tool_id, tool_slug, message, contact, ip_hash) VALUES (${t?.id ?? null}, ${slug}, ${message}, ${contact || null}, ${createHash("sha256").update(ip + (process.env.SESSION_SECRET ?? "")).digest("hex").slice(0, 32)})`;14 return Response.json({ ok: true });15}16