🎭 Cohérence JA4 / User-Agent
{loading &&
Analyse en cours…
}
{error &&
Données insuffisantes pour cette IP
}
{data && vs && (
{/* Verdict badge + score */}
{vs.icon}
{vs.label}
Score de spoofing: {data.spoofing_score}/100
= 70 ? 'bg-threat-critical' :
data.spoofing_score >= 40 ? 'bg-threat-high' :
data.spoofing_score >= 20 ? 'bg-threat-medium' : 'bg-threat-low'
}`}
style={{ width: `${data.spoofing_score}%` }}
/>
{/* Explanation */}
{data.explanation.map((e, i) => (
-
• {e}
))}
{/* Key indicators */}
{[
{ label: 'UA/CH mismatch', tip: TIPS.ua_mismatch, value: `${data.indicators.ua_ch_mismatch_rate}%`, warn: data.indicators.ua_ch_mismatch_rate > 20 },
{ label: 'Browser score', tip: TIPS.browser_score, value: `${data.indicators.avg_browser_score}/100`, warn: data.indicators.avg_browser_score > 60 },
{ label: 'JA4 distincts', tip: TIPS.ja4_distinct, value: data.indicators.distinct_ja4_count, warn: data.indicators.distinct_ja4_count > 2 },
{ label: 'JA4 rares %', tip: TIPS.ja4_rare_pct, value: `${data.indicators.rare_ja4_rate}%`, warn: data.indicators.rare_ja4_rate > 50 },
].map((ind) => (
))}
{/* Top UAs */}
{data.user_agents.length > 0 && (
User-Agents observés
{data.user_agents.slice(0, 4).map((u, i) => (
{u.type}
{u.ua.length > 45 ? u.ua.slice(0, 45) + '…' : u.ua}
))}
)}
{/* JA4 links */}
{data.fingerprints.ja4_list.length > 0 && (
JA4 utilisés
{data.fingerprints.ja4_list.map((j4) => (
))}
)}
)}
);
}
// ─── Section "Attributs détectés" (données de variabilité, ex-DetailsView) ───
function Metric({ label, value, accent }: { label: string; value: string; accent?: boolean }) {
return (
);
}
function DetectionAttributesSection({ ip }: { ip: string }) {
const [open, setOpen] = useState(true); // ouvert par défaut
const { data, loading } = useVariability('ip', ip);
const first = data?.date_range.first_seen ? new Date(data.date_range.first_seen) : null;
const last = data?.date_range.last_seen ? new Date(data.date_range.last_seen) : null;
const sameDate = first && last && first.getTime() === last.getTime();
const fmt = (d: Date) => formatDateShort(d.toISOString());
return (
{open && (
{loading &&
Chargement…
}
{data && (
<>
{/* Métriques */}
{first && last && (
sameDate ? (
) : (
Période
{fmt(first)}
→ {fmt(last!)}
)
)}
{/* Insights */}
{data.insights.length > 0 && (
{data.insights.map((ins, i) => {
const s: Record
= {
warning: 'bg-yellow-500/10 border-yellow-500/40 text-yellow-400',
info: 'bg-blue-500/10 border-blue-500/40 text-blue-400',
success: 'bg-green-500/10 border-green-500/40 text-green-400',
};
return (
{ins.message}
);
})}
)}
{/* Attributs (JA4, hosts, ASN, pays, UA…) */}
>
)}
)}
);
}
export function InvestigationView() {
const { ip } = useParams<{ ip: string }>();
const navigate = useNavigate();
if (!ip) {
return (
IP non spécifiée
);
}
const handleClassify = (label: string, tags: string[], comment: string, confidence: number) => {
// Callback optionnel après classification
console.log('IP classifiée:', { ip, label, tags, comment, confidence });
};
return (
{/* Breadcrumb */}
{/* En-tête */}
Investigation: {ip}
Analyse de corrélations pour classification SOC
{/* Navigation ancres inter-sections */}
Aller à :
{[
{ id: 'section-attributs', label: '📡 Attributs' },
{ id: 'section-synthese', label: '🔎 Synthèse' },
{ id: 'section-reputation', label: '🌍 Réputation' },
{ id: 'section-correlations', label: '🕸️ Corrélations' },
{ id: 'section-geo', label: '🌐 Géo / JA4' },
{ id: 'section-classification', label: '🏷️ Classification' },
].map(({ id, label }) => (
{label}
))}
{/* Attributs détectés (ex-DetailsView) */}
{/* Synthèse multi-sources */}
{/* Réputation (1/3) + Graph de corrélations (2/3) */}
🌍 Réputation IP
🕸️ Graph de Corrélations
{/* Subnet / Country / JA4 */}
{/* User-Agents (1/2) + Classification (1/2) */}
{/* Cohérence JA4/UA (spoofing) */}
🔏 JA4 Légitimes (baseline)
Comparez les fingerprints de cette IP avec la baseline des JA4 légitimes pour évaluer le risque de spoofing.
);
}