import { NextRequest, NextResponse } from "next/server"; import crypto from "node:crypto"; import { z } from "zod"; import { db, adminWebhooks } from "@epicure/db"; import { requireAdmin } from "@/lib/api-auth"; import { validateWebhookUrl } from "@/lib/validate-webhook-url"; import { ADMIN_WEBHOOK_EVENTS } from "@/lib/admin-webhooks"; import { encrypt } from "@/lib/encrypt"; const CreateWebhookBody = z.object({ url: z.string().min(1).max(2048), events: z.array(z.enum(ADMIN_WEBHOOK_EVENTS)).default([]), }); export async function GET() { const { response } = await requireAdmin(); if (response) return response; const rows = await db .select({ id: adminWebhooks.id, url: adminWebhooks.url, events: adminWebhooks.events, active: adminWebhooks.active, createdAt: adminWebhooks.createdAt, }) .from(adminWebhooks); return NextResponse.json(rows); } export async function POST(req: NextRequest) { const { session, response } = await requireAdmin(); if (response) return response; const body = await req.json() as unknown; const parsed = CreateWebhookBody.safeParse(body); if (!parsed.success) { return NextResponse.json({ error: "Validation error", issues: parsed.error.issues }, { status: 400 }); } const ssrfError = await validateWebhookUrl(parsed.data.url); if (ssrfError) { return NextResponse.json({ error: ssrfError }, { status: 400 }); } const secret = crypto.randomBytes(32).toString("hex"); const id = crypto.randomUUID(); const now = new Date(); await db.insert(adminWebhooks).values({ id, createdById: session!.user.id, url: parsed.data.url, events: parsed.data.events, secret: encrypt(secret), active: true, createdAt: now, }); return NextResponse.json( { id, url: parsed.data.url, events: parsed.data.events, secret, active: true, createdAt: now.toISOString() }, { status: 201 } ); }