diff --git a/services/dashboard/backend/routes/api.py b/services/dashboard/backend/routes/api.py index c585170..ed5e039 100644 --- a/services/dashboard/backend/routes/api.py +++ b/services/dashboard/backend/routes/api.py @@ -1765,7 +1765,8 @@ async def browser_signatures() -> dict[str, Any]: f" countIf(h2_dict_family != '') AS sessions_matched, " f" countIf(tls_h2_family_mismatch > 0) AS sessions_mismatch, " f" round(100.0 * countIf(h2_dict_family != '') / greatest(countIf(h2_settings_known > 0), 1), 1) AS match_rate, " - f" round(100.0 * countIf(tls_h2_family_mismatch > 0) / greatest(countIf(h2_settings_known > 0), 1), 1) AS mismatch_rate " + f" round(100.0 * countIf(tls_h2_family_mismatch > 0) / greatest(countIf(h2_settings_known > 0), 1), 1) AS mismatch_rate, " + f" countIf(h2_priority_present > 0) AS sessions_with_priority " f"FROM {_DB}.view_ai_features_1h" ) if stats: @@ -1829,7 +1830,14 @@ async def browser_signatures() -> dict[str, Any]: f" h2_window_update_value AS wu_value, " f" hits, " f" h2_pseudo_ord_raw AS pseudo_order, " - f" fingerprint_coherence_score AS coherence " + f" fingerprint_coherence_score AS coherence, " + f" h2_header_table_size, " + f" h2_enable_push, " + f" h2_max_concurrent_streams, " + f" h2_initial_window_size, " + f" h2_max_frame_size, " + f" h2_max_header_list_size, " + f" h2_enable_connect_protocol " f"FROM {_DB}.view_ai_features_1h " f"WHERE tls_h2_family_mismatch > 0 " f"ORDER BY hits DESC " diff --git a/services/dashboard/backend/templates/browsers.html b/services/dashboard/backend/templates/browsers.html index 3b8e499..590bcb1 100644 --- a/services/dashboard/backend/templates/browsers.html +++ b/services/dashboard/backend/templates/browsers.html @@ -156,6 +156,7 @@ IP JA4 famille H2 famille + SETTINGS WU value Pseudo-order Hits @@ -163,7 +164,7 @@ - Chargement… + Chargement… @@ -525,8 +526,8 @@ async function loadBrowserData() { setText('pseudo-chromesafari', fmt(chrome + safari)); setText('pseudo-firefox', fmt(firefox)); setText('pseudo-other', fmt(other)); - // Pour h2_priority_present on n'a pas le chiffre direct — afficher N/A - setText('pseudo-priority', '—'); + // Pour h2_priority_present on utilise le compteur direct de l'API + setText('pseudo-priority', fmt(s.sessions_with_priority)); } // ─── Graphiques ────────────────────────────────────────────────────────── @@ -605,7 +606,7 @@ function renderMismatchBar(rows) { function renderSuspects(rows) { const tbody = document.getElementById('tbl-suspects-body'); if (!rows.length) { - tbody.innerHTML = 'Aucun mismatch détecté dans les 24 dernières heures'; + tbody.innerHTML = 'Aucun mismatch détecté dans les 24 dernières heures'; return; } const WU_LABELS = { @@ -615,6 +616,23 @@ function renderSuspects(rows) { 1073676289: 'go net/http', 0: 'absent', }; + // Noms courts des paramètres SETTINGS (ID → label) + const SETTINGS_NAMES = { + h2_header_table_size: '1', + h2_enable_push: '2', + h2_max_concurrent_streams: '3', + h2_initial_window_size: '4', + h2_max_frame_size: '5', + h2_max_header_list_size: '6', + h2_enable_connect_protocol: '8', + }; + function fmtSettings(r) { + const pairs = Object.entries(SETTINGS_NAMES) + .filter(([col]) => r[col] != null && r[col] !== -1) + .map(([col, id]) => `${id}:${r[col]}`); + if (!pairs.length) return ''; + return `${escHtml(pairs.join(', '))}`; + } tbody.innerHTML = rows.map(r => { const wuLabel = WU_LABELS[r.wu_value] || `${r.wu_value}`; const coh = r.coherence != null ? r.coherence.toFixed(2) : '—'; @@ -624,6 +642,7 @@ function renderSuspects(rows) { ${r.ip} ${r.ja4_family || '—'} ${h2fam} + ${fmtSettings(r)} ${wuLabel} ${r.pseudo_order || '—'} ${fmt(r.hits)}