Files
2026-05-10 21:23:42 +02:00

69 lines
2.1 KiB
TypeScript

import { Router } from 'express'
import axios from 'axios'
const router = Router()
router.get('/stats', async (_req, res) => {
try {
const host = process.env.CROWDSEC_HOST
const key = process.env.CROWDSEC_API_KEY
if (!host || !key) {
res.status(503).json({ error: 'CROWDSEC_HOST / CROWDSEC_API_KEY not configured' })
return
}
const headers = { 'X-Api-Key': key.trim() }
// Bouncers can only access /v1/decisions — alerts require machine/agent auth
const [activeRes, weekRes] = await Promise.all([
axios.get(`${host}/v1/decisions`, { headers, params: { limit: 500000 } }),
axios.get(`${host}/v1/decisions`, { headers, params: { limit: 500000, since: '168h' } }),
])
type Decision = {
id?: number
origin?: string
type?: string
scope?: string
value?: string
scenario?: string
created_at?: string
until?: string
}
const active: Decision[] = Array.isArray(activeRes.data) ? activeRes.data : []
const week: Decision[] = Array.isArray(weekRes.data) ? weekRes.data : []
const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000)
const alertsLast24h = active.filter(d => d.created_at && new Date(d.created_at) > oneDayAgo).length
const originCount: Record<string, number> = {}
for (const d of active) {
const o = d.origin ?? 'unknown'
originCount[o] = (originCount[o] ?? 0) + 1
}
const origins = Object.entries(originCount)
.sort((a, b) => b[1] - a[1])
.map(([name, count]) => ({ name, count }))
const recent = [...active]
.filter(d => d.created_at)
.sort((a, b) => new Date(b.created_at!).getTime() - new Date(a.created_at!).getTime())
.slice(0, 6)
.map(d => ({ value: d.value ?? '?', scenario: d.scenario ?? d.origin ?? '?', created_at: d.created_at! }))
res.json({
activeBans: active.length,
alertsLast24h,
blocksThisWeek: week.length,
origins,
recent,
})
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : 'Unknown error'
res.status(500).json({ error: msg })
}
})
export default router