[grade=A urn:ump:josd2g7kqv476vux6euigmygdkijya2s4tsbyivtobw5ftzuf6ba] fix(DC-170): revive 19 CSP-blocked inline handlers across the dashboard — audit P0-3

The meta CSP (no unsafe-inline/unsafe-hashes) blocks ALL inline event
handlers; 19 controls were silently dead in every modern browser.

Revived:
- Disk Safety: toolbar button, injected modal Close/Save/Clean Up, and
  the 5 settings sliders (oninput -> input listeners; value labels
  never updated)
- AI chat FAB click; hover scale moved to a #ai-chat-fab:hover rule
- TOTP/login logo broken-image fallbacks: capture-phase error
  delegation + WeakSet + complete/naturalWidth race guard in
  totp-auth.js; updateTotpLogo never resurrects a broken logo
  (6 onerror attrs stripped from index.html + auth-gate.js templates)
- favicon-preview data-URI fallback (same race guard)
- app-selector folder-chip remove buttons (data-remove-folder)
- premium upsells in backup-restore + workflows (data-upgrade-msg) —
  their old onclick also called scrollToSection('license'), a function
  that has never existed anywhere in the codebase; now opens the real
  license UI via window.openLicenseModal (license.js)
- health-check Edit/Delete dispatch the same CustomEvents via
  data-health-action/data-service-id
- smart-arr Test button via data-smart-test

Verified: zero inline handler attributes remain across index.html +
hand-written js (grep); node --check clean x12; status suite 68/68;
dist rebuilt (SW dashcaddy-shell-36d9aa3364, CSP hash unchanged).
r1 grade C (missed sliders + logo onerror) -> r2 grade A:
urn:ump:mptri3qhywc2e47f2ba4qjafhwm3olzvrvt5vphxoyhea3vgt32a /
urn:ump:josd2g7kqv476vux6euigmygdkijya2s4tsbyivtobw5ftzuf6ba
This commit is contained in:
Hermes committed 2026-10-28 00:48:32 -07:00
1 parent 8a6aed546d
commit 94ee76e9de
15 files changed
+439 -348

No files matched your search

+18 -2
View File
@@ -1,5 +1,21 @@
// ===== TOTP AUTHENTICATION GATE =====
(function() {
// Audit P0-3 (2026-10-27): broken-logo hiding used inline onerror, which
// the meta CSP blocks (dead handler). Track failures via capture-phase
// delegation (catches injected <img>s at any time) + a load-state sweep,
// and never resurrect a broken logo in updateTotpLogo().
const brokenLogos = new WeakSet();
document.addEventListener('error', (e) => {
const t = e.target;
if (t && t.tagName === 'IMG' && t.classList.contains('totp-logo')) {
brokenLogos.add(t);
t.style.display = 'none';
}
}, true);
document.querySelectorAll('.totp-logo').forEach((img) => {
if (img.complete && img.naturalWidth === 0) { brokenLogos.add(img); img.style.display = 'none'; }
});
function updateTotpLogo() {
const card = document.querySelector('.totp-card');
if (!card) return;
@@ -9,8 +25,8 @@
const lum = (0.299 * +m[0] + 0.587 * +m[1] + 0.114 * +m[2]) / 255;
const dark = card.querySelector('.totp-logo-dark');
const light = card.querySelector('.totp-logo-light');
if (dark) dark.style.display = lum > 0.5 ? 'none' : '';
if (light) light.style.display = lum > 0.5 ? '' : 'none';
if (dark) dark.style.display = (lum > 0.5 || brokenLogos.has(dark)) ? 'none' : '';
if (light) light.style.display = (lum <= 0.5 || brokenLogos.has(light)) ? 'none' : '';
}
function showTotpOverlay() {