[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:
15 files changed
+439
-348
No files matched your search
@@ -70,7 +70,7 @@
|
||||
<div class="mb-16">
|
||||
<label class="form-label-bold">Favicon (Browser Tab Icon):</label>
|
||||
<div id="favicon-preview-container" style="display: flex; align-items: center; gap: 12px; margin-bottom: 8px; padding: 12px; border-radius: 6px; background: var(--card-bg);">
|
||||
<img id="favicon-preview" src="/assets/dashcaddy-favicon.ico" alt="Current favicon" style="width: 32px; height: 32px; image-rendering: pixelated;" onerror="this.src='data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 32 32%22><rect fill=%22%23667%22 width=%2232%22 height=%2232%22 rx=%224%22/></svg>'" />
|
||||
<img id="favicon-preview" src="/assets/dashcaddy-favicon.ico" alt="Current favicon" style="width: 32px; height: 32px; image-rendering: pixelated;" />
|
||||
<span id="favicon-status" class="text-tiny-muted">Using DashCaddy favicon</span>
|
||||
</div>
|
||||
<input type="file" id="favicon-upload" accept="image/png,image/svg+xml" class="input-card-alt" />
|
||||
@@ -344,6 +344,15 @@
|
||||
const faviconPreview = document.getElementById('favicon-preview');
|
||||
const faviconStatus = document.getElementById('favicon-status');
|
||||
const faviconUpload = document.getElementById('favicon-upload');
|
||||
// Audit P0-3: the missing-favicon fallback used inline onerror (dead under
|
||||
// the meta CSP). Same data-URI fallback, wired + race-guarded.
|
||||
if (faviconPreview) {
|
||||
const faviconFallback = () => {
|
||||
faviconPreview.src = 'data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 32 32%22><rect fill=%22%23667%22 width=%2232%22 height=%2232%22 rx=%224%22/></svg>';
|
||||
};
|
||||
faviconPreview.addEventListener('error', faviconFallback);
|
||||
if (faviconPreview.complete && faviconPreview.naturalWidth === 0) faviconFallback();
|
||||
}
|
||||
const faviconLink = document.querySelector('link[rel="icon"]') || document.createElement('link');
|
||||
let pendingFaviconData = null;
|
||||
|
||||
|
||||
Reference in new issue
Block a user