Spaces:
Paused
Paused
| import { useState, useEffect, useCallback } from 'react'; | |
| import { useNotifications, NotificationSeverity } from '@/contexts/NotificationContext'; | |
| export type MetricType = | |
| | 'threat_count' | |
| | 'cpu_usage' | |
| | 'memory_usage' | |
| | 'network_traffic' | |
| | 'failed_logins' | |
| | 'active_connections' | |
| | 'response_time' | |
| | 'error_rate'; | |
| export type Operator = 'gt' | 'lt' | 'eq' | 'gte' | 'lte'; | |
| export interface AlertRule { | |
| id: string; | |
| name: string; | |
| description?: string; | |
| enabled: boolean; | |
| metric: MetricType; | |
| operator: Operator; | |
| threshold: number; | |
| severity: NotificationSeverity; | |
| cooldownMinutes: number; | |
| lastTriggered?: number; | |
| triggerCount: number; | |
| createdAt: number; | |
| } | |
| export interface MetricValue { | |
| metric: MetricType; | |
| value: number; | |
| timestamp: number; | |
| } | |
| const RULES_STORAGE_KEY = 'cyber-alert-rules'; | |
| export const METRIC_CONFIG: Record<MetricType, { label: string; unit: string; icon: string }> = { | |
| threat_count: { label: 'Antal trusler', unit: '', icon: 'Shield' }, | |
| cpu_usage: { label: 'CPU forbrug', unit: '%', icon: 'Cpu' }, | |
| memory_usage: { label: 'Memory forbrug', unit: '%', icon: 'HardDrive' }, | |
| network_traffic: { label: 'Netværkstrafik', unit: 'MB/s', icon: 'Network' }, | |
| failed_logins: { label: 'Fejlede logins', unit: '', icon: 'UserX' }, | |
| active_connections: { label: 'Aktive forbindelser', unit: '', icon: 'Users' }, | |
| response_time: { label: 'Responstid', unit: 'ms', icon: 'Clock' }, | |
| error_rate: { label: 'Fejlrate', unit: '%', icon: 'AlertCircle' }, | |
| }; | |
| export const OPERATOR_CONFIG: Record<Operator, { label: string; symbol: string }> = { | |
| gt: { label: 'større end', symbol: '>' }, | |
| lt: { label: 'mindre end', symbol: '<' }, | |
| eq: { label: 'lig med', symbol: '=' }, | |
| gte: { label: 'større end eller lig', symbol: '≥' }, | |
| lte: { label: 'mindre end eller lig', symbol: '≤' }, | |
| }; | |
| // Simulated metric values for demo | |
| const generateMetricValue = (metric: MetricType): number => { | |
| switch (metric) { | |
| case 'threat_count': return Math.floor(Math.random() * 150); | |
| case 'cpu_usage': return Math.floor(Math.random() * 100); | |
| case 'memory_usage': return Math.floor(40 + Math.random() * 50); | |
| case 'network_traffic': return Math.floor(Math.random() * 500); | |
| case 'failed_logins': return Math.floor(Math.random() * 20); | |
| case 'active_connections': return Math.floor(50 + Math.random() * 200); | |
| case 'response_time': return Math.floor(50 + Math.random() * 300); | |
| case 'error_rate': return Math.floor(Math.random() * 15); | |
| default: return 0; | |
| } | |
| }; | |
| const evaluateCondition = (value: number, operator: Operator, threshold: number): boolean => { | |
| switch (operator) { | |
| case 'gt': return value > threshold; | |
| case 'lt': return value < threshold; | |
| case 'eq': return value === threshold; | |
| case 'gte': return value >= threshold; | |
| case 'lte': return value <= threshold; | |
| default: return false; | |
| } | |
| }; | |
| export const useAlertRules = () => { | |
| const [rules, setRules] = useState<AlertRule[]>([]); | |
| const [currentMetrics, setCurrentMetrics] = useState<Record<MetricType, number>>({} as any); | |
| const { addNotification } = useNotifications(); | |
| // Load rules from localStorage | |
| useEffect(() => { | |
| const saved = localStorage.getItem(RULES_STORAGE_KEY); | |
| if (saved) { | |
| try { | |
| setRules(JSON.parse(saved)); | |
| } catch (e) { | |
| console.error('Failed to load alert rules:', e); | |
| } | |
| } | |
| }, []); | |
| // Save rules to localStorage | |
| const saveRules = useCallback((newRules: AlertRule[]) => { | |
| localStorage.setItem(RULES_STORAGE_KEY, JSON.stringify(newRules)); | |
| setRules(newRules); | |
| }, []); | |
| // Create new rule | |
| const createRule = useCallback((rule: Omit<AlertRule, 'id' | 'triggerCount' | 'createdAt'>): AlertRule => { | |
| const newRule: AlertRule = { | |
| ...rule, | |
| id: `rule-${Date.now()}`, | |
| triggerCount: 0, | |
| createdAt: Date.now(), | |
| }; | |
| saveRules([...rules, newRule]); | |
| return newRule; | |
| }, [rules, saveRules]); | |
| // Update existing rule | |
| const updateRule = useCallback((ruleId: string, updates: Partial<AlertRule>) => { | |
| saveRules(rules.map(r => r.id === ruleId ? { ...r, ...updates } : r)); | |
| }, [rules, saveRules]); | |
| // Delete rule | |
| const deleteRule = useCallback((ruleId: string) => { | |
| saveRules(rules.filter(r => r.id !== ruleId)); | |
| }, [rules, saveRules]); | |
| // Toggle rule enabled state | |
| const toggleRule = useCallback((ruleId: string) => { | |
| saveRules(rules.map(r => r.id === ruleId ? { ...r, enabled: !r.enabled } : r)); | |
| }, [rules, saveRules]); | |
| // Evaluate all rules against current metrics | |
| const evaluateRules = useCallback((metrics: Record<MetricType, number>) => { | |
| const now = Date.now(); | |
| const updatedRules = [...rules]; | |
| let hasChanges = false; | |
| rules.forEach((rule, index) => { | |
| if (!rule.enabled) return; | |
| const metricValue = metrics[rule.metric]; | |
| if (metricValue === undefined) return; | |
| // Check cooldown | |
| if (rule.lastTriggered) { | |
| const cooldownMs = rule.cooldownMinutes * 60 * 1000; | |
| if (now - rule.lastTriggered < cooldownMs) return; | |
| } | |
| // Evaluate condition | |
| if (evaluateCondition(metricValue, rule.operator, rule.threshold)) { | |
| const config = METRIC_CONFIG[rule.metric]; | |
| const opConfig = OPERATOR_CONFIG[rule.operator]; | |
| addNotification({ | |
| title: `Alert: ${rule.name}`, | |
| message: `${config.label} er ${metricValue}${config.unit} (${opConfig.symbol} ${rule.threshold}${config.unit})`, | |
| severity: rule.severity, | |
| source: 'Alert Rules Engine', | |
| }); | |
| updatedRules[index] = { | |
| ...rule, | |
| lastTriggered: now, | |
| triggerCount: rule.triggerCount + 1, | |
| }; | |
| hasChanges = true; | |
| } | |
| }); | |
| if (hasChanges) { | |
| saveRules(updatedRules); | |
| } | |
| }, [rules, addNotification, saveRules]); | |
| // Simulate metric updates (for demo purposes) | |
| useEffect(() => { | |
| const updateMetrics = () => { | |
| const newMetrics: Record<MetricType, number> = { | |
| threat_count: generateMetricValue('threat_count'), | |
| cpu_usage: generateMetricValue('cpu_usage'), | |
| memory_usage: generateMetricValue('memory_usage'), | |
| network_traffic: generateMetricValue('network_traffic'), | |
| failed_logins: generateMetricValue('failed_logins'), | |
| active_connections: generateMetricValue('active_connections'), | |
| response_time: generateMetricValue('response_time'), | |
| error_rate: generateMetricValue('error_rate'), | |
| }; | |
| setCurrentMetrics(newMetrics); | |
| evaluateRules(newMetrics); | |
| }; | |
| // Initial update | |
| updateMetrics(); | |
| // Update every 15 seconds | |
| const interval = setInterval(updateMetrics, 15000); | |
| return () => clearInterval(interval); | |
| }, [evaluateRules]); | |
| return { | |
| rules, | |
| currentMetrics, | |
| createRule, | |
| updateRule, | |
| deleteRule, | |
| toggleRule, | |
| }; | |
| }; | |