File size: 19,154 Bytes
5a81b95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
import { useEffect, useState } from 'react';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { 
  Shield, AlertTriangle, Activity, TrendingUp, TrendingDown, 
  ExternalLink, RefreshCw, Clock, Globe, Server, Users,
  CheckCircle, XCircle, AlertCircle, Eye, Lock, Wifi, Zap,
  Info, Code, Database
} from 'lucide-react';
import { useSecuritySimulation, SecurityEvent } from '@/hooks/useSecuritySimulation';
import { WidgetSchemaViewer } from './WidgetSchemaViewer';
import { widgetRegistry } from '@/lib/widgetRegistry';

interface WidgetDetailModalProps {
  isOpen: boolean;
  onClose: () => void;
  widget: {
    id: string;
    name: string;
    category: string;
    icon: React.ElementType;
    component: React.ReactNode;
  } | null;
}

// Widget descriptions
const widgetDescriptions: Record<string, string> = {
  'soc-dashboard': 'Security Operations Center dashboard viser real-time oversigt over alle sikkerhedshændelser, trusler og systemstatus på tværs af infrastrukturen.',
  'threat-map': 'Geografisk visualisering af aktive cyberangreb og trusselsaktivitet i realtid. Viser angrebskilder, mål og angrebstyper.',
  'malware-detection': 'Real-time malware detektion og klassificering. Overvåger alle endpoints og netværkstrafik for kendte og ukendte trusler.',
  'intrusion-detection': 'Intrusion Detection System (IDS) overvåger netværkstrafik for mistænkelig aktivitet og kendte angrebsmønstre.',
  'ddos-monitor': 'DDoS beskyttelse og monitoring. Overvåger båndbredde, pakkerater og anvender automatisk mitigation ved angreb.',
  'phishing-detector': 'Email sikkerhed med avanceret phishing detektion, URL analyse og attachment sandboxing.',
  'dark-web-monitor': 'Overvåger dark web forums, markedspladser og paste sites for lækkede credentials og virksomhedsdata.',
  'zero-day-alert': 'Overvåger for zero-day sårbarheder og nye CVEs der påvirker jeres infrastruktur.',
  'threat-level': 'Samlet trusselsniveau baseret på global threat intelligence, interne alerts og systemstatus.',
  'firewall': 'Next-generation firewall status med deep packet inspection, application control og intrusion prevention.',
  'siem-alerts': 'Security Information and Event Management - korrelerer logs og events på tværs af hele infrastrukturen.',
  'waf-status': 'Web Application Firewall beskytter web apps mod OWASP Top 10 og avancerede angreb.',
  'vpn-status': 'VPN gateway status og connected users. Overvåger tunnels, performance og sikkerhed.',
  'security-alerts': 'Samlet oversigt over alle kritiske sikkerhedsadvarsler der kræver øjeblikkelig handling.',
};

const widgetActions: Record<string, string[]> = {
  'soc-dashboard': ['Eskalér til Tier 2', 'Bloker IP', 'Kør forensic scan'],
  'threat-map': ['Aktivér GeoBlock', 'Rate Limiting', 'Kontakt ISP'],
  'malware-detection': ['Isolér Endpoint', 'Kør Full Scan', 'Opdater Signatures'],
  'intrusion-detection': ['Bloker Kilde IP', 'Opdater IDS Regler', 'Eksporter PCAP'],
  'ddos-monitor': ['Aktivér Scrubbing', 'Whitelist IPs', 'Kontakt Upstream'],
  'phishing-detector': ['Rapporter til CERT', 'Block Domain', 'Notify User'],
  'dark-web-monitor': ['Force Password Reset', 'Notify Users', 'Enable MFA'],
  'firewall': ['View Blocked IPs', 'Update Rules', 'Export Logs'],
  'vpn-status': ['Disconnect User', 'View Sessions', 'Rotate Keys'],
};

// Type for metrics
type MetricStatus = 'good' | 'warning' | 'critical';
type MetricTrend = 'up' | 'down' | 'stable';
interface DynamicMetric {
  label: string;
  value: string;
  status?: MetricStatus;
  trend?: MetricTrend;
}

export const WidgetDetailModal = ({ isOpen, onClose, widget }: WidgetDetailModalProps) => {
  const simulation = useSecuritySimulation(1500);
  const [pulseMetric, setPulseMetric] = useState<number | null>(null);

  // Pulse effect when metrics update
  useEffect(() => {
    if (isOpen) {
      const randomMetric = Math.floor(Math.random() * 4);
      setPulseMetric(randomMetric);
      const timeout = setTimeout(() => setPulseMetric(null), 500);
      return () => clearTimeout(timeout);
    }
  }, [simulation.socMetrics.activeIncidents, simulation.threatData.blockedAttacks, isOpen]);

  if (!widget) return null;

  const Icon = widget.icon;
  const description = widgetDescriptions[widget.id] || 'Dette sikkerhedsmodul overvåger og beskytter din infrastruktur i realtid.';
  const actions = widgetActions[widget.id] || ['View Details', 'Configure', 'Export Report'];

  // Helper to get status
  const getStatus = (condition: boolean, ifTrue: MetricStatus, ifFalse: MetricStatus): MetricStatus => 
    condition ? ifTrue : ifFalse;

  // Generate dynamic metrics based on widget type
  const getDynamicMetrics = (): DynamicMetric[] => {
    switch (widget.id) {
      case 'soc-dashboard':
        return [
          { label: 'Aktive Incidents', value: String(simulation.socMetrics.activeIncidents), status: getStatus(simulation.socMetrics.activeIncidents > 3, 'critical', 'warning') },
          { label: 'Løste (24h)', value: String(simulation.socMetrics.resolvedToday), status: 'good' as MetricStatus },
          { label: 'MTTD', value: `${simulation.socMetrics.mttd} min`, trend: 'down' as MetricTrend },
          { label: 'MTTR', value: `${simulation.socMetrics.mttr} min`, trend: 'down' as MetricTrend },
        ];
      case 'threat-map':
        return [
          { label: 'Live Angreb', value: String(simulation.liveAttacks), status: 'warning' as MetricStatus },
          { label: 'Blokerede IPs', value: simulation.networkMetrics.blockedIPs.toLocaleString(), status: 'good' as MetricStatus },
          { label: 'Top Kilde', value: 'CN (34%)', status: 'warning' as MetricStatus },
          { label: 'Traffic', value: `${simulation.networkMetrics.inboundGbps} Gbps`, trend: 'stable' as MetricTrend },
        ];
      case 'malware-detection':
        return [
          { label: 'Detekteret (24h)', value: String(simulation.malwareMetrics.detected24h), status: 'warning' as MetricStatus },
          { label: 'Ransomware', value: String(simulation.malwareMetrics.ransomware), status: getStatus(simulation.malwareMetrics.ransomware > 2, 'critical', 'warning') },
          { label: 'Trojans', value: String(simulation.malwareMetrics.trojans), status: 'warning' as MetricStatus },
          { label: 'Quarantined', value: String(simulation.malwareMetrics.quarantined), status: 'good' as MetricStatus },
        ];
      case 'firewall':
        return [
          { label: 'Status', value: simulation.firewallMetrics.status.toUpperCase(), status: 'good' as MetricStatus },
          { label: 'Blocked (24h)', value: simulation.firewallMetrics.blocked24h.toLocaleString(), status: 'good' as MetricStatus },
          { label: 'Allowed', value: simulation.firewallMetrics.allowed24h.toLocaleString(), trend: 'stable' as MetricTrend },
          { label: 'Rules', value: simulation.firewallMetrics.rulesActive.toLocaleString(), status: 'good' as MetricStatus },
        ];
      case 'ddos-monitor': {
        const ddosStatus: MetricStatus = simulation.networkMetrics.ddosStatus === 'normal' ? 'good' : simulation.networkMetrics.ddosStatus === 'elevated' ? 'warning' : 'critical';
        return [
          { label: 'Status', value: simulation.networkMetrics.ddosStatus.toUpperCase(), status: ddosStatus },
          { label: 'Inbound', value: `${simulation.networkMetrics.inboundGbps} Gbps`, trend: 'stable' as MetricTrend },
          { label: 'Packets/sec', value: `${(simulation.networkMetrics.packetsPerSec / 1000000).toFixed(2)}M`, trend: 'stable' as MetricTrend },
          { label: 'Connections', value: simulation.networkMetrics.activeConnections.toLocaleString(), trend: 'up' as MetricTrend },
        ];
      }
      case 'vpn-status':
        return [
          { label: 'Status', value: 'CONNECTED', status: 'good' as MetricStatus },
          { label: 'Users Online', value: String(simulation.vpnUsers), trend: 'stable' as MetricTrend },
          { label: 'Bandwidth', value: `${simulation.networkMetrics.outboundGbps} Gbps`, trend: 'up' as MetricTrend },
          { label: 'Tunnels', value: '12', status: 'good' as MetricStatus },
        ];
      case 'threat-level': {
        const threatStatus: MetricStatus = simulation.threatData.level === 'LOW' ? 'good' : simulation.threatData.level === 'MEDIUM' ? 'warning' : 'critical';
        const threatTrend: MetricTrend = simulation.threatData.score > 50 ? 'up' : 'down';
        return [
          { label: 'Threat Level', value: simulation.threatData.level, status: threatStatus },
          { label: 'Risk Score', value: `${simulation.threatData.score}/100`, trend: threatTrend },
          { label: 'Active Threats', value: String(simulation.threatData.activeThreats), status: getStatus(simulation.threatData.activeThreats > 2, 'warning', 'good') },
          { label: 'Blocked', value: simulation.threatData.blockedAttacks.toLocaleString(), status: 'good' as MetricStatus },
        ];
      }
      case 'security-alerts':
        return [
          { label: 'Active Alerts', value: String(simulation.socMetrics.activeIncidents + simulation.socMetrics.criticalAlerts), status: 'critical' as MetricStatus },
          { label: 'Critical', value: String(simulation.socMetrics.criticalAlerts), status: 'critical' as MetricStatus },
          { label: 'Warning', value: String(simulation.socMetrics.warningAlerts), status: 'warning' as MetricStatus },
          { label: 'Info', value: String(simulation.socMetrics.infoAlerts), status: 'good' as MetricStatus },
        ];
      default:
        return [
          { label: 'Status', value: 'ACTIVE', status: 'good' as MetricStatus },
          { label: 'Last Check', value: '< 1 min', trend: 'stable' as MetricTrend },
          { label: 'Health', value: `${simulation.complianceScore}%`, status: 'good' as MetricStatus },
          { label: 'Uptime', value: '99.9%', status: 'good' as MetricStatus },
        ];
    }
  };

  const metrics = getDynamicMetrics();

  const getStatusColor = (status?: MetricStatus) => {
    switch (status) {
      case 'good': return 'text-green-400';
      case 'warning': return 'text-yellow-400';
      case 'critical': return 'text-red-400';
      default: return 'text-primary';
    }
  };

  const getSeverityBadge = (severity: 'info' | 'warning' | 'critical') => {
    switch (severity) {
      case 'critical': return <Badge variant="destructive" className="text-[8px] px-1 py-0 animate-pulse">CRITICAL</Badge>;
      case 'warning': return <Badge variant="secondary" className="text-[8px] px-1 py-0 bg-yellow-500/20 text-yellow-400">WARNING</Badge>;
      default: return <Badge variant="secondary" className="text-[8px] px-1 py-0 bg-blue-500/20 text-blue-400">INFO</Badge>;
    }
  };

  const getTrendIcon = (trend?: 'up' | 'down' | 'stable') => {
    switch (trend) {
      case 'up': return <TrendingUp className="w-3 h-3 text-green-400" />;
      case 'down': return <TrendingDown className="w-3 h-3 text-red-400" />;
      default: return <Activity className="w-3 h-3 text-muted-foreground" />;
    }
  };

  return (
    <Dialog open={isOpen} onOpenChange={onClose}>
      <DialogContent className="max-w-2xl bg-background/95 backdrop-blur-xl border-primary/30">
        <DialogHeader>
          <DialogTitle className="flex items-center gap-3 font-mono text-primary">
            <div className="p-2 bg-primary/10 rounded-lg relative">
              <Icon className="w-5 h-5" />
              <div className="absolute -top-1 -right-1 w-2 h-2 bg-green-500 rounded-full animate-pulse" />
            </div>
            <div className="flex-1">
              <span className="text-lg">{widget.name}</span>
              <Badge variant="outline" className="ml-3 text-[10px]">{widget.category.toUpperCase()}</Badge>
            </div>
            <div className="flex items-center gap-2 text-xs text-green-400">
              <Zap className="w-3 h-3" />
              <span className="font-mono">LIVE</span>
            </div>
          </DialogTitle>
        </DialogHeader>

        {/* Description */}
        <p className="text-sm text-muted-foreground leading-relaxed pt-2">
          {description}
        </p>

        <Tabs defaultValue="live" className="w-full">
          <TabsList className="grid w-full grid-cols-2 bg-secondary/30">
            <TabsTrigger value="live" className="font-mono text-xs gap-2">
              <Zap className="w-3 h-3" />
              LIVE DATA
            </TabsTrigger>
            <TabsTrigger value="schema" className="font-mono text-xs gap-2">
              <Code className="w-3 h-3" />
              SCHEMA
            </TabsTrigger>
          </TabsList>

          <TabsContent value="live" className="space-y-6 pt-4">
            {/* Widget Preview */}
            <div className="bg-secondary/20 rounded-lg p-4 border border-border/50 relative overflow-hidden">
              <div className="absolute top-2 right-2 flex items-center gap-1 text-[10px] text-green-400 font-mono">
                <div className="w-1.5 h-1.5 bg-green-400 rounded-full animate-pulse" />
                REAL-TIME
              </div>
              <div className="h-32">
                {widget.component}
              </div>
            </div>

            {/* Metrics Grid - Live updating */}
            <div>
              <h4 className="text-xs font-mono text-muted-foreground mb-3 flex items-center gap-2">
                <Activity className="w-3 h-3" />
                KEY METRICS
                <span className="text-green-400 text-[10px] ml-auto">● Live</span>
              </h4>
              <div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
                {metrics.map((metric, i) => (
                  <div 
                    key={i} 
                    className={`bg-secondary/30 rounded-lg p-3 border transition-all duration-300 ${
                      pulseMetric === i ? 'border-primary/50 shadow-[0_0_10px_rgba(var(--primary),0.3)]' : 'border-border/30'
                    }`}
                  >
                    <div className="text-[10px] text-muted-foreground mb-1">{metric.label}</div>
                    <div className="flex items-center justify-between">
                      <span className={`text-lg font-mono transition-all duration-300 ${getStatusColor(metric.status)}`}>
                        {metric.value}
                      </span>
                      {metric.trend && getTrendIcon(metric.trend)}
                    </div>
                  </div>
                ))}
              </div>
            </div>

            {/* Recent Events - Live feed */}
            <div>
              <h4 className="text-xs font-mono text-muted-foreground mb-3 flex items-center gap-2">
                <Clock className="w-3 h-3" />
                LIVE EVENT FEED
                <span className="text-green-400 text-[10px] ml-auto">● Live</span>
              </h4>
              <div className="space-y-2 max-h-40 overflow-y-auto">
                {simulation.events.slice(0, 5).map((event, i) => (
                  <div 
                    key={event.id} 
                    className={`flex items-center gap-3 bg-secondary/20 rounded-lg p-2 border border-border/30 transition-all duration-500 ${
                      i === 0 ? 'animate-pulse border-primary/30' : ''
                    }`}
                  >
                    <span className="text-[10px] font-mono text-primary/70 w-16">{event.time}</span>
                    <span className="flex-1 text-xs text-muted-foreground truncate">{event.event}</span>
                    {getSeverityBadge(event.severity)}
                  </div>
                ))}
              </div>
            </div>

            {/* Quick Actions */}
            <div>
              <h4 className="text-xs font-mono text-muted-foreground mb-3 flex items-center gap-2">
                <Wifi className="w-3 h-3" />
                QUICK ACTIONS
              </h4>
              <div className="flex flex-wrap gap-2">
                {actions.map((action, i) => (
                  <Button key={i} variant="outline" size="sm" className="text-xs font-mono gap-2 hover:bg-primary/10 hover:border-primary/50 transition-colors">
                    {action}
                    <ExternalLink className="w-3 h-3" />
                  </Button>
                ))}
                <Button variant="ghost" size="sm" className="text-xs font-mono gap-2 text-green-400 hover:text-green-300">
                  <RefreshCw className="w-3 h-3 animate-spin" style={{ animationDuration: '3s' }} />
                  Auto-Refresh ON
                </Button>
              </div>
            </div>
          </TabsContent>

          <TabsContent value="schema" className="pt-4">
            {/* Widget Schema / Metadata */}
            <div className="space-y-4">
              <div className="flex items-center gap-2 text-xs text-muted-foreground mb-2">
                <Database className="w-3 h-3" />
                <span>Widget metadata definerer hvad denne widget kan og kræver i økosystemet</span>
              </div>
              
              {widgetRegistry.get(widget.id) ? (
                <WidgetSchemaViewer widgetId={widget.id} />
              ) : (
                <div className="p-6 border border-dashed border-border/50 rounded-lg text-center">
                  <Info className="w-8 h-8 text-muted-foreground mx-auto mb-3" />
                  <p className="text-sm text-muted-foreground">
                    Schema metadata er endnu ikke defineret for denne widget.
                  </p>
                  <p className="text-xs text-muted-foreground/70 mt-2">
                    Tilføj widget til registret for at aktivere økosystem-integration.
                  </p>
                </div>
              )}

              {widgetRegistry.get(widget.id) && (
                <div className="mt-4 p-3 bg-primary/5 rounded-lg border border-primary/20">
                  <h5 className="text-xs font-mono text-primary mb-2 flex items-center gap-2">
                    <Globe className="w-3 h-3" />
                    KOMPATIBLE WIDGETS
                  </h5>
                  <div className="flex flex-wrap gap-2">
                    {widgetRegistry.findCompatible(widget.id).slice(0, 5).map(compatible => (
                      <Badge key={compatible.id} variant="secondary" className="text-[10px]">
                        {compatible.name}
                      </Badge>
                    ))}
                    {widgetRegistry.findCompatible(widget.id).length === 0 && (
                      <span className="text-xs text-muted-foreground">Ingen kompatible widgets fundet</span>
                    )}
                  </div>
                </div>
              )}
            </div>
          </TabsContent>
        </Tabs>
      </DialogContent>
    </Dialog>
  );
};

export default WidgetDetailModal;