From 0cb397a384f044613630f4e209e47dbe0a0cf8fc Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 11 Oct 2026 10:30:34 +0000 Subject: [PATCH] Minimal permissions: drop "tabs", host permissions only http/https - tab.url is available with matching host permissions, "tabs" is not needed - cookies make sense only for http(s), narrowed to http://*/* and https://*/* - permission check in common.js uses the same origins - Chromium test no longer looks up about:blank tab by URL - store/permissions.md updated Passed locally: Chromium 141 13/13 (3 runs), Firefox 157.0.1 and 153.4.0esr 9/9. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_011ZZMU6eeKUpne5HfQBAxoT --- common.js | 7 ++++--- manifest.json | 4 ++-- store/permissions.md | 3 +-- tests/chrome.test.js | 8 +++----- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/common.js b/common.js index b8b6552..56c7e3d 100644 --- a/common.js +++ b/common.js @@ -14,7 +14,8 @@ const TRIGGERS = [ ]; const DEFAULT_ON_COLOR = 'red'; const DEFAULT_OFF_COLOR = 'light'; -const ALL_URLS = { origins: [''] }; +// Must match host_permissions in manifest.json +const SITE_ORIGINS = { origins: ['http://*/*', 'https://*/*'] }; // Default IDE keys: VS Code - php.debug.ideKey of xdebug/vscode-php-debug, // others - as in Xdebug helper extension. Any other value is a custom key. const IDE_PRESETS = [ @@ -70,7 +71,7 @@ function isSupportedUrl(url) { async function hasHostPermission() { try { - return await api.permissions.contains(ALL_URLS); + return await api.permissions.contains(SITE_ORIGINS); } catch (e) { logError('permissions.contains failed', e); return false; @@ -79,7 +80,7 @@ async function hasHostPermission() { // Must be called from a user action handler (click) async function requestHostPermission() { - let granted = await api.permissions.request(ALL_URLS); + let granted = await api.permissions.request(SITE_ORIGINS); log('host permission granted:', granted); return granted; } diff --git a/manifest.json b/manifest.json index e671bdf..ed4b849 100644 --- a/manifest.json +++ b/manifest.json @@ -15,13 +15,13 @@ }, "permissions": [ - "tabs", "cookies", "storage" ], "host_permissions": [ - "" + "http://*/*", + "https://*/*" ], "action": { diff --git a/store/permissions.md b/store/permissions.md index 0a1e54b..9e7d0ed 100644 --- a/store/permissions.md +++ b/store/permissions.md @@ -6,8 +6,7 @@ for the current site to start PHP debugging, profiling or tracing. | Permission | Why it is needed | |---|---| | `cookies` | Set and remove the Xdebug trigger cookies for the current site; watch cookie changes to show the actual state on the toolbar icon. | -| `tabs` | Read the URL of the active tab to know which site the cookie is for, and update the toolbar icon and badge per tab. | | `storage` | Save extension settings (cookie names and values, IDE, icon colors) and per-site choices. | -| Host permission `` | The cookies API works only for sites the extension has host permission for. Developers debug arbitrary hosts (localhost, test domains, staging servers), so the list of sites cannot be fixed in advance. | +| Host permissions `http://*/*`, `https://*/*` | The cookies API works only for sites the extension has host permission for; the same permission gives the URL of the current tab (to know which site the cookie is for and to show the state on the toolbar icon). Developers debug arbitrary hosts (localhost, test domains, staging servers), so the list of sites cannot be fixed in advance. Only http and https are requested: Xdebug cookies make sense only there. | | Remote code | Not used. All code is in the package. | | Data collection | None. | diff --git a/tests/chrome.test.js b/tests/chrome.test.js index ba34c9c..1b3622d 100644 --- a/tests/chrome.test.js +++ b/tests/chrome.test.js @@ -190,12 +190,10 @@ describe('Chromium', () => { }); it('shows unsupported message on browser pages', async () => { - const blank = await context.newPage(); - await blank.goto('about:blank'); - const blankTabId = await worker.evaluate(async () => (await api.tabs.query({ url: 'about:blank' }))[0].id); - await popup.goto(`chrome-extension://${extensionId}/popup.html?tabId=${blankTabId}`); + // Without the "tabs" permission non-http tabs can't be found by URL, so the site tab is reused + await site.goto('about:blank'); + await popup.goto(`chrome-extension://${extensionId}/popup.html?tabId=${siteTabId}`); await eventually(async () => assert.ok(await popup.isVisible('.unsupported'))); - await blank.close(); }); it('has no unexpected console errors', () => {