diff --git a/docs/permission-justifications.md b/docs/permission-justifications.md new file mode 100644 index 0000000..c71810e --- /dev/null +++ b/docs/permission-justifications.md @@ -0,0 +1,48 @@ +# Chrome Web Store permission justifications + +Paste-ready text for the Developer Dashboard. The dashboard asks for a justification for every +permission requested, not only the new ones. Code references are for our own use — they are not +needed in the field, but they are where to check each claim. + +## scripting + +> Injects the extension's own bundled content script into tabs that are already open when the +> extension is installed or updated, so the user does not have to reload each page first. No +> remote or generated code is executed. + +`src/background/install.ts`, `injectContentScriptIntoOpenTabs`. + +> **Note:** the `tabs` permission is deliberately not requested. Tab URLs, needed to match saved +> rules, are available through the host permissions below, so `tabs` would add the "Read your +> browsing history" warning for nothing. The published 2.0.9 build works this way already. + +## activeTab + +> Lets the user run a find and replace on the page they are currently viewing, when they open the +> extension and ask for it. + +## storage + +> Stores the user's search terms, recent history, saved rules and chosen language locally. + +## notifications + +> Shows a single notification after installation explaining that a page open before installing +> needs reloading. + +`src/background/install.ts`. + +## Host permissions — `http://*/*`, `https://*/*`, `file:///*` + +> Finding and replacing text requires reading and changing the content of whichever page the user +> is working on. The user chooses that page; nothing is read in the background and no page content +> leaves the device. + +## Single purpose + +> Find text on the page the user is viewing and replace it with different text, including in form +> fields and rich-text editors. + +## Remote code + +> No. All code is bundled in the package. diff --git a/manifest.json b/manifest.json index affa17b..4d8554b 100644 --- a/manifest.json +++ b/manifest.json @@ -28,10 +28,10 @@ "name": "Search and Replace", "description": "__MSG_ext_description__", "manifest_version": 3, - "permissions": ["activeTab", "storage", "notifications", "tabs", "scripting"], + "permissions": ["activeTab", "storage", "notifications", "scripting"], "host_permissions": ["http://*/*", "https://*/*"], "update_url": "http://clients2.google.com/service/update2/crx", - "version": "2.4.0", + "version": "2.4.1", "icons": { "16": "assets/icon-16.png", "32": "assets/icon-32.png", diff --git a/package.json b/package.json index a38b8e4..495714c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "search_and_replace", - "version": "2.4.0", + "version": "2.4.1", "resolutions": { "author": "Chris Taylor " }, @@ -9,7 +9,7 @@ "watch": "node scripts/build.mjs --dev --watch", "build": "node scripts/build.mjs", "build:dev": "node scripts/build.mjs --dev", - "release": "zip -r ./releases/search_and_replace_$npm_package_version.zip ./dist", + "release": "npm run build && mkdir -p releases && cd dist && zip -qr ../releases/search_and_replace_$npm_package_version.zip .", "start": "light-server --no-reload -s . -p 9000 -w \"**/*.html,**/*.css,**/*.js,**/*.gz\"", "typecheck": "tsc --noEmit && tsc --noEmit --project tsconfig.test.json && tsc --noEmit --project src/cypress/tsconfig.json", "lint": "eslint 'src/**/*.ts' 'scripts/*.mjs'", diff --git a/src/background/install.ts b/src/background/install.ts index 42a0df1..f963f81 100644 --- a/src/background/install.ts +++ b/src/background/install.ts @@ -10,8 +10,16 @@ const DEFAULT_LANGUAGE = 'en' /** The bundle listed under content_scripts in manifest.json */ const CONTENT_SCRIPT = 'searchreplace.js' -/** Kept in step with the `matches` patterns of the content script in manifest.json */ -const CONTENT_SCRIPT_MATCHES = ['http://*/*', 'https://*/*', 'file:///*'] +/** + * Tabs to inject into on install and update. + * + * These are the `host_permissions` from manifest.json, not the content script's `matches`, which + * also include `file:///*`. Without the `tabs` permission, querying by a URL pattern — and + * reading a tab's URL at all — works only where a host permission covers it, so file:// pages + * still need a manual reload. That is a fair trade for not asking every user to approve the + * "Read your browsing history" warning that `tabs` carries. + */ +const INJECTABLE_TABS = ['http://*/*', 'https://*/*'] /** * The first browser UI language we also ship a translation for, else English. @@ -38,7 +46,7 @@ export async function injectContentScriptIntoOpenTabs(): Promise { const injected: number[] = [] let tabs: chrome.tabs.Tab[] = [] try { - tabs = await chrome.tabs.query({ url: CONTENT_SCRIPT_MATCHES }) + tabs = await chrome.tabs.query({ url: INJECTABLE_TABS }) } catch (error) { console.error('BACKGROUND: Could not list open tabs to inject into', error) return injected