fix: Bouton 'Voir détails' utilise sample_ip

🐛 CORRECTION:
• Problème: Les IPs n'étaient pas trouvées
• Cause: Utilisation du subnet (176.65.132.0) au lieu d'une IP réelle
• Solution: Ajout sample_ip + fallback getSampleIP()

BACKEND:
• API /api/incidents/clusters retourne sample_ip
• Utilisation de any(src_ip) dans la requête SQL
• Fallback sur None si pas d'IP trouvée

FRONTEND:
• Interface IncidentCluster: sample_ip optionnel
• Fonction getSampleIP() génère une IP depuis le subnet
• Fallback: sample_ip || getSampleIP(subnet)
• Tous les boutons utilisent la même logique

RÉSULTAT:
• Avant: /entities/ip/176.65.132.0 (n'existe pas)
• Après: /entities/ip/176.65.132.1 (IP valide)

 Build: SUCCESS
 Container: restarted

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
SOC Analyst
2026-03-14 22:45:59 +01:00
parent 4434fcee80
commit 1e0e5d211d
2 changed files with 30 additions and 6 deletions

View File

@ -9,6 +9,7 @@ interface IncidentCluster {
total_detections: number;
unique_ips: number;
subnet?: string;
sample_ip?: string;
ja4?: string;
primary_ua?: string;
primary_target?: string;
@ -112,6 +113,18 @@ export function IncidentsView() {
return address.replace(/^::ffff:/i, '');
};
// Générer une IP exemple depuis un subnet
const getSampleIP = (subnet: string): string => {
const clean = cleanIP(subnet);
const ipParts = clean.replace('/24', '').split('.');
if (ipParts.length === 4) {
// Remplacer le dernier octet par 1
ipParts[3] = '1';
return ipParts.join('.');
}
return cleanIP(subnet.split('/')[0]);
};
if (loading) {
return (
<div className="flex items-center justify-center h-64">
@ -309,13 +322,13 @@ export function IncidentsView() {
<div className="flex gap-2">
<button
onClick={() => navigate(`/investigation/${cleanIP(cluster.subnet?.split('/')[0] || '')}`)}
onClick={() => navigate(`/investigation/${cleanIP(cluster.sample_ip || getSampleIP(cluster.subnet || ''))}`)}
className="px-3 py-1.5 bg-accent-primary text-white rounded text-sm hover:bg-accent-primary/80 transition-colors"
>
Investiguer
</button>
<button
onClick={() => navigate(`/entities/ip/${cleanIP(cluster.subnet?.split('/')[0] || '')}`)}
onClick={() => navigate(`/entities/ip/${cleanIP(cluster.sample_ip || getSampleIP(cluster.subnet || ''))}`)}
className="px-3 py-1.5 bg-background-card text-text-primary rounded text-sm hover:bg-background-card/80 transition-colors"
>
Voir détails
@ -323,7 +336,7 @@ export function IncidentsView() {
<button
onClick={() => {
// Quick classify
navigate(`/bulk-classify?ips=${encodeURIComponent(cleanIP(cluster.subnet?.split('/')[0] || ''))}`);
navigate(`/bulk-classify?ips=${encodeURIComponent(cleanIP(cluster.sample_ip || getSampleIP(cluster.subnet || '')))}`);
}}
className="px-3 py-1.5 bg-background-card text-text-primary rounded text-sm hover:bg-background-card/80 transition-colors"
>