fix(dashboard): XSS escaping, ResizeObserver leak, WS reconnect timer

- Ajout de esc() dans api.js pour échapper les valeurs serveur avant injection innerHTML
- Application de esc() sur hostname, ip et agentId dans grid.js et popups.js
- Fix fuite mémoire ResizeObserver dans showDetail : déconnexion avant recréation (_resizeObs)
- Fix WebSocket reconnect : clearTimeout avant setTimeout pour éviter les timers concurrents (_reconnectTimer)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gilles Soulier
2026-05-22 12:46:37 +02:00
co-authored by Claude Sonnet 4.6
parent 555ddc3556
commit a19705ffda
4 changed files with 25 additions and 9 deletions
+8 -5
View File
@@ -1,6 +1,7 @@
const Popups = (() => {
let _currentAgentId = null;
let _agentCfgData = null;
let _resizeObs = null;
// ══ POPUP DÉTAIL ══
async function showDetail(agentId) {
@@ -50,7 +51,7 @@ const Popups = (() => {
const memPts = Charts.historyToMemPts(history);
const smartBtn = metrics?.smart
? `<div class="smart-btn ok" onclick="Popups.showSmart('${agentId}')" data-tip="Voir la santé complète du disque">
? `<div class="smart-btn ok" onclick="Popups.showSmart('${esc(agentId)}')" data-tip="Voir la santé complète du disque">
<div class="smart-dot"></div>
<span style="font-weight:600">SMART</span>
<span>·</span>
@@ -116,8 +117,8 @@ const Popups = (() => {
<div>
<div class="sec-title">INFORMATIONS</div>
<div class="meta-grid">
<div class="meta"><div class="meta-lbl">HOSTNAME</div><div class="meta-val">${agent.hostname}</div></div>
<div class="meta"><div class="meta-lbl">ADRESSE IP</div><div class="meta-val">${agent.ip || '—'}</div></div>
<div class="meta"><div class="meta-lbl">HOSTNAME</div><div class="meta-val">${esc(agent.hostname)}</div></div>
<div class="meta"><div class="meta-lbl">ADRESSE IP</div><div class="meta-val">${esc(agent.ip) || '—'}</div></div>
<div class="meta"><div class="meta-lbl">PROTOCOLES ACTIFS</div><div style="display:flex;gap:5px;margin-top:4px">${protos || '—'}</div></div>
<div class="meta"><div class="meta-lbl">DERNIER CONTACT</div><div class="meta-val">${new Date(agent.last_seen * 1000).toLocaleTimeString('fr-FR')}</div></div>
</div>
@@ -129,14 +130,16 @@ const Popups = (() => {
});
// Resize → sauvegarder sur serveur
if (_resizeObs) _resizeObs.disconnect();
const pd = document.getElementById('popup-detail');
new ResizeObserver(() => {
_resizeObs = new ResizeObserver(() => {
API.putServerConfig({
...App.serverConfig,
popup_detail_w: pd.offsetWidth,
popup_detail_h: pd.offsetHeight,
}).catch(() => {});
}).observe(pd);
});
_resizeObs.observe(pd);
document.getElementById('overlay-detail').style.display = 'flex';
}