'use client' /** * Middleware Configuration Admin Page * * Manage middleware settings for BreakPilot: * - Enable/disable middlewares * - Configure rate limits * - Manage IP whitelist/blacklist * - View middleware events and statistics */ import { useState, useEffect } from 'react' import AdminLayout from '@/components/admin/AdminLayout' import SystemInfoSection, { SYSTEM_INFO_CONFIGS } from '@/components/admin/SystemInfoSection' 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 }> } type TabType = 'overview' | 'rate-limiting' | 'security' | 'logging' | 'events' const MIDDLEWARE_INFO: Record = { request_id: { name: 'Request-ID', description: 'Generates unique identifiers for request tracing', icon: '๐Ÿ”‘', }, security_headers: { name: 'Security Headers', description: 'Adds security headers (HSTS, CSP, X-Frame-Options)', icon: '๐Ÿ›ก๏ธ', }, cors: { name: 'CORS', description: 'Cross-Origin Resource Sharing configuration', icon: '๐ŸŒ', }, rate_limiter: { name: 'Rate Limiter', description: 'Protects against abuse with request limits', icon: 'โฑ๏ธ', }, pii_redactor: { name: 'PII Redactor', description: 'Redacts sensitive data from logs (DSGVO)', icon: '๐Ÿ”’', }, input_gate: { name: 'Input Gate', description: 'Validates request body size and content types', icon: '๐Ÿšง', }, } export default function MiddlewarePage() { const [activeTab, setActiveTab] = useState('overview') const [configs, setConfigs] = useState([]) const [ipList, setIpList] = useState([]) const [events, setEvents] = useState([]) const [stats, setStats] = useState([]) const [loading, setLoading] = useState(true) const [saving, setSaving] = useState(false) const [editingConfig, setEditingConfig] = useState(null) const [newIP, setNewIP] = useState({ ip_address: '', list_type: 'whitelist', reason: '' }) const BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000' useEffect(() => { loadData() }, []) const loadData = async () => { setLoading(true) try { const [configsRes, ipListRes, eventsRes, statsRes] = await Promise.all([ fetch(`${BACKEND_URL}/api/admin/middleware`), fetch(`${BACKEND_URL}/api/admin/middleware/rate-limit/ip-list`), fetch(`${BACKEND_URL}/api/admin/middleware/events?limit=50`), fetch(`${BACKEND_URL}/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 (error) { console.error('Failed to load middleware data:', error) } finally { setLoading(false) } } const toggleMiddleware = async (name: string, enabled: boolean) => { setSaving(true) try { const res = await fetch(`${BACKEND_URL}/api/admin/middleware/${name}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ enabled }), }) if (res.ok) { setConfigs(configs.map(c => c.middleware_name === name ? { ...c, enabled } : c)) } } catch (error) { console.error('Failed to update middleware:', error) } finally { setSaving(false) } } const updateConfig = async (name: string, config: Record) => { setSaving(true) try { const res = await fetch(`${BACKEND_URL}/api/admin/middleware/${name}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ config }), }) if (res.ok) { const updated = await res.json() setConfigs(configs.map(c => c.middleware_name === name ? updated : c)) setEditingConfig(null) } } catch (error) { console.error('Failed to update config:', error) } finally { setSaving(false) } } const addIP = async () => { if (!newIP.ip_address) return setSaving(true) try { const res = await fetch(`${BACKEND_URL}/api/admin/middleware/rate-limit/ip-list`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(newIP), }) if (res.ok) { const added = await res.json() setIpList([added, ...ipList]) setNewIP({ ip_address: '', list_type: 'whitelist', reason: '' }) } } catch (error) { console.error('Failed to add IP:', error) } finally { setSaving(false) } } const removeIP = async (id: string) => { setSaving(true) try { const res = await fetch(`${BACKEND_URL}/api/admin/middleware/rate-limit/ip-list/${id}`, { method: 'DELETE', }) if (res.ok) { setIpList(ipList.filter(ip => ip.id !== id)) } } catch (error) { console.error('Failed to remove IP:', error) } finally { setSaving(false) } } const getConfig = (name: string) => configs.find(c => c.middleware_name === name) const getStats = (name: string) => stats.find(s => s.middleware_name === name) const tabs = [ { id: 'overview', label: 'Overview', icon: '๐Ÿ“Š' }, { id: 'rate-limiting', label: 'Rate Limiting', icon: 'โฑ๏ธ' }, { id: 'security', label: 'Security', icon: '๐Ÿ›ก๏ธ' }, { id: 'logging', label: 'Logging', icon: '๐Ÿ“' }, { id: 'events', label: 'Events', icon: '๐Ÿ“‹' }, ] return ( {/* Tab Navigation */}
{/* Test Wizard Link */}
๐Ÿงช

UI Test Wizard

Interaktives Testing mit Lernmaterial - Testen Sie alle Middleware-Komponenten Schritt fuer Schritt

Wizard starten โ†’
{loading ? (

Loading middleware configuration...

) : ( <> {/* Overview Tab */} {activeTab === 'overview' && (

Middleware Status

{Object.entries(MIDDLEWARE_INFO).map(([key, info]) => { const config = getConfig(key) const mwStats = getStats(key) return (
{info.icon}

{info.name}

{info.description}

{mwStats && (
Last hour: {mwStats.events_last_hour} events 24h: {mwStats.events_last_24h} events
)}
) })}
{/* Quick Stats */}

Activity Summary (24h)

{stats.map((s) => (

{MIDDLEWARE_INFO[s.middleware_name]?.name || s.middleware_name}

{s.events_last_24h}

{s.events_last_hour} in last hour

))}
)} {/* Rate Limiting Tab */} {activeTab === 'rate-limiting' && (
{/* Rate Limit Config */}

Rate Limit Settings

{(() => { const config = getConfig('rate_limiter') if (!config) return

Loading...

return (
{ const newConfig = { ...config.config, ip_limit: parseInt(e.target.value) } updateConfig('rate_limiter', newConfig) }} className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500" />
{ const newConfig = { ...config.config, user_limit: parseInt(e.target.value) } updateConfig('rate_limiter', newConfig) }} className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500" />
{ const newConfig = { ...config.config, auth_limit: parseInt(e.target.value) } updateConfig('rate_limiter', newConfig) }} className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500" />
) })()}
{/* IP Whitelist/Blacklist */}

IP Whitelist / Blacklist

{/* Add IP Form */}
setNewIP({ ...newIP, ip_address: e.target.value })} className="flex-1 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500" /> setNewIP({ ...newIP, reason: e.target.value })} className="flex-1 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500" />
{/* IP List Table */} {ipList.length === 0 ? ( ) : ( ipList.map((ip) => ( )) )}
IP Address Type Reason Created
No IPs in whitelist/blacklist
{ip.ip_address} {ip.list_type} {ip.reason || '-'} {new Date(ip.created_at).toLocaleDateString()}
)} {/* Security Tab */} {activeTab === 'security' && (

Security Headers Configuration

{(() => { const config = getConfig('security_headers') if (!config) return

Loading...

return (

HSTS (Strict-Transport-Security)

Force HTTPS connections

{ const newConfig = { ...config.config, hsts_enabled: e.target.checked } updateConfig('security_headers', newConfig) }} className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" />

CSP (Content-Security-Policy)

Control resource loading

{ const newConfig = { ...config.config, csp_enabled: e.target.checked } updateConfig('security_headers', newConfig) }} className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" />