# Content Security Policy (CSP) Fix - Complete ## Date: December 19, 2025 ## Problem The media library had Content Security Policy violations that prevented buttons from working: - ❌ "New Folder" button not working - ❌ "Upload Files" button not working - ❌ Inline event handlers blocked by CSP - ❌ CDN source map connections blocked ### CSP Errors ``` media-library.html:297 Executing inline event handler violates the following Content Security Policy directive 'script-src-attr 'none''. Connecting to 'https://cdn.jsdelivr.net/...' violates the following Content Security Policy directive: "default-src 'self'". Note that 'connect-src' was not explicitly set. ``` ## Solution ### 1. Fixed CSP Configuration (`backend/server.js`) Added `connectSrc` directive to allow CDN connections: ```javascript contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'", "https://cdn.jsdelivr.net"], scriptSrc: ["'self'", "'unsafe-inline'", "https://cdn.jsdelivr.net"], imgSrc: ["'self'", "data:", "blob:"], fontSrc: ["'self'", "https://cdn.jsdelivr.net"], connectSrc: ["'self'", "https://cdn.jsdelivr.net"], // ✅ ADDED }, } ``` ### 2. Removed ALL Inline Event Handlers (`media-library.html`) #### Buttons Fixed - ✅ Logout button: `onclick="logout()"` → `id="logoutBtn"` + event listener - ✅ New Folder button: `onclick="showCreateFolderModal()"` → `id="newFolderBtn"` + event listener - ✅ Upload Files button: `onclick="showUploadZone()"` → `id="uploadFilesBtn"` + event listener - ✅ Delete Selected button: `onclick="handleDeleteSelected()"` → event listener - ✅ Create Folder modal button: `onclick="createFolder()"` → `id="createFolderBtn"` + event listener #### Upload Zone Fixed Removed inline handlers: - `ondrop="handleDrop(event)"` - `ondragover="..."` - `ondragleave="..."` - `onclick="..."` Replaced with proper event listeners in JavaScript. #### File Input Fixed - `onchange="handleFileSelect(event)"` → event listener #### Dynamic HTML Fixed **Folders:** - Checkbox: `onclick="toggleSelection(...)"` → `data-item-id` + event delegation - Folder item: `ondblclick="navigateToFolder(...)"` → `data-folder-id` + event delegation **Files:** - Checkbox: `onclick="toggleSelection(...)"` → `data-item-id` + event delegation **Breadcrumbs:** - Links: `onclick="navigateToFolder(...)"` → `data-folder-id` + event delegation ### 3. Added Central Event Listener Setup Created `setupEventListeners()` function that runs on page load: ```javascript function setupEventListeners() { // Logout button document.getElementById('logoutBtn').addEventListener('click', logout); // New Folder button document.getElementById('newFolderBtn').addEventListener('click', showCreateFolderModal); // Upload Files button document.getElementById('uploadFilesBtn').addEventListener('click', showUploadZone); // Delete Selected button document.getElementById('deleteSelectedBtn').addEventListener('click', handleDeleteSelected); // Upload zone (click, drag, drop) const uploadZone = document.getElementById('uploadZone'); uploadZone.addEventListener('click', () => document.getElementById('fileInput').click()); uploadZone.addEventListener('drop', handleDrop); uploadZone.addEventListener('dragover', (e) => { ... }); uploadZone.addEventListener('dragleave', (e) => { ... }); // File input change document.getElementById('fileInput').addEventListener('change', handleFileSelect); // Create Folder button in modal document.getElementById('createFolderBtn').addEventListener('click', createFolder); // Enter key in folder name input document.getElementById('folderNameInput').addEventListener('keypress', (e) => { if (e.key === 'Enter') createFolder(); }); } ``` ### 4. Event Delegation for Dynamic Content After rendering media items: ```javascript // Attach checkbox listeners grid.querySelectorAll('.media-checkbox').forEach(checkbox => { checkbox.addEventListener('click', (e) => { e.stopPropagation(); const itemId = e.target.getAttribute('data-item-id'); toggleSelection(itemId, e); }); }); // Attach folder double-click listeners grid.querySelectorAll('.folder-item').forEach(item => { item.addEventListener('dblclick', (e) => { const folderId = parseInt(e.currentTarget.getAttribute('data-folder-id')); navigateToFolder(folderId); }); }); ``` After rendering breadcrumbs: ```javascript breadcrumb.querySelectorAll('a').forEach(link => { link.addEventListener('click', (e) => { e.preventDefault(); const folderId = e.currentTarget.getAttribute('data-folder-id'); navigateToFolder(folderId === 'null' ? null : parseInt(folderId)); }); }); ``` ## Files Modified ### Backend - ✅ `backend/server.js` - Added `connectSrc` to CSP ### Frontend - ✅ `website/admin/media-library.html` - Removed all inline handlers, added event listeners ## Testing 1. Navigate to 2. Open browser console (F12) - **No CSP errors** 3. Click "New Folder" button - **Works!** Modal opens 4. Click "Upload Files" button - **Works!** Upload zone appears 5. Click upload zone - **Works!** File picker opens 6. Drag and drop files - **Works!** Upload proceeds 7. Select items with checkboxes - **Works!** Delete button appears 8. Double-click folder - **Works!** Navigates into folder 9. Click breadcrumb links - **Works!** Navigation works 10. Click Logout - **Works!** Confirmation dialog appears ## Results ### Before Fix ``` ❌ CSP violations blocking inline handlers ❌ New Folder button not working ❌ Upload Files button not working ❌ CDN source map connections blocked ❌ Console full of CSP errors ``` ### After Fix ``` ✅ No CSP violations ✅ All buttons working perfectly ✅ Upload zone fully functional ✅ Folder creation works ✅ File upload works ✅ Drag & drop works ✅ Clean console with no errors ``` ## Best Practices Applied 1. **No Inline Handlers**: All JavaScript in `