@@ -245,17 +245,20 @@ try {
245245 <link rel="preload" href="/assets/logos/thinkRED-np.svg" as="image" fetchpriority="high">
246246 <link rel="preload" href="/assets/avatars/assistant-red.webp" as="image">` ;
247247
248- // 4. ENHANCED CSP WITH NONCE
249- const cspMeta = `
250- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'nonce-${ nonce } ' https://script.google.com https://script.googleusercontent.com; style-src 'self' 'nonce-${ nonce } ' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https://script.google.com https://script.googleusercontent.com; frame-src 'self' https://script.google.com; object-src 'none'; base-uri 'self'; form-action 'self';">` ;
248+ // 4. ENHANCED CSP WITH NONCE - Replace existing CSP if present
249+ const cspMeta = `<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'nonce-${ nonce } ' https://script.google.com https://script.googleusercontent.com; style-src 'self' 'nonce-${ nonce } ' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https://script.google.com https://script.googleusercontent.com; frame-src 'self' https://script.google.com; object-src 'none'; base-uri 'self'; form-action 'self';">` ;
250+
251+ // Remove any existing CSP headers to prevent conflicts
252+ html = html . replace ( / < m e t a [ ^ > ] * C o n t e n t - S e c u r i t y - P o l i c y [ ^ > ] * > / gi, '' ) ;
251253
252254 // 5. ADDITIONAL SECURITY AND PERFORMANCE HEADERS
253255 const securityMeta = `
254256 <meta http-equiv="X-Content-Type-Options" content="nosniff">
255257 <meta http-equiv="X-Frame-Options" content="SAMEORIGIN">
256258 <meta http-equiv="X-XSS-Protection" content="1; mode=block">
257259 <meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin">
258- <meta http-equiv="Permissions-Policy" content="camera=(), microphone=(), geolocation=(), payment=()">` ;
260+ <meta http-equiv="Permissions-Policy" content="camera=(), microphone=(), geolocation=(), payment=()">
261+ ` ;
259262
260263 // 6. SERVICE WORKER REGISTRATION
261264 const serviceWorkerScript = `
@@ -291,9 +294,17 @@ try {
291294 '<script$1 fetchpriority="high">'
292295 ) ;
293296
294- // Add nonce to inline scripts and styles
295- html = html . replace ( / < s c r i p t (? ! [ ^ > ] * s r c ) ( [ ^ > ] * ) > / g, `<script$1 nonce="${ nonce } ">` ) ;
296- html = html . replace ( / < s t y l e ( [ ^ > ] * ) > / g, `<style$1 nonce="${ nonce } ">` ) ;
297+ // Add nonce to inline scripts and styles that don't already have one
298+ // More robust regex to prevent duplicate nonces
299+ html = html . replace ( / < s c r i p t (? ! [ ^ > ] * n o n c e = ) (? ! [ ^ > ] * s r c ) ( [ ^ > ] * ) > / g, `<script$1 nonce="${ nonce } ">` ) ;
300+ html = html . replace ( / < s t y l e (? ! [ ^ > ] * n o n c e = ) ( [ ^ > ] * ) > / g, `<style$1 nonce="${ nonce } ">` ) ;
301+
302+ // Add nonce to stylesheet links that don't already have one
303+ html = html . replace ( / < l i n k ( [ ^ > ] * r e l = " s t y l e s h e e t " [ ^ > ] * ?) (? ! [ ^ > ] * n o n c e = ) > / g, `<link$1 nonce="${ nonce } ">` ) ;
304+
305+ // Remove any duplicate nonce attributes that might have been created
306+ html = html . replace ( / n o n c e = " [ ^ " ] * " \s + n o n c e = " [ ^ " ] * " / g, `nonce="${ nonce } "` ) ;
307+ html = html . replace ( / n o n c e = " [ ^ " ] * " \s + ( [ ^ > ] * ) \s + n o n c e = " [ ^ " ] * " / g, `nonce="${ nonce } " $1` ) ;
297308
298309 // 9. LAZY LOADING OPTIMIZATION
299310 // Add loading="lazy" to images that are not critical
0 commit comments