Harden CSP by removing unsafe-inline for scripts
Refactored all inline event handlers (onclick, onchange, onsubmit) to use
addEventListener with data-action attributes and event delegation pattern.
Changes:
- views/*.php: Replaced inline handlers with data-action attributes
- views/admin/*.php: Same refactoring for all admin views
- assets/js/dashboard.js: Added event delegation for bulk/quick action modals
- assets/js/ticket.js: Added event delegation for dynamic elements
- assets/js/markdown.js: Refactored toolbar button handlers
- assets/js/keyboard-shortcuts.js: Refactored modal close button
- SecurityHeadersMiddleware.php: Enabled strict CSP with nonces
The CSP now uses script-src 'self' 'nonce-{nonce}' instead of 'unsafe-inline',
significantly improving XSS protection.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -182,7 +182,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
|
||||
<div style="display: grid; grid-template-columns: 1fr 2fr; gap: 0.75rem;">
|
||||
<div class="metadata-field">
|
||||
<label style="font-weight: 500; display: block; margin-bottom: 0.25rem; color: var(--terminal-cyan); font-family: var(--font-mono); font-size: 0.85rem;">Visibility:</label>
|
||||
<select id="visibilitySelect" class="metadata-select editable-metadata" disabled onchange="toggleVisibilityGroupsEdit()" style="width: 100%; padding: 0.25rem 0.5rem; border-radius: 0; border: 2px solid var(--terminal-green); background: var(--bg-primary); color: var(--terminal-green); font-family: var(--font-mono);">
|
||||
<select id="visibilitySelect" class="metadata-select editable-metadata" disabled data-action="toggle-visibility-groups" style="width: 100%; padding: 0.25rem 0.5rem; border-radius: 0; border: 2px solid var(--terminal-green); background: var(--bg-primary); color: var(--terminal-green); font-family: var(--font-mono);">
|
||||
<option value="public" <?php echo $currentVisibility == 'public' ? 'selected' : ''; ?>>Public</option>
|
||||
<option value="internal" <?php echo $currentVisibility == 'internal' ? 'selected' : ''; ?>>Internal</option>
|
||||
<option value="confidential" <?php echo $currentVisibility == 'confidential' ? 'selected' : ''; ?>>Confidential</option>
|
||||
@@ -211,7 +211,7 @@ $nonce = SecurityHeadersMiddleware::getNonce();
|
||||
</div>
|
||||
<div class="header-controls">
|
||||
<div class="status-priority-group">
|
||||
<select id="statusSelect" class="editable status-select status-<?php echo str_replace(' ', '-', strtolower($ticket["status"])); ?>" data-field="status" onchange="updateTicketStatus()">
|
||||
<select id="statusSelect" class="editable status-select status-<?php echo str_replace(' ', '-', strtolower($ticket["status"])); ?>" data-field="status" data-action="update-ticket-status">
|
||||
<option value="<?php echo $ticket['status']; ?>" selected>
|
||||
<?php echo $ticket['status']; ?> (current)
|
||||
</option>
|
||||
@@ -275,14 +275,14 @@ $nonce = SecurityHeadersMiddleware::getNonce();
|
||||
<div class="markdown-toggles">
|
||||
<div class="preview-toggle">
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="markdownMaster" onchange="toggleMarkdownMode()">
|
||||
<input type="checkbox" id="markdownMaster" data-action="toggle-markdown-mode">
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
<span class="toggle-label">Enable Markdown</span>
|
||||
</div>
|
||||
<div class="preview-toggle">
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="markdownToggle" onchange="togglePreview()" disabled>
|
||||
<input type="checkbox" id="markdownToggle" data-action="toggle-preview" disabled>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
<span class="toggle-label">Preview Markdown</span>
|
||||
@@ -553,6 +553,28 @@ $nonce = SecurityHeadersMiddleware::getNonce();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Handle change events for data-action
|
||||
document.addEventListener('change', function(e) {
|
||||
var target = e.target.closest('[data-action]');
|
||||
if (!target) return;
|
||||
|
||||
var action = target.getAttribute('data-action');
|
||||
switch (action) {
|
||||
case 'update-ticket-status':
|
||||
if (typeof updateTicketStatus === 'function') updateTicketStatus();
|
||||
break;
|
||||
case 'toggle-visibility-groups':
|
||||
if (typeof toggleVisibilityGroupsEdit === 'function') toggleVisibilityGroupsEdit();
|
||||
break;
|
||||
case 'toggle-markdown-mode':
|
||||
if (typeof toggleMarkdownMode === 'function') toggleMarkdownMode();
|
||||
break;
|
||||
case 'toggle-preview':
|
||||
if (typeof togglePreview === 'function') togglePreview();
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user