'use client' /** * Middleware Admin - Rate Limiting, IP Whitelist/Blacklist, Events * * Manage middleware configurations and monitor events * Migrated from old admin (/admin/middleware) */ import { useEffect, useState, useCallback } from 'react' import { PagePurpose } from '@/components/common/PagePurpose' interface MiddlewareConfig { id: string middleware_name: string enabled: boolean config: Record updated_at: string | null } interface RateLimitIP { id: string ip_address: string list_type: 'whitelist' | 'blacklist' reason: string | null expires_at: string | null created_at: string } interface MiddlewareEvent { id: string middleware_name: string event_type: string ip_address: string | null user_id: string | null request_path: string | null request_method: string | null details: Record | null created_at: string } interface MiddlewareStats { middleware_name: string total_events: number events_last_hour: number events_last_24h: number top_event_types: Array<{ event_type: string; count: number }> top_ips: Array<{ ip_address: string; count: number }> } export default function MiddlewareAdminPage() { const [configs, setConfigs] = useState([]) const [ipList, setIpList] = useState([]) const [events, setEvents] = useState([]) const [stats, setStats] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [activeTab, setActiveTab] = useState<'overview' | 'config' | 'ip-list' | 'events' | 'stats'>('overview') const [actionLoading, setActionLoading] = useState(null) // IP Form const [newIP, setNewIP] = useState('') const [newIPType, setNewIPType] = useState<'whitelist' | 'blacklist'>('whitelist') const [newIPReason, setNewIPReason] = useState('') const fetchData = useCallback(async () => { setLoading(true) setError(null) try { const [configsRes, ipListRes, eventsRes, statsRes] = await Promise.all([ fetch('/api/admin/middleware'), fetch('/api/admin/middleware/rate-limit/ip-list'), fetch('/api/admin/middleware/events?limit=50'), fetch('/api/admin/middleware/stats'), ]) if (configsRes.ok) { setConfigs(await configsRes.json()) } if (ipListRes.ok) { setIpList(await ipListRes.json()) } if (eventsRes.ok) { setEvents(await eventsRes.json()) } if (statsRes.ok) { setStats(await statsRes.json()) } } catch (err) { setError(err instanceof Error ? err.message : 'Verbindung zum Backend fehlgeschlagen') } finally { setLoading(false) } }, []) useEffect(() => { fetchData() }, [fetchData]) useEffect(() => { const interval = setInterval(fetchData, 30000) return () => clearInterval(interval) }, [fetchData]) const toggleMiddleware = async (name: string, enabled: boolean) => { setActionLoading(name) setError(null) try { const response = await fetch(`/api/admin/middleware/${name}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ enabled }), }) if (!response.ok) { throw new Error(`Fehler beim Aktualisieren: ${response.statusText}`) } // Update local state setConfigs(prev => prev.map(c => (c.middleware_name === name ? { ...c, enabled } : c)) ) } catch (err) { setError(err instanceof Error ? err.message : 'Aktualisierung fehlgeschlagen') } finally { setActionLoading(null) } } const addIP = async (e: React.FormEvent) => { e.preventDefault() if (!newIP.trim()) return setActionLoading('add-ip') setError(null) try { const response = await fetch('/api/admin/middleware/rate-limit/ip-list', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ip_address: newIP.trim(), list_type: newIPType, reason: newIPReason.trim() || null, }), }) if (!response.ok) { const data = await response.json() throw new Error(data.detail || `Fehler: ${response.statusText}`) } const newEntry = await response.json() setIpList(prev => [newEntry, ...prev]) setNewIP('') setNewIPReason('') } catch (err) { setError(err instanceof Error ? err.message : 'IP konnte nicht hinzugefuegt werden') } finally { setActionLoading(null) } } const removeIP = async (id: string) => { setActionLoading(`remove-${id}`) setError(null) try { const response = await fetch(`/api/admin/middleware/rate-limit/ip-list/${id}`, { method: 'DELETE', }) if (!response.ok) { throw new Error(`Fehler beim Loeschen: ${response.statusText}`) } setIpList(prev => prev.filter(ip => ip.id !== id)) } catch (err) { setError(err instanceof Error ? err.message : 'IP konnte nicht entfernt werden') } finally { setActionLoading(null) } } const getMiddlewareDescription = (name: string): { icon: string; desc: string } => { const descriptions: Record = { request_id: { icon: '🆔', desc: 'Generiert eindeutige Request-IDs fuer Tracing' }, security_headers: { icon: '🛡️', desc: 'Fuegt Security-Header hinzu (CSP, HSTS, etc.)' }, cors: { icon: '🌐', desc: 'Cross-Origin Resource Sharing Konfiguration' }, rate_limiter: { icon: '⏱️', desc: 'Rate Limiting zum Schutz vor Missbrauch' }, pii_redactor: { icon: '🔒', desc: 'Redaktiert personenbezogene Daten in Logs' }, input_gate: { icon: '🚪', desc: 'Validiert und sanitisiert Eingaben' }, } return descriptions[name] || { icon: '⚙️', desc: 'Middleware-Komponente' } } const getEventTypeColor = (eventType: string) => { if (eventType.includes('error') || eventType.includes('blocked') || eventType.includes('blacklist')) { return 'bg-red-100 text-red-800' } if (eventType.includes('warning') || eventType.includes('rate_limit')) { return 'bg-yellow-100 text-yellow-800' } if (eventType.includes('success') || eventType.includes('whitelist')) { return 'bg-green-100 text-green-800' } return 'bg-slate-100 text-slate-800' } const whitelistCount = ipList.filter(ip => ip.list_type === 'whitelist').length const blacklistCount = ipList.filter(ip => ip.list_type === 'blacklist').length return (
{/* Stats Overview */}

Middleware Status

{configs.length}
Middleware
{whitelistCount}
Whitelist IPs
{blacklistCount}
Blacklist IPs
{events.length}
Recent Events
{/* Tabs */}
{(['overview', 'config', 'ip-list', 'events', 'stats'] as const).map(tab => ( ))}
{error && (
{error}
)} {loading ? (
) : ( <> {/* Overview Tab */} {activeTab === 'overview' && (
{configs.map(config => { const info = getMiddlewareDescription(config.middleware_name) return (
{info.icon} {config.middleware_name.replace('_', ' ')}

{info.desc}

{config.updated_at && (
Aktualisiert: {new Date(config.updated_at).toLocaleString('de-DE')}
)}
) })}
)} {/* Config Tab */} {activeTab === 'config' && (
{configs.map(config => { const info = getMiddlewareDescription(config.middleware_name) return (

{info.icon} {config.middleware_name.replace('_', ' ')}

{info.desc}

{config.enabled ? 'Aktiviert' : 'Deaktiviert'}
{Object.keys(config.config).length > 0 && (
Konfiguration
                              {JSON.stringify(config.config, null, 2)}
                            
)}
) })}
)} {/* IP List Tab */} {activeTab === 'ip-list' && (
{/* Add IP Form */}

IP hinzufuegen

setNewIP(e.target.value)} placeholder="IP-Adresse (z.B. 192.168.1.1)" className="flex-1 min-w-[200px] px-4 py-2 border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-orange-500" /> setNewIPReason(e.target.value)} placeholder="Grund (optional)" className="flex-1 min-w-[150px] px-4 py-2 border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-orange-500" />
{/* IP List Table */}
{ipList.length === 0 ? ( ) : ( ipList.map(ip => ( )) )}
IP-Adresse Typ Grund Hinzugefuegt Aktion
Keine IP-Eintraege vorhanden.
{ip.ip_address} {ip.list_type === 'whitelist' ? 'Whitelist' : 'Blacklist'} {ip.reason || '-'} {new Date(ip.created_at).toLocaleString('de-DE')}
)} {/* Events Tab */} {activeTab === 'events' && (
{events.length === 0 ? ( ) : ( events.map(event => ( )) )}
Zeit Middleware Event IP Pfad
Keine Events vorhanden.
{new Date(event.created_at).toLocaleString('de-DE')} {event.middleware_name.replace('_', ' ')} {event.event_type} {event.ip_address || '-'} {event.request_method && event.request_path ? `${event.request_method} ${event.request_path}` : '-'}
)} {/* Stats Tab */} {activeTab === 'stats' && (
{stats.map(stat => { const info = getMiddlewareDescription(stat.middleware_name) return (

{info.icon} {stat.middleware_name.replace('_', ' ')}

{stat.total_events}
Gesamt
{stat.events_last_hour}
Letzte Stunde
{stat.events_last_24h}
24 Stunden
{stat.top_event_types.length > 0 && (
Top Event-Typen
{stat.top_event_types.slice(0, 3).map(et => ( {et.event_type} ({et.count}) ))}
)} {stat.top_ips.length > 0 && (
Top IPs
{stat.top_ips .slice(0, 3) .map(ip => `${ip.ip_address} (${ip.count})`) .join(', ')}
)}
) })}
)} )}
{/* Info Box */}

Middleware Stack

Der Middleware Stack verarbeitet alle API-Anfragen in der konfigurierten Reihenfolge. Aenderungen an der Konfiguration werden sofort wirksam. Verwenden Sie die Whitelist fuer vertrauenswuerdige IPs und die Blacklist fuer bekannte Angreifer.

) }