import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; interface InvestigationPanelProps { entityType: 'ip' | 'ja4' | 'asn' | 'host'; entityValue: string; onClose: () => void; } interface AttributeValue { value: string; count: number; percentage: number; first_seen?: string; last_seen?: string; } interface EntityData { type: string; value: string; total_detections: number; unique_ips: number; threat_level?: string; anomaly_score?: number; country_code?: string; asn_number?: string; user_agents?: { value: string; count: number }[]; ja4s?: string[]; hosts?: string[]; attributes?: { user_agents?: AttributeValue[]; ja4?: AttributeValue[]; countries?: AttributeValue[]; asns?: AttributeValue[]; hosts?: AttributeValue[]; }; } export function InvestigationPanel({ entityType, entityValue, onClose }: InvestigationPanelProps) { const navigate = useNavigate(); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [classifying, setClassifying] = useState(false); const [showAllUA, setShowAllUA] = useState(false); useEffect(() => { const fetchData = async () => { setLoading(true); try { const response = await fetch(`/api/variability/${entityType}/${encodeURIComponent(entityValue)}`); if (response.ok) { const result = await response.json(); setData(result); } } catch (error) { console.error('Error fetching entity data:', error); } finally { setLoading(false); } }; fetchData(); }, [entityType, entityValue]); const getSeverityColor = (score?: number) => { if (!score) return 'bg-gray-500'; if (score < -0.7) return 'bg-threat-critical'; if (score < -0.3) return 'bg-threat-high'; if (score < 0) return 'bg-threat-medium'; return 'bg-threat-low'; }; const getSeverityLabel = (score?: number) => { if (!score) return 'Unknown'; if (score < -0.7) return 'CRITICAL'; if (score < -0.3) return 'HIGH'; if (score < 0) return 'MEDIUM'; return 'LOW'; }; const getCountryFlag = (code?: string) => { if (!code) return ''; return code.toUpperCase().replace(/./g, char => String.fromCodePoint(char.charCodeAt(0) + 127397)); }; const handleQuickClassify = async (label: string) => { setClassifying(true); try { await fetch('/api/analysis/classifications', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ [entityType]: entityValue, label, tags: ['quick-classification'], comment: 'Classification rapide depuis panel latéral', confidence: 0.7, analyst: 'soc_user' }) }); alert(`Classification sauvegardée: ${label}`); } catch (error) { alert('Erreur lors de la classification'); } finally { setClassifying(false); } }; return (
{/* Backdrop */}
{/* Panel */}
{/* Header */}
{entityType === 'ip' && '🌐'} {entityType === 'ja4' && '🔐'} {entityType === 'asn' && '🏢'} {entityType === 'host' && '🖥️'}
{entityType.toUpperCase()}
{entityValue}
{/* Content */}
{loading ? (
Chargement...
) : data ? ( <> {/* Quick Stats */}
{/* Risk Score */}
Score de Risque Estimé
{getSeverityLabel(data.anomaly_score)}
{/* User-Agents */} {data.attributes?.user_agents && data.attributes.user_agents.length > 0 && (
🤖 User-Agents ({data.attributes.user_agents.length})
{(showAllUA ? data.attributes.user_agents : data.attributes.user_agents.slice(0, 5)).map((ua: any, idx: number) => (
{ua.value}
{ua.count} détections • {ua.percentage.toFixed(1)}%
))} {data.attributes.user_agents.length > 5 && ( )}
)} {/* JA4 Fingerprints */} {data.attributes?.ja4 && data.attributes.ja4.length > 0 && (
🔐 JA4 Fingerprints ({data.attributes.ja4.length})
{data.attributes.ja4.slice(0, 5).map((ja4: any, idx: number) => (
navigate(`/investigation/ja4/${encodeURIComponent(ja4.value)}`)} >
{ja4.value}
{ja4.count}
))}
)} {/* Countries */} {data.attributes?.countries && data.attributes.countries.length > 0 && (
🌍 Pays ({data.attributes.countries.length})
{data.attributes.countries.slice(0, 5).map((country: any, idx: number) => (
{getCountryFlag(country.value)}
{country.value}
{country.percentage.toFixed(1)}%
{country.count}
))}
)} {/* Quick Classification */}
⚡ Classification Rapide
) : (
Aucune donnée disponible
)}
); } // Stat Box Component function StatBox({ label, value }: { label: string; value: string }) { return (
{label}
{value}
); }