diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 32c4734..4a17b75 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -330,6 +330,8 @@ function RouteTracker() {
const p = location.pathname;
if (p.startsWith('/investigation/ja4/')) {
saveRecent({ type: 'ja4', value: decodeURIComponent(p.split('/investigation/ja4/')[1] || '') });
+ } else if (p.startsWith('/investigation/ip/')) {
+ // Redirigé — ne pas sauvegarder l'alias (la route finale /investigation/:ip sera sauvegardée)
} else if (p.startsWith('/investigation/')) {
saveRecent({ type: 'ip', value: decodeURIComponent(p.split('/investigation/')[1] || '') });
} else if (p.startsWith('/entities/subnet/')) {
diff --git a/frontend/src/components/BruteForceView.tsx b/frontend/src/components/BruteForceView.tsx
index 124cdf7..fede15e 100644
--- a/frontend/src/components/BruteForceView.tsx
+++ b/frontend/src/components/BruteForceView.tsx
@@ -1,6 +1,8 @@
import { useState, useEffect, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import DataTable, { Column } from './ui/DataTable';
+import { InfoTip } from './ui/Tooltip';
+import { TIPS } from './ui/tooltips';
// ─── Types ────────────────────────────────────────────────────────────────────
@@ -87,12 +89,14 @@ function AttackersTable({
{
key: 'total_params',
label: 'Params',
+ tooltip: TIPS.params_combos,
align: 'right',
render: (v: number) => formatNumber(v),
},
{
key: 'ja4',
label: 'JA4',
+ tooltip: TIPS.ja4,
render: (v: string) => (
{v ? `${v.slice(0, 16)}…` : '—'}
@@ -163,9 +167,9 @@ function TargetRow({ t, navigate }: { t: BruteForceTarget; navigate: (path: stri
{formatNumber(t.total_params)} |
{t.attack_type === 'credential_stuffing' ? (
- 💳 Credential Stuffing
+ 💳 Credential Stuffing
) : (
- 🔍 Énumération
+ 🔍 Énumération
)}
|
@@ -380,9 +384,15 @@ export function BruteForceView() {
| Host (cliquer pour détails) |
IPs distinctes |
Total hits |
- Params combos |
+
+ Params combos
+
+ |
Type d'attaque |
- Top JA4 |
+
+ Top JA4
+
+ |
diff --git a/frontend/src/components/HeaderFingerprintView.tsx b/frontend/src/components/HeaderFingerprintView.tsx
index aaa24a1..0312b17 100644
--- a/frontend/src/components/HeaderFingerprintView.tsx
+++ b/frontend/src/components/HeaderFingerprintView.tsx
@@ -1,6 +1,7 @@
import { useState, useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import DataTable, { Column } from './ui/DataTable';
+import { TIPS } from './ui/tooltips';
// ─── Types ────────────────────────────────────────────────────────────────────
@@ -140,6 +141,7 @@ export function HeaderFingerprintView() {
{
key: 'hash',
label: 'Hash cluster',
+ tooltip: TIPS.hash_cluster,
sortable: true,
render: (_, row) => (
@@ -158,6 +160,7 @@ export function HeaderFingerprintView() {
{
key: 'avg_browser_score',
label: 'Browser Score',
+ tooltip: TIPS.browser_score,
sortable: true,
render: (v) => (
@@ -171,6 +174,7 @@ export function HeaderFingerprintView() {
{
key: 'ua_ch_mismatch_pct',
label: 'UA/CH Mismatch %',
+ tooltip: TIPS.ua_mismatch,
sortable: true,
align: 'right',
render: (v) => (
@@ -191,6 +195,7 @@ export function HeaderFingerprintView() {
{
key: 'top_sec_fetch_modes',
label: 'Sec-Fetch modes',
+ tooltip: TIPS.sec_fetch,
sortable: false,
render: (v) => (
diff --git a/frontend/src/components/InvestigationView.tsx b/frontend/src/components/InvestigationView.tsx
index c4183eb..20b4c79 100644
--- a/frontend/src/components/InvestigationView.tsx
+++ b/frontend/src/components/InvestigationView.tsx
@@ -7,6 +7,8 @@ import { UserAgentAnalysis } from './analysis/UserAgentAnalysis';
import { CorrelationSummary } from './analysis/CorrelationSummary';
import { CorrelationGraph } from './CorrelationGraph';
import { ReputationPanel } from './ReputationPanel';
+import { InfoTip } from './ui/Tooltip';
+import { TIPS } from './ui/tooltips';
// ─── Multi-source Activity Summary Widget ─────────────────────────────────────
@@ -33,7 +35,7 @@ function RiskGauge({ score }: { score: number }) {
transform="rotate(-90 40 40)" />
{score}
- Risk Score
+ Risk Score
);
}
@@ -113,9 +115,9 @@ function IPActivitySummary({ ip }: { ip: string }) {
0} label={`ML: ${data.ml.total_detections} détections`} color="threat-critical" />
-
-
-
+
+
+
{/* Detail grid */}
@@ -137,7 +139,7 @@ function IPActivitySummary({ ip }: { ip: string }) {
)}
{data.tcp_spoofing.detected && (
-
TCP Spoofing
+
TCP Spoofing
TTL {data.tcp_spoofing.tcp_ttl} → {data.tcp_spoofing.suspected_os}
UA déclare: {data.tcp_spoofing.declared_os}
@@ -220,8 +222,8 @@ function FingerprintCoherenceWidget({ ip }: { ip: string }) {
{vs.icon}
{vs.label}
-
- Score de spoofing:
{data.spoofing_score}/100
+
+ Score de spoofing: {data.spoofing_score}/100
@@ -250,14 +252,17 @@ function FingerprintCoherenceWidget({ ip }: { ip: string }) {
{/* Key indicators */}
{[
- { label: 'UA/CH mismatch', value: `${data.indicators.ua_ch_mismatch_rate}%`, warn: data.indicators.ua_ch_mismatch_rate > 20 },
- { label: 'Browser score', value: `${data.indicators.avg_browser_score}/100`, warn: data.indicators.avg_browser_score > 60 },
- { label: 'JA4 distincts', value: data.indicators.distinct_ja4_count, warn: data.indicators.distinct_ja4_count > 2 },
- { label: 'JA4 rares', value: `${data.indicators.rare_ja4_rate}%`, warn: data.indicators.rare_ja4_rate > 50 },
+ { 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) => (
{ind.value}
-
{ind.label}
+
+ {ind.label}
+
+
))}
@@ -376,7 +381,10 @@ export function InvestigationView() {
-
🔏 JA4 Légitimes (baseline)
+
+ 🔏 JA4 Légitimes (baseline)
+
+
Comparez les fingerprints de cette IP avec la baseline des JA4 légitimes pour évaluer le risque de spoofing.