From 98ea763d64c0e63d2eed17ab6d8048ad12804b5f Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Sat, 11 Oct 2025 19:13:04 +0200 Subject: [PATCH] Intercept iframe navigation and open links externally - Add navigation interceptor script that prevents all iframe navigation - Intercept link clicks, form submissions, and window.location changes - Send open-external-url messages to parent window - Use chrome.tabs.create() in extension context, window.open() fallback - Fix font-size workaround to use 'initial' instead of hardcoded 16px - Document Chrome extension font-size bug with Stack Overflow reference This prevents HTML artifacts from navigating away when users click links, which would break the sandbox message system. All links now open in new Chrome tabs instead. --- .../web-ui/src/components/SandboxedIframe.ts | 67 ++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/packages/web-ui/src/components/SandboxedIframe.ts b/packages/web-ui/src/components/SandboxedIframe.ts index 41278e1d..a6131858 100644 --- a/packages/web-ui/src/components/SandboxedIframe.ts +++ b/packages/web-ui/src/components/SandboxedIframe.ts @@ -133,6 +133,21 @@ export class SandboxIframe extends LitElement { // Update router with iframe reference BEFORE appending to DOM RUNTIME_MESSAGE_ROUTER.setSandboxIframe(sandboxId, this.iframe); + // Listen for open-external-url messages from iframe + const externalUrlHandler = (e: MessageEvent) => { + if (e.data.type === "open-external-url" && e.source === this.iframe?.contentWindow) { + // Use chrome.tabs API to open in new tab + const chromeAPI = (globalThis as any).chrome; + if (chromeAPI?.tabs) { + chromeAPI.tabs.create({ url: e.data.url }); + } else { + // Fallback for non-extension context + window.open(e.data.url, "_blank"); + } + } + }; + window.addEventListener("message", externalUrlHandler); + // Listen for sandbox-ready and sandbox-error messages directly const readyHandler = (e: MessageEvent) => { if (e.data.type === "sandbox-ready" && e.source === this.iframe?.contentWindow) { @@ -189,6 +204,15 @@ export class SandboxIframe extends LitElement { // Update router with iframe reference BEFORE appending to DOM RUNTIME_MESSAGE_ROUTER.setSandboxIframe(sandboxId, this.iframe); + // Listen for open-external-url messages from iframe + const externalUrlHandler = (e: MessageEvent) => { + if (e.data.type === "open-external-url" && e.source === this.iframe?.contentWindow) { + // Fallback for non-extension context + window.open(e.data.url, "_blank"); + } + }; + window.addEventListener("message", externalUrlHandler); + this.appendChild(this.iframe); } @@ -495,9 +519,13 @@ export class SandboxIframe extends LitElement { }) .join("\n"); + // TODO the font-size is needed, as chrome seems to inject a stylesheet into iframes + // found in an extension context like sidepanel, settin body { font-size: 75% }. It's + // definitely not our code doing that. + // See https://stackoverflow.com/questions/71480433/chrome-is-injecting-some-stylesheet-in-popup-ui-which-reduces-the-font-size-to-7 return ` `; } }