From 3e1a3f92c8590b0f805e9f144e75e1af06b53490 Mon Sep 17 00:00:00 2001 From: openhands Date: Wed, 23 Sep 2026 15:06:16 +0200 Subject: [PATCH] feat(security): recovery alerts, gate-block sharing, rolling-window burst and admin breakdown for CrowdSec --- src/app/admin/devops/antiddos/page.tsx | 76 +++++++++++- src/lib/crowdsec-api.test.ts | 104 +++++++++++++++++ src/lib/crowdsec-api.ts | 63 ++++++++-- src/lib/crowdsec-report.test.ts | 37 ++++++ src/lib/crowdsec-report.ts | 16 ++- src/lib/crowdsec-stats.ts | 153 +++++++++++++++++-------- src/lib/ddos-guard-crowdsec.test.ts | 29 ++++- src/lib/ddos-guard.ts | 35 ++++++ 8 files changed, 448 insertions(+), 65 deletions(-) diff --git a/src/app/admin/devops/antiddos/page.tsx b/src/app/admin/devops/antiddos/page.tsx index 3f51cd6e..70df9430 100644 --- a/src/app/admin/devops/antiddos/page.tsx +++ b/src/app/admin/devops/antiddos/page.tsx @@ -45,7 +45,7 @@ import { crowdsecReportEnabled, getLastCrowdsecReport, } from "@/lib/crowdsec-report"; -import { getCrowdsecStats } from "@/lib/crowdsec-stats"; +import { type CrowdsecDailyStat, getCrowdsecStats } from "@/lib/crowdsec-stats"; import { db, WebsiteSetting } from "@/lib/db"; import { canAccess, getAdminContext, PERMS } from "@/lib/permissions"; import { redis } from "@/lib/redis"; @@ -58,6 +58,40 @@ function seconds(ttlMs: number): string { return `${Math.floor(s / 3600)}h ${Math.floor((s % 3600) / 60)}m`; } +function BarSparkline({ values }: { values: number[] }) { + if (values.length === 0) return null; + const max = Math.max(...values, 1); + return ( +