import { useEffect, useState } from 'react'; interface JA4SubnetData { subnet: string; count: number; } interface JA4Analysis { ja4: string; shared_ips_count: number; top_subnets: JA4SubnetData[]; other_ja4_for_ip: string[]; } interface JA4AnalysisProps { ip: string; } export function JA4Analysis({ ip }: JA4AnalysisProps) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchJA4Analysis = async () => { setLoading(true); try { const response = await fetch(`/api/analysis/${encodeURIComponent(ip)}/ja4`); if (!response.ok) throw new Error('Erreur chargement JA4'); const result = await response.json(); setData(result); } catch (err) { setError(err instanceof Error ? err.message : 'Erreur inconnue'); } finally { setLoading(false); } }; fetchJA4Analysis(); }, [ip]); if (loading) { return (
Chargement...
); } if (error || !data || !data.ja4) { return (
JA4 non disponible
); } return (

3. JA4 FINGERPRINT ANALYSIS

{data.shared_ips_count > 50 && ( 🔴 {data.shared_ips_count} IPs )}
{/* JA4 Fingerprint */}
JA4 Fingerprint
{data.ja4}
{/* IPs avec même JA4 */}
IPs avec le MÊME JA4 (24h)
{data.shared_ips_count}
{data.shared_ips_count > 50 && (
🔴 PATTERN: Même outil/bot sur {data.shared_ips_count} IPs
)}
{/* Autres JA4 pour cette IP */}
Autres JA4 pour cette IP
{data.other_ja4_for_ip.length > 0 ? (
{data.other_ja4_for_ip.slice(0, 3).map((ja4, idx) => (
{ja4}
))} {data.other_ja4_for_ip.length > 3 && (
+{data.other_ja4_for_ip.length - 3} autres
)}
) : (
1 seul JA4 → Comportement stable
)}
{/* Top subnets */} {data.top_subnets.length > 0 && (
Top subnets pour ce JA4
{data.top_subnets.map((subnet, idx) => (
{subnet.subnet}
{subnet.count} IPs
))}
)}
); }