From e1fcbe9ce77299df9c36a3c1802875f878dfb091 Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Sun, 12 Apr 2026 17:06:35 -0400 Subject: [PATCH] feat: expand CSP connect-src directive and add async loading guard for highlight.js in popout view - Add cdnjs.cloudflare.com, fonts.googleapis.com, and fonts.gstatic.com to connect-src CSP directive - Add waitForHljs helper function with 50 attempt limit and 100ms polling interval - Check if hljs is defined before highlighting code blocks in popout view - Fall back to async waiting if hljs not immediately available to prevent undefined reference errors --- backend/main.py | 2 +- frontend/popout.html | 24 ++++++++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/backend/main.py b/backend/main.py index 34b02f2..cd7ac6c 100644 --- a/backend/main.py +++ b/backend/main.py @@ -458,7 +458,7 @@ class SecurityHeadersMiddleware(BaseHTTPMiddleware): "script-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://unpkg.com https://esm.sh; " "style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com https://fonts.googleapis.com; " "img-src 'self' data: blob:; " - "connect-src 'self' https://esm.sh https://unpkg.com; " + "connect-src 'self' https://esm.sh https://unpkg.com https://cdnjs.cloudflare.com https://fonts.googleapis.com https://fonts.gstatic.com; " "font-src 'self' https://fonts.gstatic.com;" ) return response diff --git a/frontend/popout.html b/frontend/popout.html index bfa4287..aa4c427 100644 --- a/frontend/popout.html +++ b/frontend/popout.html @@ -752,10 +752,18 @@ const RightSidebarManager = { OutlineManager.init(); RightSidebarManager.init(); - // Highlight code blocks - document.querySelectorAll('pre code').forEach((el) => { - hljs.highlightElement(el); - }); + // Highlight code blocks (wait for hljs to be available) + if (typeof hljs !== 'undefined') { + document.querySelectorAll('pre code').forEach((el) => { + hljs.highlightElement(el); + }); + } else { + waitForHljs().then(() => { + document.querySelectorAll('pre code').forEach((el) => { + hljs.highlightElement(el); + }); + }); + } // Hide loading document.getElementById('loading').style.opacity = '0'; @@ -768,6 +776,14 @@ const RightSidebarManager = { } } + async function waitForHljs() { + let attempts = 0; + while (typeof hljs === 'undefined' && attempts < 50) { + await new Promise((resolve) => setTimeout(resolve, 100)); + attempts++; + } + } + async function waitForCodeMirror() { let attempts = 0; while (!window.CodeMirror && attempts < 50) {