From 1d4e85f1d20c663556dd0a514dcdf60a3fac7651 Mon Sep 17 00:00:00 2001 From: Local Dev Date: Tue, 27 Oct 2026 21:05:05 +0200 Subject: [PATCH] Theseus 0.3.123 (cont'd): Shield + Cookie Pop-ups now apply to sidebar AI panels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shield (adblocker) already ran in the sidebar — it hooks the default session's webRequest, so any WebContentsView on that session got the same filter as a tab. Cookie Pop-ups (consent) didn't: the add-on-inject preload asks main which scripts to run, and the gate required the sender to be a web tab. Sidebar panels aren't in `tabs`, so sites loaded in the sparkle-opened AI panel (and quick-link apps like WhatsApp, Telegram) still showed every consent banner. Fix is in injectionsForSender (and addon-page-msg for the inject's round-trip back): also accept quickPanel.webContents and leftPanel's sender as a "page" for the purpose of page-inject add-ons. The scripts still see only the URL — nothing panel-specific — so no new attack surface is opened; everything on the user's enabled page-inject list runs on the same origins there as it does in a tab. --- main.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/main.js b/main.js index 15d05b3e..9e4740da 100644 --- a/main.js +++ b/main.js @@ -7646,8 +7646,14 @@ ipcMain.on("wiz-link", (e, uri) => { }); ipcMain.handle("addon-page-msg", async (e, addonId, msg, payload) => { + // Sidebar panels (quickPanel, leftPanel) count as pages for inject + // round-trips too — see injectionsForSender for the same gate. const tab = tabForSender(e.sender); - if (!tab || !addonHost) throw new Error("not a page"); + const isPanel = !tab && ( + (quickPanel && e.sender === quickPanel.webContents) || + (leftPanel && e.sender === leftPanel.webContents) + ); + if ((!tab && !isPanel) || !addonHost) throw new Error("not a page"); // Only the tab's top-level document speaks for its origin. The inject // preload runs in the main frame alone, so a message from any other frame // did not come through it — and it would be credited with the top-level @@ -7672,14 +7678,23 @@ ipcMain.handle("addon-page-msg", async (e, addonId, msg, payload) => { // Assigning event.returnValue sends the reply at once, so it is set exactly // once at the end. function injectionsForSender(e, href) { + // Normally the sender must be a web tab. Sidebar panels (the sparkle-opened + // AI chat, the quick-link apps like Telegram/WhatsApp) are not in `tabs` + // but DO load third-party origins, so cookie-consent rules, page-inject + // wallets and friends should run there too — otherwise the AI panel in + // the strip shows every consent banner the matching tab wouldn't. const tab = tabForSender(e.sender); - if (!tab || !addonHost) return []; + const isPanel = !tab && ( + (quickPanel && e.sender === quickPanel.webContents) || + (leftPanel && e.sender === leftPanel.webContents) + ); + if ((!tab && !isPanel) || !addonHost) return []; const url = e.sender.getURL(); if (!url || url.startsWith("file:")) return []; if (href && href !== url) console.log(`[addons] inject: preload href ${href} ≠ committed ${url}`); const origin = pageOriginOf(url); const list = addonHost.injectionsFor(url).map((x) => ({ ...x, origin })); - if (list.length) console.log(`[addons] inject ${list.map((x) => x.id).join(",")} into ${origin}`); + if (list.length) console.log(`[addons] inject ${list.map((x) => x.id).join(",")} into ${origin}${isPanel ? " (sidebar panel)" : ""}`); return list; } ipcMain.on("addon-inject-scripts", (e, href) => { e.returnValue = injectionsForSender(e, href); });