SPB Git
1.2 KB · 16 lines typescript
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
Files · main
Menu

Theme