[grade=B] fix: stop aggressive API polling and SSE reconnect when auth lost
CI / Test & Lint (push) Canceled after 0s
CI / Security audit (push) Canceled after 0s

When unauthenticated (TOTP gate active), the dashboard was polling
/api/v1/services/status every few seconds and reconnecting SSE every
2-8s indefinitely. Now: 401/403 sets _dcAuthLost flag to skip the
polling interval entirely (no fallback to direct probes which
misleadingly mark services as healthy), SSE exposes _sseClose()
coordinated with _dcAuthLost, and queued refreshes are guarded.
This commit is contained in:
Hermes
2026-08-13 14:43:53 -07:00
parent 89968f5485
commit 29eedb3515
3 changed files with 110 additions and 86 deletions
+14 -3
View File
@@ -349,6 +349,9 @@
}
async function refreshAll() {
// Skip if auth has been lost (e.g. TOTP gate activated externally).
// The polling interval in init.js also checks this flag.
if (window._dcAuthLost) return;
if (refreshInFlight) {
refreshQueued = true;
return refreshInFlight;
@@ -402,9 +405,15 @@
try {
const response = await fetch('/api/v1/services/status', { cache: 'no-store' });
if (response.status === 401 || response.status === 403) {
// Auth lost — stop the polling loop from hammering every few seconds
// Auth lost — stop the polling loop and close SSE; do NOT fall
// through to direct probes (those would misleadingly mark
// services as healthy since /probe/ treats 401/403 as "up").
window._dcAuthLost = true;
throw new Error(`Authentication required (${response.status})`);
if (window._sseReconnect && window._sseClose) {
window._sseClose(); // tell SSE to stop reconnecting
}
updateStamp('auth required');
return; // skip the fallback entirely
}
if (!response.ok) {
throw new Error(`Status refresh failed (${response.status})`);
@@ -424,9 +433,11 @@
}
} finally {
refreshInFlight = null;
if (refreshQueued) {
if (refreshQueued && !window._dcAuthLost) {
refreshQueued = false;
setTimeout(() => { window.refreshAll(); }, 0);
} else {
refreshQueued = false;
}
}
})();