From da6fef87fd840e60d4bd6bfc35773a80934c5946 Mon Sep 17 00:00:00 2001 From: SOC Analyst Date: Thu, 19 Mar 2026 12:24:53 +0100 Subject: [PATCH] feat: tooltips universels sur l'ensemble du site MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CampaignsView: Score menace, JA4, ASN, Tendance, Score, Détections, Confiance - FingerprintsView: colonnes avec tooltips via DataTable - JA4InvestigationView: IPs Uniques, JA4, ASN, Score - SubnetInvestigation: colonnes clés avec tooltips - CorrelationGraph: légende et badges - EntityInvestigationView: sections headers, JA4, ASN - IncidentsView: stat cards, sévérité, ASN, Score de risque - Fix: suppression des imports dupliqués dans CampaignsView Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- frontend/src/components/BruteForceView.tsx | 2 +- frontend/src/components/CampaignsView.tsx | 19 +++++++++++----- frontend/src/components/CorrelationGraph.tsx | 4 +++- .../components/EntityInvestigationView.tsx | 8 ++++--- frontend/src/components/FingerprintsView.tsx | 22 ++++++++++--------- .../src/components/HeaderFingerprintView.tsx | 2 ++ frontend/src/components/IncidentsView.tsx | 22 ++++++++++--------- .../src/components/JA4InvestigationView.tsx | 12 +++++----- frontend/src/components/PivotView.tsx | 9 +++++--- .../src/components/SubnetInvestigation.tsx | 10 +++++---- frontend/src/components/ThreatIntelView.tsx | 4 +++- 11 files changed, 70 insertions(+), 44 deletions(-) diff --git a/frontend/src/components/BruteForceView.tsx b/frontend/src/components/BruteForceView.tsx index fede15e..661a761 100644 --- a/frontend/src/components/BruteForceView.tsx +++ b/frontend/src/components/BruteForceView.tsx @@ -388,7 +388,7 @@ export function BruteForceView() { Params combos - Type d'attaque + Type d'attaque Top JA4 diff --git a/frontend/src/components/CampaignsView.tsx b/frontend/src/components/CampaignsView.tsx index 6ceaee2..dc412b9 100644 --- a/frontend/src/components/CampaignsView.tsx +++ b/frontend/src/components/CampaignsView.tsx @@ -2,6 +2,8 @@ import { useState, useEffect, useCallback, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import DataTable, { Column } from './ui/DataTable'; import ThreatBadge from './ui/ThreatBadge'; +import { InfoTip } from './ui/Tooltip'; +import { TIPS } from './ui/tooltips'; // ─── Types ──────────────────────────────────────────────────────────────────── @@ -433,7 +435,7 @@ function ClusterCard({ cluster, expanded, ips, loadingIPs, onToggle, onNavigate {cluster.asn && ( - ASN {cluster.asn} + ASN {cluster.asn} )} {cluster.primary_target && ( @@ -447,7 +449,7 @@ function ClusterCard({ cluster, expanded, ips, loadingIPs, onToggle, onNavigate
{cluster.ja4 && (
- JA4 + JA4 {cluster.ja4} @@ -477,7 +479,10 @@ function ClusterCard({ cluster, expanded, ips, loadingIPs, onToggle, onNavigate {/* Score bar */}
- Score menace + + Score menace + + {cluster.score}/100
@@ -532,7 +537,7 @@ function ClusterCard({ cluster, expanded, ips, loadingIPs, onToggle, onNavigate IP JA4 Détections - Confiance + Confiance @@ -759,6 +764,7 @@ function BehavioralMatrix({ clusters }: { clusters: ClusterData[] }) { { key: 'score', label: 'Score', + tooltip: TIPS.risk_score_inv, align: 'right', render: (v: number) => ( @@ -774,6 +780,7 @@ function BehavioralMatrix({ clusters }: { clusters: ClusterData[] }) { { key: 'trend', label: 'Tendance', + tooltip: TIPS.tendance, sortable: false, render: (_: string, row: BehavioralRow) => row.trend === 'up' ? ( @@ -916,7 +923,7 @@ function BotnetRow({ item, onInvestigate }: { item: BotnetItem; onInvestigate: (
- {badge.label} + {badge.label}
diff --git a/frontend/src/components/EntityInvestigationView.tsx b/frontend/src/components/EntityInvestigationView.tsx index 4dd770c..6a390f5 100644 --- a/frontend/src/components/EntityInvestigationView.tsx +++ b/frontend/src/components/EntityInvestigationView.tsx @@ -1,5 +1,7 @@ import { useParams, useNavigate } from 'react-router-dom'; import { useEffect, useState } from 'react'; +import { InfoTip } from './ui/Tooltip'; +import { TIPS } from './ui/tooltips'; interface EntityStats { entity_type: string; @@ -194,7 +196,7 @@ export function EntityInvestigationView() { {/* Panel 2: JA4 Fingerprints */}
-

2. JA4 Fingerprints

+

2. JA4 Fingerprints

{data.related.ja4s.slice(0, 10).map((ja4, idx) => (
@@ -251,7 +253,7 @@ export function EntityInvestigationView() { {/* Panel 4: Client Headers */}
-

4. Client Headers

+

4. Client Headers

{data.client_headers.slice(0, 10).map((header, idx) => (
@@ -347,7 +349,7 @@ export function EntityInvestigationView() {
{/* ASNs */}
-

ASNs

+

ASNs

{data.related.asns.slice(0, 10).map((asn, idx) => (
diff --git a/frontend/src/components/FingerprintsView.tsx b/frontend/src/components/FingerprintsView.tsx index 9d2d13b..c3969c0 100644 --- a/frontend/src/components/FingerprintsView.tsx +++ b/frontend/src/components/FingerprintsView.tsx @@ -2,6 +2,8 @@ import { useState, useEffect, useCallback, Fragment, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import DataTable, { Column } from './ui/DataTable'; import ThreatBadge from './ui/ThreatBadge'; +import { InfoTip } from './ui/Tooltip'; +import { TIPS } from './ui/tooltips'; // ─── Types ──────────────────────────────────────────────────────────────────── @@ -489,7 +491,7 @@ function SpoofingPanel() { JA4 suspects de spoofing — {data.total} fingerprints analysés - Score de spoofing [0-100] + Score de spoofing [0-100]
{data.items.length === 0 && ( @@ -563,11 +565,11 @@ function SpoofingPanel() { {/* Indicators */}
{[ - { label: 'UA/CH mismatch', value: `${item.indicators.ua_ch_mismatch_pct}%`, warn: item.indicators.ua_ch_mismatch_pct > 20 }, - { label: 'Browser score', value: `${item.indicators.avg_browser_score}/100`, warn: item.indicators.avg_browser_score > 50 }, - { label: 'SNI mismatch', value: `${item.indicators.sni_mismatch_pct}%`, warn: item.indicators.sni_mismatch_pct > 10 }, - { label: 'JA4 rare', value: `${item.indicators.rare_ja4_pct}%`, warn: item.indicators.rare_ja4_pct > 50 }, - { label: 'UA rotation', value: `${item.indicators.ua_rotating_pct}%`, warn: item.indicators.ua_rotating_pct > 10 }, + { label: 'UA/CH mismatch', value: `${item.indicators.ua_ch_mismatch_pct}%`, warn: item.indicators.ua_ch_mismatch_pct > 20, tip: TIPS.ua_mismatch }, + { label: 'Browser score', value: `${item.indicators.avg_browser_score}/100`, warn: item.indicators.avg_browser_score > 50, tip: TIPS.browser_score }, + { label: 'SNI mismatch', value: `${item.indicators.sni_mismatch_pct}%`, warn: item.indicators.sni_mismatch_pct > 10, tip: TIPS.sni_mismatch }, + { label: 'JA4 rare', value: `${item.indicators.rare_ja4_pct}%`, warn: item.indicators.rare_ja4_pct > 50, tip: TIPS.ja4_rare_pct }, + { label: 'UA rotation', value: `${item.indicators.ua_rotating_pct}%`, warn: item.indicators.ua_rotating_pct > 10, tip: TIPS.ua_rotation }, ].map((ind) => (
{ind.value}
-
{ind.label}
+
{ind.label}
))}
@@ -603,8 +605,8 @@ function SpoofingPanel() { {activeSubTab === 'matrix' && (
- - Matrice JA4 × User-Agent — {matrixData.length} fingerprints + + Matrice JA4 × User-Agent — {matrixData.length} fingerprints

Pour chaque JA4, répartition des User-Agents observés. 🎭 = spoofing suspect détecté. @@ -1204,7 +1206,7 @@ export function FingerprintsView() { onClick={() => handleColSort('botnet_score')} > - Score botnet + Score botnet {sortField === 'botnet_score' ? {sortDir === 'desc' ? '↓' : '↑'} : } diff --git a/frontend/src/components/HeaderFingerprintView.tsx b/frontend/src/components/HeaderFingerprintView.tsx index 0312b17..3c15ca3 100644 --- a/frontend/src/components/HeaderFingerprintView.tsx +++ b/frontend/src/components/HeaderFingerprintView.tsx @@ -241,12 +241,14 @@ export function HeaderFingerprintView() { { key: 'sec_fetch_mode', label: 'Sec-Fetch Mode', + tooltip: TIPS.sec_fetch_dest, sortable: true, render: (v) => {v || '—'}, }, { key: 'sec_fetch_dest', label: 'Sec-Fetch Dest', + tooltip: TIPS.sec_fetch_dest, sortable: true, render: (v) => {v || '—'}, }, diff --git a/frontend/src/components/IncidentsView.tsx b/frontend/src/components/IncidentsView.tsx index bd8df61..19409cc 100644 --- a/frontend/src/components/IncidentsView.tsx +++ b/frontend/src/components/IncidentsView.tsx @@ -1,5 +1,7 @@ import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; +import { InfoTip } from './ui/Tooltip'; +import { TIPS } from './ui/tooltips'; interface IncidentCluster { id: string; @@ -147,10 +149,10 @@ export function IncidentsView() { {baseline && (

{([ - { key: 'total_detections', label: 'Détections 24h', icon: '📊' }, - { key: 'unique_ips', label: 'IPs uniques', icon: '🖥️' }, - { key: 'critical_alerts', label: 'Alertes CRITICAL', icon: '🔴' }, - ] as { key: keyof BaselineData; label: string; icon: string }[]).map(({ key, label, icon }) => { + { key: 'total_detections', label: 'Détections 24h', icon: '📊', tip: TIPS.total_detections_stat }, + { key: 'unique_ips', label: 'IPs uniques', icon: '🖥️', tip: TIPS.unique_ips_stat }, + { key: 'critical_alerts', label: 'Alertes CRITICAL', icon: '🔴', tip: TIPS.risk_critical }, + ] as { key: keyof BaselineData; label: string; icon: string; tip: string }[]).map(({ key, label, icon, tip }) => { const m = baseline[key]; const up = m.pct_change > 0; const neutral = m.pct_change === 0; @@ -158,7 +160,7 @@ export function IncidentsView() {
{icon}
-
{label}
+
{label}
{m.today.toLocaleString('fr-FR')}
hier: {m.yesterday.toLocaleString('fr-FR')}
@@ -292,7 +294,7 @@ export function IncidentsView() {
- + {cluster.severity} {cluster.id} @@ -302,7 +304,7 @@ export function IncidentsView() {
{cluster.score}/100
-
Score de risque
+
Score de risque
@@ -327,11 +329,11 @@ export function IncidentsView() {
-
ASN
+
ASN
AS{cluster.asn || '?'}
-
Tendance
+
Tendance
-
JA4 Principal
+
JA4 Principal
{cluster.ja4}
)} diff --git a/frontend/src/components/JA4InvestigationView.tsx b/frontend/src/components/JA4InvestigationView.tsx index 26a5c97..aa78b71 100644 --- a/frontend/src/components/JA4InvestigationView.tsx +++ b/frontend/src/components/JA4InvestigationView.tsx @@ -1,6 +1,8 @@ import { useParams, useNavigate } from 'react-router-dom'; import { useEffect, useState } from 'react'; import { JA4CorrelationSummary } from './analysis/JA4CorrelationSummary'; +import { InfoTip } from './ui/Tooltip'; +import { TIPS } from './ui/tooltips'; interface JA4InvestigationData { ja4: string; @@ -164,7 +166,7 @@ export function JA4InvestigationView() {
-
JA4 Fingerprint
+
JA4 Fingerprint
{data.ja4}
@@ -176,7 +178,7 @@ export function JA4InvestigationView() {
- + @@ -247,7 +249,7 @@ export function JA4InvestigationView() {
-

🏢 TOP ASNs

+

🏢 TOP ASNs

{data.top_asns.map((asn, idx) => (
@@ -318,10 +320,10 @@ export function JA4InvestigationView() { ); } -function StatBox({ label, value }: { label: string; value: string }) { +function StatBox({ label, value, tip }: { label: string; value: string; tip?: string }) { return (
-
{label}
+
{label}{tip && }
{value}
); diff --git a/frontend/src/components/PivotView.tsx b/frontend/src/components/PivotView.tsx index 034cce7..4ecf728 100644 --- a/frontend/src/components/PivotView.tsx +++ b/frontend/src/components/PivotView.tsx @@ -12,6 +12,8 @@ import { useState, useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; +import { InfoTip } from './ui/Tooltip'; +import { TIPS } from './ui/tooltips'; // ─── Types ──────────────────────────────────────────────────────────────────── @@ -47,11 +49,11 @@ interface VariabilityData { type AttrKey = keyof VariabilityData['attributes']; -const ATTR_ROWS: { key: AttrKey; label: string; icon: string }[] = [ - { key: 'ja4', label: 'JA4 Fingerprint', icon: '🔐' }, +const ATTR_ROWS: { key: AttrKey; label: string; icon: string; tip?: string }[] = [ + { key: 'ja4', label: 'JA4 Fingerprint', icon: '🔐', tip: TIPS.ja4 }, { key: 'user_agents', label: 'User-Agents', icon: '🤖' }, { key: 'countries', label: 'Pays', icon: '🌍' }, - { key: 'asns', label: 'ASN', icon: '🏢' }, + { key: 'asns', label: 'ASN', icon: '🏢', tip: TIPS.asn }, { key: 'hosts', label: 'Hosts cibles', icon: '🖥️' }, { key: 'subnets', label: 'Subnets', icon: '🔷' }, ]; @@ -283,6 +285,7 @@ export function PivotView() {
{row.icon} {row.label} + {row.tip && }
{shared.size > 0 && (
diff --git a/frontend/src/components/SubnetInvestigation.tsx b/frontend/src/components/SubnetInvestigation.tsx index a86d45b..8649085 100644 --- a/frontend/src/components/SubnetInvestigation.tsx +++ b/frontend/src/components/SubnetInvestigation.tsx @@ -1,5 +1,7 @@ import { useEffect, useState } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; +import { InfoTip } from './ui/Tooltip'; +import { TIPS } from './ui/tooltips'; interface SubnetIP { ip: string; @@ -139,7 +141,7 @@ export function SubnetInvestigation() {
{stats.total_detections.toLocaleString()}
-
JA4 Uniques
+
JA4 Uniques
{stats.unique_ja4}
@@ -161,7 +163,7 @@ export function SubnetInvestigation() {
-
ASN Principal
+
ASN Principal
AS{stats.primary_asn}
@@ -187,8 +189,8 @@ export function SubnetInvestigation() { UA Pays ASN - Menace - Score + Menace + Score Actions diff --git a/frontend/src/components/ThreatIntelView.tsx b/frontend/src/components/ThreatIntelView.tsx index b2079d0..b5e16e4 100644 --- a/frontend/src/components/ThreatIntelView.tsx +++ b/frontend/src/components/ThreatIntelView.tsx @@ -1,4 +1,6 @@ import { useEffect, useState } from 'react'; +import { InfoTip } from './ui/Tooltip'; +import { TIPS } from './ui/tooltips'; interface Classification { ip?: string; @@ -229,7 +231,7 @@ export function ThreatIntelView() { Entité Label Tags - Confiance + Confiance Analyste