[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
@@ -204,6 +204,20 @@
|
||||
var restoreBtn = document.getElementById('backup-do-restore-btn');
|
||||
var resultDiv = document.getElementById('backup-result');
|
||||
var scheduleContainer = document.getElementById('backup-schedules-container');
|
||||
|
||||
// Audit P0-3 (2026-10-27): premium upsell buttons used inline onclick,
|
||||
// which the meta CSP blocks — dead buttons. (Their onclick also called
|
||||
// scrollToSection('license'), which has NEVER existed — doubly dead.)
|
||||
// data-upgrade-msg + wiring; license UI opens via window.openLicenseModal.
|
||||
function wireUpgradeButtons(root) {
|
||||
if (!root || !root.querySelectorAll) return;
|
||||
root.querySelectorAll('[data-upgrade-msg]').forEach((btn) => {
|
||||
btn.addEventListener('click', () => {
|
||||
showNotification(btn.dataset.upgradeMsg, 'info');
|
||||
if (window.openLicenseModal) window.openLicenseModal();
|
||||
});
|
||||
});
|
||||
}
|
||||
var historyContainer = document.getElementById('backup-history-container');
|
||||
var diskContainer = document.getElementById('backup-disk-container');
|
||||
var pointintimeContainer = document.getElementById('pointintime-container');
|
||||
@@ -420,8 +434,9 @@
|
||||
'<div style="font-size: 2rem; margin-bottom: 12px;">⭐</div>' +
|
||||
'<div style="font-weight: 600; margin-bottom: 8px;">Premium Feature</div>' +
|
||||
'<div style="font-size: 0.85rem; color: var(--muted);">Auto-backup scheduling requires a DashCaddy Premium subscription.</div>' +
|
||||
'<button onclick="showNotification(\'Upgrade to Premium to enable auto-backups!\', \'info\'); scrollToSection(\'license\');" style="margin-top: 16px; padding: 8px 20px; background: linear-gradient(135deg, #f39c12, #e67e22); border: none; color: white; border-radius: 8px; cursor: pointer; font-weight: 600;">Upgrade to Premium</button>' +
|
||||
'<button type="button" data-upgrade-msg="Upgrade to Premium to enable auto-backups!" style="margin-top: 16px; padding: 8px 20px; background: linear-gradient(135deg, #f39c12, #e67e22); border: none; color: white; border-radius: 8px; cursor: pointer; font-weight: 600;">Upgrade to Premium</button>' +
|
||||
'</div>';
|
||||
wireUpgradeButtons(scheduleContainer);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -749,8 +764,9 @@
|
||||
'<div style="font-size: 2rem; margin-bottom: 12px;">⭐</div>' +
|
||||
'<div style="font-weight: 600; margin-bottom: 8px;">Premium Feature</div>' +
|
||||
'<div style="font-size: 0.85rem; color: var(--muted);">Point-in-time restore requires DashCaddy Premium with auto-backup enabled.</div>' +
|
||||
'<button onclick="showNotification(\'Upgrade to Premium for point-in-time restore!\', \'info\'); scrollToSection(\'license\');" style="margin-top: 16px; padding: 8px 20px; background: linear-gradient(135deg, #f39c12, #e67e22); border: none; color: white; border-radius: 8px; cursor: pointer; font-weight: 600;">Upgrade to Premium</button>' +
|
||||
'<button type="button" data-upgrade-msg="Upgrade to Premium for point-in-time restore!" style="margin-top: 16px; padding: 8px 20px; background: linear-gradient(135deg, #f39c12, #e67e22); border: none; color: white; border-radius: 8px; cursor: pointer; font-weight: 600;">Upgrade to Premium</button>' +
|
||||
'</div>';
|
||||
wireUpgradeButtons(pointintimeContainer);
|
||||
return;
|
||||
}
|
||||
} catch (e) { /* ignore */ }
|
||||
|
||||
Reference in new issue
Block a user