From 6238edd5d78c0298182ebb4ac3ffd387d65804e6 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sun, 29 Mar 2026 23:10:45 -0700 Subject: [PATCH] fix: add inspector message types to background.js allowlist Pre-existing bug found by Codex: ALLOWED_TYPES in background.js was missing all inspector message types (startInspector, stopInspector, elementPicked, pickerCancelled, applyStyle, toggleClass, injectCSS, resetAll, inspectResult). Messages were silently rejected, making the inspector broken on ALL pages. Also: separate executeScript and insertCSS into individual try blocks in injectInspector(), store inspectorMode for routing, and add content.js fallback when script injection fails (CSP, chrome:// pages). Co-Authored-By: Claude Opus 4.6 (1M context) --- extension/background.js | 45 ++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/extension/background.js b/extension/background.js index 9e253c87..4084acaf 100644 --- a/extension/background.js +++ b/extension/background.js @@ -160,24 +160,41 @@ async function fetchAndRelayRefs() { // ─── Inspector ────────────────────────────────────────────────── +// Track inspector mode per tab — 'full' (inspector.js injected) or 'basic' (content.js fallback) +let inspectorMode = 'full'; + async function injectInspector(tabId) { + // Try full inspector injection first try { await chrome.scripting.executeScript({ target: { tabId, allFrames: true }, files: ['inspector.js'], }); - await chrome.scripting.insertCSS({ - target: { tabId, allFrames: true }, - files: ['inspector.css'], - }); - } catch (err) { - return { error: 'Cannot inspect this page (CSP restriction)' }; + // CSS injection failure alone doesn't need fallback + try { + await chrome.scripting.insertCSS({ + target: { tabId, allFrames: true }, + files: ['inspector.css'], + }); + } catch {} + // Send startPicker to the injected inspector.js + try { + await chrome.tabs.sendMessage(tabId, { type: 'startPicker' }); + } catch {} + inspectorMode = 'full'; + return { ok: true, mode: 'full' }; + } catch { + // Script injection failed (CSP, chrome:// page, etc.) + // Fall back to content.js basic picker (loaded by manifest on most pages) + try { + await chrome.tabs.sendMessage(tabId, { type: 'startBasicPicker' }); + inspectorMode = 'basic'; + return { ok: true, mode: 'basic' }; + } catch { + inspectorMode = 'full'; + return { error: 'Cannot inspect this page' }; + } } - // Send startPicker to all frames - try { - await chrome.tabs.sendMessage(tabId, { type: 'startPicker' }); - } catch {} - return { ok: true }; } async function stopInspector(tabId) { @@ -236,7 +253,11 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { const ALLOWED_TYPES = new Set([ 'getPort', 'setPort', 'getServerUrl', 'fetchRefs', - 'openSidePanel', 'command', 'sidebar-command' + 'openSidePanel', 'command', 'sidebar-command', + // Inspector message types + 'startInspector', 'stopInspector', 'elementPicked', 'pickerCancelled', + 'applyStyle', 'toggleClass', 'injectCSS', 'resetAll', + 'inspectResult' ]); if (!ALLOWED_TYPES.has(msg.type)) { console.warn('[gstack] Rejected unknown message type:', msg.type);