import Link from "next/link"; import { ShieldAlert, ShieldCheck } from "lucide-react"; import { requireAdmin } from "@/lib/session"; import { getSuspiciousActivity, listAbuseEvents, str } from "@/lib/queries/admin"; import { formatNumber, formatPercent } from "@/lib/format"; import { PageHeader } from "@/components/ui/page-header"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { EmptyState } from "@/components/ui/empty-state"; import { Table, TableBody, TableCell, TableEmpty, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { DateCell, Mono, Panel, PlanBadge, numCell } from "@/components/admin/primitives"; import { RecordAbuseDialog, ResolveAbuseButton } from "@/components/admin/abuse-actions"; import { cn } from "@/lib/utils"; export const dynamic = "force-dynamic"; function SeverityBadge({ s }: { s: string }) { const v = s === "critical" ? "danger" : s === "high" ? "danger" : s === "medium" ? "warning" : "default"; return {s}; } export default async function AdminAbusePage({ searchParams }: { searchParams: Promise> }) { await requireAdmin(); const sp = await searchParams; const view = (["all", "open", "resolved"] as const).find((v) => v === str(sp.view)) ?? "open"; const [events, sus] = await Promise.all([listAbuseEvents({ resolved: view }), getSuspiciousActivity()]); const signals = sus.ssrf.length + sus.limited.length + sus.unverified.length; return ( <> } /> Suspicious activity (24h) {signals ? {signals} signals : clear} } description="Heuristics, not verdicts. Investigate from the organization page before acting." bodyClassName="p-0" >

SSRF / disallowed URLs

Orgs with > 30 % `URL_NOT_ALLOWED` (min. 5 requests).

Organization Blocked Ratio {sus.ssrf.length === 0 ? ( None. ) : ( sus.ssrf.map((r) => ( {r.orgName} {" "} {r.notAllowed} / {r.total} {formatPercent(r.ratio)} )) )}

Rate / concurrency limits

Orgs hitting `RATE_LIMITED` or `CONCURRENCY_LIMIT` most.

Organization Rate Concurrency {sus.limited.length === 0 ? ( None. ) : ( sus.limited.map((r) => ( {r.orgName} {" "} {formatNumber(r.rateLimited)} {formatNumber(r.concurrency)} )) )}

Unverified heavy playground use

Unverified owners with ≥ 20 playground requests.

User Requests Signed up {sus.unverified.length === 0 ? ( None. ) : ( sus.unverified.map((r) => ( {r.email} {formatNumber(r.playground)} )) )}
{(["open", "resolved", "all"] as const).map((v) => ( ))} } flush className="mt-6" > {events.length === 0 ? (
) : ( When Kind Severity Organization Project / request Detail Status {events.map((e) => ( {e.kind} {e.organizationId ? {e.orgName ?? e.organizationId} : —}
{e.projectId ?? "—"}
{e.requestId ? ( {e.requestId} ) : null}
{e.detail ?? "—"} {e.resolved ? resolved : open}
))}
)}
); }