From f5881caad0e49c6efd32860ba731a6bbed1334b7 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Tue, 16 May 2023 15:27:24 +0200 Subject: [PATCH 1/8] Add DNR + MV3 examples These examples are designed to be cross-browser compatible. In particular, these extensions do not use `background` because there is currently no single manifest that can support both Firefox and Chrome, due to the lack of event page support in Chrome, and the lack of service worker support in Firefox. Three examples demonstrating the use of the declarativeNetRequest API: - dnr-block-only: One minimal example demonstrating the use of static DNR rules to block requests. - dnr-redirect-url: One minimal example demonstrating the use of static DNR rules to redirect requests. - dnr-dynamic-with-options: A generic example demonstrating how host permissions can be requested and free forms to input DNR rules. --- .eslintrc.json | 5 +- dnr-block-only/README.md | 25 +++++++ dnr-block-only/manifest.json | 16 ++++ dnr-block-only/rules.json | 31 ++++++++ dnr-block-only/testpage.html | 97 ++++++++++++++++++++++++ dnr-dynamic-with-options/README.md | 100 +++++++++++++++++++++++++ dnr-dynamic-with-options/manifest.json | 12 +++ dnr-dynamic-with-options/options.css | 8 ++ dnr-dynamic-with-options/options.html | 36 +++++++++ dnr-dynamic-with-options/options.js | 90 ++++++++++++++++++++++ dnr-redirect-url/README.md | 49 ++++++++++++ dnr-redirect-url/manifest.json | 24 ++++++ dnr-redirect-url/popup.html | 30 ++++++++ dnr-redirect-url/popup.js | 37 +++++++++ dnr-redirect-url/redirect-rules.json | 65 ++++++++++++++++ dnr-redirect-url/redirectTarget.html | 38 ++++++++++ examples.json | 37 +++++++++ 17 files changed, 699 insertions(+), 1 deletion(-) create mode 100644 dnr-block-only/README.md create mode 100644 dnr-block-only/manifest.json create mode 100644 dnr-block-only/rules.json create mode 100644 dnr-block-only/testpage.html create mode 100644 dnr-dynamic-with-options/README.md create mode 100644 dnr-dynamic-with-options/manifest.json create mode 100644 dnr-dynamic-with-options/options.css create mode 100644 dnr-dynamic-with-options/options.html create mode 100644 dnr-dynamic-with-options/options.js create mode 100644 dnr-redirect-url/README.md create mode 100644 dnr-redirect-url/manifest.json create mode 100644 dnr-redirect-url/popup.html create mode 100644 dnr-redirect-url/popup.js create mode 100644 dnr-redirect-url/redirect-rules.json create mode 100644 dnr-redirect-url/redirectTarget.html diff --git a/.eslintrc.json b/.eslintrc.json index 34bf2d87..22a593cb 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -8,12 +8,15 @@ "es6": true, "webextensions": true }, + "globals": { + "globalThis": false + }, "extends": [ "eslint:recommended" ], "rules": { "no-console": 0, - "no-unused-vars": ["warn", { "vars": "all", "args": "all" } ], + "no-unused-vars": ["warn", { "vars": "all", "args": "after-used" } ], "no-undef": ["warn"], "no-proto": ["error"], "prefer-arrow-callback": ["warn"], diff --git a/dnr-block-only/README.md b/dnr-block-only/README.md new file mode 100644 index 00000000..fb1b6fdb --- /dev/null +++ b/dnr-block-only/README.md @@ -0,0 +1,25 @@ +# dnr-block-only + +Demonstrates how to block network requests without host permissions through the +declarativeNetRequest API with the `declarative_net_request` manifest key.", + +## What it does + +This extension blocks network requests: + +- requests to URLs containing "blocksub" (except for top-level navigations). +- top-level navigation to URLs containing "blocktop". +- all requests containing "blockall". + +`testpage.html` can be loaded to see the extension in action. +This demo page does not need to be packaged with the extension. + +# What it shows + +- how to use the declarativeNetRequest API through the `declarative_net_request` manifest key. +- how to use the "resourceTypes" and "excludedResourceTypes" condition of a declarativeNetRequest rule. +- how to block network requests without host permissions, but instead through the "declarativeNetRequest" permission that triggers the "Block content on any page" permission warning at install time. + +This is the only cross-browser way to block network requests (at least in +Firefox, Chrome and Safari). While the extension uses `"manifest_version": 3`, +it also works identically with `"manifest_version": 2`. diff --git a/dnr-block-only/manifest.json b/dnr-block-only/manifest.json new file mode 100644 index 00000000..bd6481cc --- /dev/null +++ b/dnr-block-only/manifest.json @@ -0,0 +1,16 @@ +{ + "manifest_version": 3, + "name": "Block only, without host_permissions", + "description": "Blocks requests to 'blocksub', 'blocktop' or 'blockall'. Due to the 'declarativeNetRequest' permission, host_permissions in manifest.json are not needed.", + "version": "0.1", + "permissions": [ + "declarativeNetRequest" + ], + "declarative_net_request": { + "rule_resources": [{ + "id": "ruleset", + "enabled": true, + "path": "rules.json" + }] + } +} diff --git a/dnr-block-only/rules.json b/dnr-block-only/rules.json new file mode 100644 index 00000000..5d87193c --- /dev/null +++ b/dnr-block-only/rules.json @@ -0,0 +1,31 @@ +[ + { + "id": 1, + "condition": { + "urlFilter": "blocksub" + }, + "action": { + "type": "block" + } + }, + { + "id": 2, + "condition": { + "urlFilter": "blocktop", + "resourceTypes": ["main_frame"] + }, + "action": { + "type": "block" + } + }, + { + "id": 3, + "condition": { + "urlFilter": "blockall", + "excludedResourceTypes": [] + }, + "action": { + "type": "block" + } + } +] diff --git a/dnr-block-only/testpage.html b/dnr-block-only/testpage.html new file mode 100644 index 00000000..b5558e59 --- /dev/null +++ b/dnr-block-only/testpage.html @@ -0,0 +1,97 @@ + + + + + + + + +

Block requests containing 'blocksub' (except main_frame)

+Given the following rule: +
+  {
+    "id": 1,
+    "condition": {
+      "urlFilter": "blocksub"
+    },
+    "action": {
+      "type": "block"
+    }
+  },
+
+
+ rule 1 will block this image (containing 'blocksub'): + +
+
+ rule 1 will not block this image (does not contain 'blocksub'): + +
+
+ rule 1 will not block top-level navigations to + https://developer.mozilla.org/favicon.ico?blocksub + because top-level navigation ("main_frame") requests are not matched by default, + when "resourceTypes" and "excludedResourceTypes" are not specified. +
+ +

Block main_frame requests containing 'blocktop'

+Given the following rule: +
+  {
+    "id": 2,
+    "condition": {
+      "urlFilter": "blocktop",
+      "resourceTypes": ["main_frame"]
+    },
+    "action": {
+      "type": "block"
+    }
+  },
+
+
+ rule 2 will block top-level navigation to + https://developer.mozilla.org/favicon.ico?blocktop + because the "resourceTypes" array contains "main_frame". +
+
+ rule 2 will not block this image (containing 'blocktop') + + because "image" is not in the "resourceTypes" array. +
+ +

Block all requests containing 'blockall'

+Given the following rule: +
+  {
+    "id": 3,
+    "condition": {
+      "urlFilter": "blockall",
+      "excludedResourceTypes": []
+    },
+    "action": {
+      "type": "block"
+    }
+  }
+
+
+ rule 3 will block this image (containing 'blockall'): + +
+
+ rule 3 will block top-level navigation to + https://developer.mozilla.org/favicon.ico?blockall + because "excludedResourceTypes" is set to an empty array. +
+ Note: not blocked in Chrome due to https://crbug.com/1432871. +
+ + + diff --git a/dnr-dynamic-with-options/README.md b/dnr-dynamic-with-options/README.md new file mode 100644 index 00000000..72c6e14a --- /dev/null +++ b/dnr-dynamic-with-options/README.md @@ -0,0 +1,100 @@ +# dnr-dynamic-with-options + +Demonstrates a generic way to request host permissions and register +declarativeNetRequest rules to modify network requests, without any +install-time permission warnings. The options_ui page offers a way to request +permissions and register DNR rules. + +## What it does + +After loading the extension, visit the extension options page: + +1. Visit `about:addons`. +2. Go to the extension at "DNR Dynamic with options". +3. Click on Preferences to view its options page (options.html). + +At this options page: + +1. Input the list of host permissions and click on "Grant host permissions". +2. Input the list of declarativeNetRequest rules and click "Save". +3. Trigger a network request to verify that the rule matched. + +### Example for options page + +Host permissions: + +```json +["*://example.com/"] +``` + +DNR rules: + +```json +[ + { + "id": 1, + "priority": 1, + "condition": { + "urlFilter": "|https://example.com/", + "resourceTypes": [ + "main_frame" + ] + }, + "action": { + "type": "block" + } + } +] +``` + +Manual test case: Visit https://example.com/ and verify that it was blocked. + +# What it shows + +How to have an extension with zero install-time permission warnings, and only +request (host) permissions dynamically as needed: + +- declares the "declarativeNetRequestWithHostAccess" permission, which + unlocks the declarativeNetRequest API without install-time warning. + In contrast, the "declarativeNetRequest" permission has the same effect, + but has the "Block content on any page" permission warning. +- declares the most permissive match pattern in `optional_host_permissions`. +- calls `permissions.request` to request host permissions. +- uses `permissions.getAll` and `permissions.remove` to reset permissions. + +How to retrieve and dynamically register declarativeNetRequest rules: + +- `declarativeNetRequest.getDynamicRules` and + `declarativeNetRequest.updateDynamicRules` to manage DNR rules that persist + across extension restarts. When loaded non-temporarily, these rules also + persist across browser restarts. +- `declarativeNetRequest.getSessionRules` and + `declarativeNetRequest.updateSessionRules` to manage DNR rules that are + session-scoped, i.e. cleared upon extension unload or browser quits. + +## Note on `optional_host_permissions` and `optional_permissions` + +Firefox does not support `optional_host_permissions` permissions yet, but still +supports host permissions in `optional_permissions` +(https://bugzilla.mozilla.org/show_bug.cgi?id=1766026). + +Chrome recognizes `optional_host_permissions` but does not support host +permissions in `optional_permissions`. + +To support both, manifest.json contains both `optional_host_permissions` and +`optional_permissions`. + +## Comparison with Manifest Version 2 + +While this example uses `"manifest_version": 3`, the functionality is not +specific to Manifest Version 3. + +To create a MV2 version of the extension, modify `manifest.json` as follows: + +- Set `manifest_version` to 2. +- Use `optional_permissions` instead of `optional_host_permissions` to list + optional host permissions. + - In this specific example, `optional_permissions` is already present with + the same value as `optional_host_permissions` for the reasons explained in + the previous section. The latter is MV3-only and can be removed from a MV2 + manifest. diff --git a/dnr-dynamic-with-options/manifest.json b/dnr-dynamic-with-options/manifest.json new file mode 100644 index 00000000..1cc90682 --- /dev/null +++ b/dnr-dynamic-with-options/manifest.json @@ -0,0 +1,12 @@ +{ + "manifest_version": 3, + "name": "DNR dynamic with options", + "description": "Modify requests according to user-specifies rules in the options page.", + "version": "0.1", + "permissions": ["declarativeNetRequestWithHostAccess"], + "optional_host_permissions": ["*://*/"], + "optional_permissions": ["*://*/"], + "options_ui": { + "page": "options.html" + } +} diff --git a/dnr-dynamic-with-options/options.css b/dnr-dynamic-with-options/options.css new file mode 100644 index 00000000..254fe16e --- /dev/null +++ b/dnr-dynamic-with-options/options.css @@ -0,0 +1,8 @@ +.input-and-buttons legend { + font-weight: bold; +} +.input-and-buttons textarea { + display: block; + width: 100%; + min-height: 7em; +} diff --git a/dnr-dynamic-with-options/options.html b/dnr-dynamic-with-options/options.html new file mode 100644 index 00000000..bea7c417 --- /dev/null +++ b/dnr-dynamic-with-options/options.html @@ -0,0 +1,36 @@ + + + + + + + + +
+ Allowed host permissions + Specify the JSON-formatted list of allowed host permissions (documentation: origins). + + + + +
+ +
+ Dynamic declarativeNetRequest rules (persists across restarts) + Specify the JSON-formatted list of dynamic DNR rules (documentation: declarativeNetRequest rules). + + + +
+ +
+ Session-scoped declarativeNetRequest rules (cleared on extension unload/reload) + Specify the JSON-formatted list of session DNR rules (documentation: declarativeNetRequest rules). + + + +
+ + + + diff --git a/dnr-dynamic-with-options/options.js b/dnr-dynamic-with-options/options.js new file mode 100644 index 00000000..ab1471a0 --- /dev/null +++ b/dnr-dynamic-with-options/options.js @@ -0,0 +1,90 @@ +"use strict"; + +if (typeof browser == "undefined") { + // `browser` is not defined in Chrome, but Manifest V3 extensions in Chrome + // also support promises in the `chrome` namespace, like Firefox. To easily + // test the example without modifications, polyfill "browser" to "chrome". + globalThis.browser = chrome; +} + +function initializePrefHandlerForHostPermissions() { + const textarea = document.getElementById("input-host-permissions"); + const statusOutput = document.getElementById("status-host-permissions"); + document.getElementById("grant-host-permissions").onclick = async () => { + try { + let origins = JSON.parse(textarea.value); + statusOutput.value = "Requesting permissions"; + let ok = await browser.permissions.request({ origins }); + statusOutput.value = ok ? "Permissions granted" : "Permissions denied"; + } catch (e) { + statusOutput.value = `Failed to grant permissions: ${e}`; + } + }; + document.getElementById("reset-host-permissions").onclick = async () => { + let permissions = await browser.permissions.getAll(); + await browser.permissions.remove({ origins: permissions.origins }); + statusOutput.value = `Removed: ${JSON.stringify(permissions.origins)}`; + }; + + browser.permissions.getAll().then( + permissions => { + textarea.value = JSON.stringify(permissions.origins, null, 2); + } + ); +} + +function serializeRules(rules) { + // The getDynamicRules and getSessionRules APIs returns the rules, including + // optional keys. For readability, we strip all optional keys. + // JSON.stringify will drop keys if the replacer function returns undefined. + const replacer = (key, value) => value === null ? undefined : value; + return JSON.stringify(rules, replacer, 2); +} + +function initializePrefHandlerForDynamicDNR() { + const textarea = document.getElementById("input-dynamic-rules"); + const statusOutput = document.getElementById("status-dynamic-rules"); + document.getElementById("save-dynamic-rules").onclick = async () => { + try { + let newRules = JSON.parse(textarea.value); + let oldRules = await browser.declarativeNetRequest.getDynamicRules(); + await browser.declarativeNetRequest.updateDynamicRules({ + removeRuleIds: oldRules.map(rule => rule.id), + addRules: newRules, + }); + statusOutput.value = `Saved ${newRules.length} rules`; + } catch (e) { + statusOutput.value = `Failed to save rules: ${e}`; + } + }; + + browser.declarativeNetRequest.getDynamicRules().then(rules => { + textarea.value = serializeRules(rules); + }); +} + +function initializePrefHandlerForSessionDNR() { + const textarea = document.getElementById("input-session-rules"); + const statusOutput = document.getElementById("status-session-rules"); + document.getElementById("save-session-rules").onclick = async () => { + try { + let newRules = JSON.parse(textarea.value); + let oldRules = await browser.declarativeNetRequest.getSessionRules(); + await browser.declarativeNetRequest.updateSessionRules({ + removeRuleIds: oldRules.map(rule => rule.id), + addRules: newRules, + }); + statusOutput.value = `Saved ${newRules.length} rules`; + } catch (e) { + statusOutput.value = `Failed to save rules: ${e}`; + } + }; + + browser.declarativeNetRequest.getSessionRules().then(rules => { + textarea.value = serializeRules(rules); + }); +} + +initializePrefHandlerForHostPermissions(); +initializePrefHandlerForDynamicDNR(); +initializePrefHandlerForSessionDNR(); diff --git a/dnr-redirect-url/README.md b/dnr-redirect-url/README.md new file mode 100644 index 00000000..697784d8 --- /dev/null +++ b/dnr-redirect-url/README.md @@ -0,0 +1,49 @@ +# dnr-redirect-url + +Demonstrates multiple ways to redirect requests using the declarativeNetRequest +API through the `declarative_net_request` manifest key. Demonstrates aspects of +Manifest Version 3 (MV3): action, host_permissions, web_accessible_resources. + +## What it does + +This extension redirects requests from the example.com domain to other destinations: + +- example.com/ to `redirectTarget.html` packaged with the extension. +- example.com/ew to extensionworkshop.com +- https://www.example.com/[anything] to the same URL but the domain changed to example.com and `?redirected_from_www=1` appended to the URL. +- URLs matching regular expression `^https?://([^?]+)$` to the same URL but with scheme changed to https and `?redirected_by_regex` appended. + +Redirecting requires host permissions for the pre-redirect URLs. Manifest V3 extensions do not have access to these by default. +The permission to these can be granted from the extension action popup. + +# What it shows + +- how to use the declarativeNetRequest API through the `declarative_net_request` manifest key. +- using the `permissions.contains` API to check whether an extension is granted host permissions. +- using the `permissions.request` API to request host permissions, from the `action` popup panel. +- how to redirect requests to a another website. +- how to redirect requests to a page packaged with the extension, and also listed in `web_accessible_resources`. +- how to redirect requests and transform the URL with the `transform` and `queryTransform` options. +- how to redirect a URL matched by a regular expression in `regexFilter` and a generated redirect target in `regexSubstitution`. +- how to use "priority" to specify the highest-priority rule that should match when multiple rule conditions are matched for a given request. +- manifest.json specifies the "declarativeNetRequestWithHostAccess" permission, + which does not have a separate permission warning. In contrast, the + "declarativeNetRequest" permission has the same effect, but has the "Block + content on any page" permission warning. + +## Comparison with Manifest Version 2 + +While this example uses `"manifest_version": 3`, the functionality is not +specific to Manifest Version 3. + +To create a MV2 version of the extension, modify `manifest.json` as follows: + +- Set `manifest_version` to 2. +- Rename `host_permissions` to `optional_permissions`. +- Rename `action` to `browser_action`. +- Set `web_accessible_resources` to `["redirectTarget.html"]` + +As an alternative to renaming `host_permissions` to `optional_permissions`, +add the match patterns in the `host_permissions` array to the existing +`permissions` key of the MV2 manifest. Then the user does not need to opt in to +the host permission, and the extension immediately works after installation. diff --git a/dnr-redirect-url/manifest.json b/dnr-redirect-url/manifest.json new file mode 100644 index 00000000..e9417744 --- /dev/null +++ b/dnr-redirect-url/manifest.json @@ -0,0 +1,24 @@ +{ + "manifest_version": 3, + "name": "Redirect example.com requests", + "description": "Redirects example.com requests. Redirects always require host_permissions.", + "version": "0.1", + "permissions": ["declarativeNetRequestWithHostAccess"], + "host_permissions": ["*://*.example.com/"], + "declarative_net_request": { + "rule_resources": [ + { + "id": "ruleset", + "enabled": true, + "path": "redirect-rules.json" + } + ] + }, + "action": { + "default_popup": "popup.html" + }, + "web_accessible_resources": [{ + "resources": ["redirectTarget.html"], + "matches": ["*://example.com/*"] + }] +} diff --git a/dnr-redirect-url/popup.html b/dnr-redirect-url/popup.html new file mode 100644 index 00000000..7e59ce46 --- /dev/null +++ b/dnr-redirect-url/popup.html @@ -0,0 +1,30 @@ + + + + + + + + +

Host permission requirement

+ To redirect requests, the extension needs host permissions.
+ "Manage Extensions" (about:addons) offers a built-in UI to grant or revoke permissions.
+ The permissions extension API offers the ability to build your own UI: +

+ + +

Test cases

+ There are four rules in redirect-rules.json; each rule has a test case here. + + + + + diff --git a/dnr-redirect-url/popup.js b/dnr-redirect-url/popup.js new file mode 100644 index 00000000..0c2ee8c6 --- /dev/null +++ b/dnr-redirect-url/popup.js @@ -0,0 +1,37 @@ +"use strict"; + +if (typeof browser == "undefined") { + // `browser` is not defined in Chrome, but Manifest V3 extensions in Chrome + // also support promises in the `chrome` namespace, like Firefox. To easily + // test the example without modifications, polyfill "browser" to "chrome". + globalThis.browser = chrome; +} + +const permissions = { + // This origin is listed in host_permissions: + origins: ["*://*.example.com/"], +}; + +const checkbox_host_permission = document.getElementById("checkbox_host_permission"); +checkbox_host_permission.onchange = async () => { + if (checkbox_host_permission.checked) { + let granted = await browser.permissions.request(permissions); + if (!granted) { + // Permission request was denied by the user. + checkbox_host_permission.checked = false; + } + } else { + try { + await browser.permissions.remove(permissions); + } catch (e) { + // While Chrome allows granting of host_permissions that have manually + // been revoked by the user, it fails when revoking them, with + // "Error: You cannot remove required permissions." + console.error(e); + checkbox_host_permission.checked = true; + } + } +}; +browser.permissions.contains(permissions).then(granted => { + checkbox_host_permission.checked = granted; +}); diff --git a/dnr-redirect-url/redirect-rules.json b/dnr-redirect-url/redirect-rules.json new file mode 100644 index 00000000..bc75b95a --- /dev/null +++ b/dnr-redirect-url/redirect-rules.json @@ -0,0 +1,65 @@ +[ + { + "id": 1, + "priority": 4, + "condition": { + "urlFilter": "||example.com/|", + "resourceTypes": ["main_frame"] + }, + "action": { + "type": "redirect", + "redirect": { + "extensionPath": "/redirectTarget.html" + } + } + }, + { + "id": 2, + "priority": 3, + "condition": { + "urlFilter": "||example.com/ew", + "resourceTypes": ["main_frame"] + }, + "action": { + "type": "redirect", + "redirect": { + "url": "https://extensionworkshop.com/" + } + } + }, + { + "id": 3, + "priority": 2, + "condition": { + "urlFilter": "|https://www.example.com/", + "resourceTypes": ["main_frame"] + }, + "action": { + "type": "redirect", + "redirect": { + "transform": { + "host": "example.com", + "queryTransform": { + "addOrReplaceParams": [ + { "key": "redirected_from_www", "value": "1" } + ] + } + } + } + } + }, + { + "id": 4, + "condition": { + "regexFilter": "^https?://([^?]+)$", + "requestDomains": ["example.com"], + "resourceTypes": ["main_frame"] + }, + "action": { + "type": "redirect", + "redirect": { + "regexSubstitution": "https://\\1?redirected_by_regex" + } + } + } +] diff --git a/dnr-redirect-url/redirectTarget.html b/dnr-redirect-url/redirectTarget.html new file mode 100644 index 00000000..7672903c --- /dev/null +++ b/dnr-redirect-url/redirectTarget.html @@ -0,0 +1,38 @@ + + + + + +redirectTarget.html + + + This page is the redirect target of requests matching rule 1 from redirect-rules.json.
+ The pattern ||example.com/| means: (sub)domain of example.com, with path "/" and nothing else before the end of the URL. +
+  {
+    "id": 1,
+    "priority": 4,
+    "condition": {
+      "urlFilter": "||example.com/|",
+      "resourceTypes": ["main_frame"]
+    },
+    "action": {
+      "type": "redirect",
+      "redirect": {
+        "extensionPath": "/redirectTarget.html"
+      }
+    }
+  },
+
+ +For the redirect to have succeeded, three conditions need to be met: + + + +See popup.html for the permissions UI and examples. + + diff --git a/examples.json b/examples.json index 4057a0a2..99ad4668 100644 --- a/examples.json +++ b/examples.json @@ -156,6 +156,43 @@ "javascript_apis": [], "name": "discogs-search" }, + { + "description": "Demonstrates how to block network requests without host permissions through the declarativeNetRequest API with the `declarative_net_request` manifest key.", + "javascript_apis": [ + "declarativeNetRequest.Rule", + "declarativeNetRequest.RuleAction", + "declarativeNetRequest.RuleCondition" + ], + "name": "dnr-block-only" + }, + { + "description": "Demonstrates a generic way to request host permissions and register declarativeNetRequest rules to modify network requests, without any install-time permission warnings. The options_ui page offers a way to request permissions and register DNR rules.", + "javascript_apis": [ + "declarativeNetRequest.Rule", + "declarativeNetRequest.getDynamicRules", + "declarativeNetRequest.getSessionRules", + "declarativeNetRequest.updateDynamicRules", + "declarativeNetRequest.updateSessionRules", + "permissions.getAll", + "permissions.remove", + "permissions.request" + ], + "name": "dnr-dynamic-with-options" + }, + { + "description": "Demonstrates multiple ways to redirect requests using the declarativeNetRequest API through the `declarative_net_request` manifest key. Demonstrates aspects of Manifest Version 3 (MV3): action, host_permissions, web_accessible_resources, and includes a comparison with Manifest Version 2 (MV2).", + "javascript_apis": [ + "declarativeNetRequest.Redirect", + "declarativeNetRequest.Rule", + "declarativeNetRequest.RuleAction", + "declarativeNetRequest.RuleCondition", + "declarativeNetRequest.URLTransform", + "permissions.contains", + "permissions.remove", + "permissions.request" + ], + "name": "dnr-redirect-url" + }, { "description": "Dynamic theme example", "javascript_apis": [ From 3da16b765d3bdf34103c8ae897c4d9a86e447a64 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Wed, 17 May 2023 14:25:56 +0200 Subject: [PATCH 2/8] Apply suggestions from code review to dnr-block-only/README.md Co-authored-by: rebloor --- dnr-block-only/README.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/dnr-block-only/README.md b/dnr-block-only/README.md index fb1b6fdb..6f77e1e6 100644 --- a/dnr-block-only/README.md +++ b/dnr-block-only/README.md @@ -1,25 +1,27 @@ # dnr-block-only -Demonstrates how to block network requests without host permissions through the -declarativeNetRequest API with the `declarative_net_request` manifest key.", +Demonstrates how to block network requests without host permissions using the +declarativeNetRequest API with the `declarative_net_request` manifest key. ## What it does -This extension blocks network requests: +This extension blocks: -- requests to URLs containing "blocksub" (except for top-level navigations). +- network requests to URLs containing "blocksub" (except for top-level navigations). - top-level navigation to URLs containing "blocktop". - all requests containing "blockall". -`testpage.html` can be loaded to see the extension in action. +Load `testpage.html` to see the extension in action. This demo page does not need to be packaged with the extension. # What it shows -- how to use the declarativeNetRequest API through the `declarative_net_request` manifest key. -- how to use the "resourceTypes" and "excludedResourceTypes" condition of a declarativeNetRequest rule. -- how to block network requests without host permissions, but instead through the "declarativeNetRequest" permission that triggers the "Block content on any page" permission warning at install time. +This example shows how to: + +- use the declarativeNetRequest API through the `declarative_net_request` manifest key. +- use the "resourceTypes" and "excludedResourceTypes" conditions of a declarativeNetRequest rule. +- block network requests without host permissions using the "declarativeNetRequest" permission, which triggers the "Block content on any page" permission warning at install time. This is the only cross-browser way to block network requests (at least in -Firefox, Chrome and Safari). While the extension uses `"manifest_version": 3`, +Firefox, Chrome, and Safari). While the extension uses `"manifest_version": 3`, it also works identically with `"manifest_version": 2`. From fe206cbd68492857c82fb37c9ecd348f33ad8119 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Wed, 17 May 2023 14:28:20 +0200 Subject: [PATCH 3/8] Apply suggestions from code review to dnr-dynamic-with-options/README.md Co-authored-by: rebloor --- dnr-dynamic-with-options/README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/dnr-dynamic-with-options/README.md b/dnr-dynamic-with-options/README.md index 72c6e14a..c0653e1c 100644 --- a/dnr-dynamic-with-options/README.md +++ b/dnr-dynamic-with-options/README.md @@ -3,7 +3,7 @@ Demonstrates a generic way to request host permissions and register declarativeNetRequest rules to modify network requests, without any install-time permission warnings. The options_ui page offers a way to request -permissions and register DNR rules. +permissions and register declarative net request (DNR) rules. ## What it does @@ -13,7 +13,7 @@ After loading the extension, visit the extension options page: 2. Go to the extension at "DNR Dynamic with options". 3. Click on Preferences to view its options page (options.html). -At this options page: +On the options page: 1. Input the list of host permissions and click on "Grant host permissions". 2. Input the list of declarativeNetRequest rules and click "Save". @@ -47,12 +47,12 @@ DNR rules: ] ``` -Manual test case: Visit https://example.com/ and verify that it was blocked. +Manual test case: Visit https://example.com/ and verify that it is blocked. # What it shows -How to have an extension with zero install-time permission warnings, and only -request (host) permissions dynamically as needed: +How to create an extension with no install-time permission warnings and +request (host) permissions as needed: - declares the "declarativeNetRequestWithHostAccess" permission, which unlocks the declarativeNetRequest API without install-time warning. @@ -62,7 +62,7 @@ request (host) permissions dynamically as needed: - calls `permissions.request` to request host permissions. - uses `permissions.getAll` and `permissions.remove` to reset permissions. -How to retrieve and dynamically register declarativeNetRequest rules: +How to retrieve and dynamically register declarativeNetRequest rules, using: - `declarativeNetRequest.getDynamicRules` and `declarativeNetRequest.updateDynamicRules` to manage DNR rules that persist @@ -70,19 +70,19 @@ How to retrieve and dynamically register declarativeNetRequest rules: persist across browser restarts. - `declarativeNetRequest.getSessionRules` and `declarativeNetRequest.updateSessionRules` to manage DNR rules that are - session-scoped, i.e. cleared upon extension unload or browser quits. + session-scoped, that is, cleared when an extension unloads or the browser quits. ## Note on `optional_host_permissions` and `optional_permissions` -Firefox does not support `optional_host_permissions` permissions yet, but still +Firefox does not support `optional_host_permissions` permissions, it supports host permissions in `optional_permissions` (https://bugzilla.mozilla.org/show_bug.cgi?id=1766026). Chrome recognizes `optional_host_permissions` but does not support host permissions in `optional_permissions`. -To support both, manifest.json contains both `optional_host_permissions` and -`optional_permissions`. +To support both, include `optional_host_permissions` and `optional_permissions` +in your manifest.json. ## Comparison with Manifest Version 2 @@ -94,7 +94,7 @@ To create a MV2 version of the extension, modify `manifest.json` as follows: - Set `manifest_version` to 2. - Use `optional_permissions` instead of `optional_host_permissions` to list optional host permissions. - - In this specific example, `optional_permissions` is already present with + - In this example, `optional_permissions` is present with the same value as `optional_host_permissions` for the reasons explained in the previous section. The latter is MV3-only and can be removed from a MV2 manifest. From 98c6e3643f5705b52ee9a92168c96c12fd40a470 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Wed, 17 May 2023 14:29:13 +0200 Subject: [PATCH 4/8] Apply suggestions from code review to dnr-redirect-url/README.md Co-authored-by: rebloor --- dnr-redirect-url/README.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/dnr-redirect-url/README.md b/dnr-redirect-url/README.md index 697784d8..e548ca75 100644 --- a/dnr-redirect-url/README.md +++ b/dnr-redirect-url/README.md @@ -2,7 +2,7 @@ Demonstrates multiple ways to redirect requests using the declarativeNetRequest API through the `declarative_net_request` manifest key. Demonstrates aspects of -Manifest Version 3 (MV3): action, host_permissions, web_accessible_resources. +Manifest Version 3 (MV3): action, host_permissions, and web_accessible_resources. ## What it does @@ -18,18 +18,18 @@ The permission to these can be granted from the extension action popup. # What it shows -- how to use the declarativeNetRequest API through the `declarative_net_request` manifest key. -- using the `permissions.contains` API to check whether an extension is granted host permissions. -- using the `permissions.request` API to request host permissions, from the `action` popup panel. -- how to redirect requests to a another website. -- how to redirect requests to a page packaged with the extension, and also listed in `web_accessible_resources`. -- how to redirect requests and transform the URL with the `transform` and `queryTransform` options. -- how to redirect a URL matched by a regular expression in `regexFilter` and a generated redirect target in `regexSubstitution`. -- how to use "priority" to specify the highest-priority rule that should match when multiple rule conditions are matched for a given request. -- manifest.json specifies the "declarativeNetRequestWithHostAccess" permission, - which does not have a separate permission warning. In contrast, the - "declarativeNetRequest" permission has the same effect, but has the "Block - content on any page" permission warning. + +This extension shows how to: + +- use the declarativeNetRequest API through the `declarative_net_request` manifest key. +- use the `permissions.contains` API to check whether an extension is granted host permissions. +- use the `permissions.request` API to request host permissions from the `action` popup panel. +- redirect requests to another website. +- redirect requests to a page packaged in the extension and listed in `web_accessible_resources`. +- redirect requests and transform the URL with the `transform` and `queryTransform` options. +- redirect a URL matching a regular expression in `regexFilter` and generate a redirect target in `regexSubstitution`. +- use "priority" to specify the rule to action when multiple rule conditions are matched to a request. +- specify the "declarativeNetRequestWithHostAccess" permission in the manifest.json, which does not trigger a permission warning. (Compared to the"declarativeNetRequest" permission, which has the same effect but displays the "Block content on any page" permission warning.) ## Comparison with Manifest Version 2 @@ -44,6 +44,6 @@ To create a MV2 version of the extension, modify `manifest.json` as follows: - Set `web_accessible_resources` to `["redirectTarget.html"]` As an alternative to renaming `host_permissions` to `optional_permissions`, -add the match patterns in the `host_permissions` array to the existing +add the match patterns in the `host_permissions` array to the `permissions` key of the MV2 manifest. Then the user does not need to opt in to -the host permission, and the extension immediately works after installation. +the host permission, and the extension works immediately after installation. From 017d5c0f8a189a15f786951cb928fd0278df0611 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Wed, 17 May 2023 15:31:26 +0200 Subject: [PATCH 5/8] Apply suggestions from code review to remaining files Co-authored-by: rebloor --- dnr-block-only/manifest.json | 2 +- dnr-block-only/testpage.html | 2 +- dnr-dynamic-with-options/manifest.json | 2 +- dnr-redirect-url/popup.html | 5 ++--- dnr-redirect-url/redirectTarget.html | 2 +- examples.json | 4 ++-- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/dnr-block-only/manifest.json b/dnr-block-only/manifest.json index bd6481cc..ed039746 100644 --- a/dnr-block-only/manifest.json +++ b/dnr-block-only/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Block only, without host_permissions", - "description": "Blocks requests to 'blocksub', 'blocktop' or 'blockall'. Due to the 'declarativeNetRequest' permission, host_permissions in manifest.json are not needed.", + "description": "Blocks requests to 'blocksub', 'blocktop', and 'blockall'. Uses the 'declarativeNetRequest' permission, meaning that host_permissions in manifest.json are not needed.", "version": "0.1", "permissions": [ "declarativeNetRequest" diff --git a/dnr-block-only/testpage.html b/dnr-block-only/testpage.html index b5558e59..02b1f54f 100644 --- a/dnr-block-only/testpage.html +++ b/dnr-block-only/testpage.html @@ -38,7 +38,7 @@

Block requests containing 'blocksub' (except main_frame)

rule 1 will not block top-level navigations to https://developer.mozilla.org/favicon.ico?blocksub - because top-level navigation ("main_frame") requests are not matched by default, + because top-level navigation ("main_frame") requests are not matched when "resourceTypes" and "excludedResourceTypes" are not specified.
diff --git a/dnr-dynamic-with-options/manifest.json b/dnr-dynamic-with-options/manifest.json index 1cc90682..bc16e834 100644 --- a/dnr-dynamic-with-options/manifest.json +++ b/dnr-dynamic-with-options/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "DNR dynamic with options", - "description": "Modify requests according to user-specifies rules in the options page.", + "description": "Modify requests according to the rules specified by the user in the options page.", "version": "0.1", "permissions": ["declarativeNetRequestWithHostAccess"], "optional_host_permissions": ["*://*/"], diff --git a/dnr-redirect-url/popup.html b/dnr-redirect-url/popup.html index 7e59ce46..ac92ca5b 100644 --- a/dnr-redirect-url/popup.html +++ b/dnr-redirect-url/popup.html @@ -8,8 +8,7 @@

Host permission requirement

To redirect requests, the extension needs host permissions.
- "Manage Extensions" (about:addons) offers a built-in UI to grant or revoke permissions.
- The permissions extension API offers the ability to build your own UI: + While "Manage Extensions" (about:addons) offers a built-in UI to grant or revoke permissions, this extension uses the permissions API to build the request into the UI:

Host permission requirement

Test cases

There are four rules in redirect-rules.json; each rule has a test case here.
    -
  • 1: example.com/ should redirect to redirectTarget.html packaged within the extension.
  • +
  • 1: example.com/ should redirect to redirectTarget.html packaged in the extension.
  • 2: example.com/ew should redirect to extensionworkshop.com
  • 3: https://www.example.com/anything should redirect to https://example.com/anything?redirected_from_www=1.
  • 4: http://example.com/no_question should redirect to https://example.com/no_question?redirected_by_regex.
  • diff --git a/dnr-redirect-url/redirectTarget.html b/dnr-redirect-url/redirectTarget.html index 7672903c..a9b1d677 100644 --- a/dnr-redirect-url/redirectTarget.html +++ b/dnr-redirect-url/redirectTarget.html @@ -25,7 +25,7 @@ }, -For the redirect to have succeeded, three conditions need to be met: +For the redirect to have succeeded, three conditions must be met:
    • The declarativeNetRequest (DNR) rule should match the request.
    • diff --git a/examples.json b/examples.json index 99ad4668..994dd9ce 100644 --- a/examples.json +++ b/examples.json @@ -157,7 +157,7 @@ "name": "discogs-search" }, { - "description": "Demonstrates how to block network requests without host permissions through the declarativeNetRequest API with the `declarative_net_request` manifest key.", + "description": "Demonstrates how to block network requests without host permissions using the declarativeNetRequest API with the `declarative_net_request` manifest key.", "javascript_apis": [ "declarativeNetRequest.Rule", "declarativeNetRequest.RuleAction", @@ -180,7 +180,7 @@ "name": "dnr-dynamic-with-options" }, { - "description": "Demonstrates multiple ways to redirect requests using the declarativeNetRequest API through the `declarative_net_request` manifest key. Demonstrates aspects of Manifest Version 3 (MV3): action, host_permissions, web_accessible_resources, and includes a comparison with Manifest Version 2 (MV2).", + "description": "Demonstrates multiple ways to redirect requests using the declarativeNetRequest API through the `declarative_net_request` manifest key. Demonstrates aspects of Manifest Version 3 (MV3): action, host_permissions, and web_accessible_resources, and includes a comparison with Manifest Version 2 (MV2).", "javascript_apis": [ "declarativeNetRequest.Redirect", "declarativeNetRequest.Rule", From ba07083b9daeb0aed0ae17e41bae8616b2ee70e7 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Wed, 17 May 2023 15:58:36 +0200 Subject: [PATCH 6/8] Clarify again --- dnr-block-only/README.md | 16 +++++++++++++--- dnr-dynamic-with-options/README.md | 4 ++-- dnr-redirect-url/README.md | 16 +++++++++++----- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/dnr-block-only/README.md b/dnr-block-only/README.md index 6f77e1e6..aa2e5d8e 100644 --- a/dnr-block-only/README.md +++ b/dnr-block-only/README.md @@ -22,6 +22,16 @@ This example shows how to: - use the "resourceTypes" and "excludedResourceTypes" conditions of a declarativeNetRequest rule. - block network requests without host permissions using the "declarativeNetRequest" permission, which triggers the "Block content on any page" permission warning at install time. -This is the only cross-browser way to block network requests (at least in -Firefox, Chrome, and Safari). While the extension uses `"manifest_version": 3`, -it also works identically with `"manifest_version": 2`. +This example is the only cross-browser way to block network requests (at least +in Firefox, Chrome, and Safari). The webRequest API is an alternative way to +implement this functionality, but is only available in Firefox (MV2 and MV3) +and in Chrome (MV2 only). Safari does not support the webRequest API. + +## Comparison with Manifest Version 2 + +While this example uses `"manifest_version": 3`, the functionality is not +specific to Manifest Version 3. + +To create a MV2 version of the extension, modify `manifest.json` as follows: + +- Set `manifest_version` to 2. diff --git a/dnr-dynamic-with-options/README.md b/dnr-dynamic-with-options/README.md index c0653e1c..ab2fc605 100644 --- a/dnr-dynamic-with-options/README.md +++ b/dnr-dynamic-with-options/README.md @@ -66,8 +66,8 @@ How to retrieve and dynamically register declarativeNetRequest rules, using: - `declarativeNetRequest.getDynamicRules` and `declarativeNetRequest.updateDynamicRules` to manage DNR rules that persist - across extension restarts. When loaded non-temporarily, these rules also - persist across browser restarts. + across extension restarts. These rules also persist across browser restarts, + unless the extension is loaded temporarily or unloaded. - `declarativeNetRequest.getSessionRules` and `declarativeNetRequest.updateSessionRules` to manage DNR rules that are session-scoped, that is, cleared when an extension unloads or the browser quits. diff --git a/dnr-redirect-url/README.md b/dnr-redirect-url/README.md index e548ca75..4fbd9fed 100644 --- a/dnr-redirect-url/README.md +++ b/dnr-redirect-url/README.md @@ -10,10 +10,13 @@ This extension redirects requests from the example.com domain to other destinati - example.com/ to `redirectTarget.html` packaged with the extension. - example.com/ew to extensionworkshop.com -- https://www.example.com/[anything] to the same URL but the domain changed to example.com and `?redirected_from_www=1` appended to the URL. -- URLs matching regular expression `^https?://([^?]+)$` to the same URL but with scheme changed to https and `?redirected_by_regex` appended. +- https://www.example.com/[anything] to the same URL but the domain changed to + example.com and `?redirected_from_www=1` appended to the URL. +- example.com URLs matching regular expression `^https?://([^?]+)$` to the same URL but with the + scheme set to `https:` (if it was `http:` before), and with `?redirected_by_regex` appended. -Redirecting requires host permissions for the pre-redirect URLs. Manifest V3 extensions do not have access to these by default. +Redirecting requires host permissions for the pre-redirect URLs. In Firefox +(and Safari), Manifest V3 extensions do not have access to these by default. The permission to these can be granted from the extension action popup. # What it shows @@ -27,9 +30,12 @@ This extension shows how to: - redirect requests to another website. - redirect requests to a page packaged in the extension and listed in `web_accessible_resources`. - redirect requests and transform the URL with the `transform` and `queryTransform` options. -- redirect a URL matching a regular expression in `regexFilter` and generate a redirect target in `regexSubstitution`. +- redirect a URL matching a regular expression in `regexFilter` to `regexSubstitution`. - use "priority" to specify the rule to action when multiple rule conditions are matched to a request. -- specify the "declarativeNetRequestWithHostAccess" permission in the manifest.json, which does not trigger a permission warning. (Compared to the"declarativeNetRequest" permission, which has the same effect but displays the "Block content on any page" permission warning.) +- specify the "declarativeNetRequestWithHostAccess" permission in the + manifest.json, which does not trigger a permission warning. (Compared to + the "declarativeNetRequest" permission, which has the same effect but displays + the "Block content on any page" permission warning.) ## Comparison with Manifest Version 2 From e72a98d1cb28dcaffa7c7ad84d80f54a5c6758a4 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Wed, 17 May 2023 17:47:13 +0200 Subject: [PATCH 7/8] Emphasize that dnr-dynamic-with-options does not use BG --- dnr-dynamic-with-options/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dnr-dynamic-with-options/README.md b/dnr-dynamic-with-options/README.md index ab2fc605..9b11c052 100644 --- a/dnr-dynamic-with-options/README.md +++ b/dnr-dynamic-with-options/README.md @@ -2,7 +2,7 @@ Demonstrates a generic way to request host permissions and register declarativeNetRequest rules to modify network requests, without any -install-time permission warnings. The options_ui page offers a way to request +install-time permission warnings. The `options_ui` page offers a way to request permissions and register declarative net request (DNR) rules. ## What it does @@ -72,6 +72,10 @@ How to retrieve and dynamically register declarativeNetRequest rules, using: `declarativeNetRequest.updateSessionRules` to manage DNR rules that are session-scoped, that is, cleared when an extension unloads or the browser quits. +How these registered DNR rules can modify network requests without requiring an +active extension script in the background, in a cross-browser way (at least in +Firefox, Chrome, and Safari). + ## Note on `optional_host_permissions` and `optional_permissions` Firefox does not support `optional_host_permissions` permissions, it From 25fb16daaad377cf7bce5fdc559ea0916eab2e50 Mon Sep 17 00:00:00 2001 From: Rob Wu Date: Wed, 17 May 2023 18:06:54 +0200 Subject: [PATCH 8/8] Wrap README at 80 characters and minor fixups --- dnr-block-only/README.md | 13 +++++++--- dnr-dynamic-with-options/README.md | 3 ++- dnr-redirect-url/README.md | 41 ++++++++++++++++++------------ 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/dnr-block-only/README.md b/dnr-block-only/README.md index aa2e5d8e..94916c3d 100644 --- a/dnr-block-only/README.md +++ b/dnr-block-only/README.md @@ -7,7 +7,8 @@ declarativeNetRequest API with the `declarative_net_request` manifest key. This extension blocks: -- network requests to URLs containing "blocksub" (except for top-level navigations). +- network requests to URLs containing "blocksub" (except for top-level + navigations). - top-level navigation to URLs containing "blocktop". - all requests containing "blockall". @@ -18,9 +19,13 @@ This demo page does not need to be packaged with the extension. This example shows how to: -- use the declarativeNetRequest API through the `declarative_net_request` manifest key. -- use the "resourceTypes" and "excludedResourceTypes" conditions of a declarativeNetRequest rule. -- block network requests without host permissions using the "declarativeNetRequest" permission, which triggers the "Block content on any page" permission warning at install time. +- use the declarativeNetRequest API through the `declarative_net_request` + manifest key. +- use the "resourceTypes" and "excludedResourceTypes" conditions of a + declarativeNetRequest rule. +- block network requests without host permissions using the + "declarativeNetRequest" permission, which triggers the "Block content on any + page" permission warning at install time. This example is the only cross-browser way to block network requests (at least in Firefox, Chrome, and Safari). The webRequest API is an alternative way to diff --git a/dnr-dynamic-with-options/README.md b/dnr-dynamic-with-options/README.md index 9b11c052..993ca1b2 100644 --- a/dnr-dynamic-with-options/README.md +++ b/dnr-dynamic-with-options/README.md @@ -70,7 +70,8 @@ How to retrieve and dynamically register declarativeNetRequest rules, using: unless the extension is loaded temporarily or unloaded. - `declarativeNetRequest.getSessionRules` and `declarativeNetRequest.updateSessionRules` to manage DNR rules that are - session-scoped, that is, cleared when an extension unloads or the browser quits. + session-scoped, that is, cleared when an extension unloads or the browser + quits. How these registered DNR rules can modify network requests without requiring an active extension script in the background, in a cross-browser way (at least in diff --git a/dnr-redirect-url/README.md b/dnr-redirect-url/README.md index 4fbd9fed..27bc5276 100644 --- a/dnr-redirect-url/README.md +++ b/dnr-redirect-url/README.md @@ -2,18 +2,21 @@ Demonstrates multiple ways to redirect requests using the declarativeNetRequest API through the `declarative_net_request` manifest key. Demonstrates aspects of -Manifest Version 3 (MV3): action, host_permissions, and web_accessible_resources. +Manifest Version 3 (MV3): `action`, `host_permissions`, and +`web_accessible_resources`. ## What it does -This extension redirects requests from the example.com domain to other destinations: +This extension redirects requests from the example.com domain to other +destinations: - example.com/ to `redirectTarget.html` packaged with the extension. - example.com/ew to extensionworkshop.com - https://www.example.com/[anything] to the same URL but the domain changed to example.com and `?redirected_from_www=1` appended to the URL. -- example.com URLs matching regular expression `^https?://([^?]+)$` to the same URL but with the - scheme set to `https:` (if it was `http:` before), and with `?redirected_by_regex` appended. +- example.com URLs matching regular expression `^https?://([^?]+)$` to the same + URL but with the scheme set to `https:` (if it was `http:` before), and with + `?redirected_by_regex` appended. Redirecting requires host permissions for the pre-redirect URLs. In Firefox (and Safari), Manifest V3 extensions do not have access to these by default. @@ -21,21 +24,27 @@ The permission to these can be granted from the extension action popup. # What it shows - This extension shows how to: -- use the declarativeNetRequest API through the `declarative_net_request` manifest key. -- use the `permissions.contains` API to check whether an extension is granted host permissions. -- use the `permissions.request` API to request host permissions from the `action` popup panel. +- use the declarativeNetRequest API through the `declarative_net_request` + manifest key, along with the "declarativeNetRequestWithHostAccess" + permission. This permission does not trigger a permission warning. (Compared + to the "declarativeNetRequest" permission, which has the same effect but + displays the "Block content on any page" permission warning.) +- use the `action` API to offer a UI surface with which the user can interact. +- use the `permissions.contains` API to check whether an extension is granted + host permissions. +- use the `permissions.request` API to request host permissions as needed. - redirect requests to another website. -- redirect requests to a page packaged in the extension and listed in `web_accessible_resources`. -- redirect requests and transform the URL with the `transform` and `queryTransform` options. -- redirect a URL matching a regular expression in `regexFilter` to `regexSubstitution`. -- use "priority" to specify the rule to action when multiple rule conditions are matched to a request. -- specify the "declarativeNetRequestWithHostAccess" permission in the - manifest.json, which does not trigger a permission warning. (Compared to - the "declarativeNetRequest" permission, which has the same effect but displays - the "Block content on any page" permission warning.) +- redirect requests to a page packaged in the extension and listed in + `web_accessible_resources`. +- redirect requests and transform the URL with the `transform` and + `queryTransform` options. +- redirect a URL matching a regular expression in `regexFilter` to a + destination composed from `regexSubstitution` and the matched URL. +- use "priority" to establish a guaranteed order of precedence between rules. + This results in a predictable redirect outcome when there are multiple + matching rule conditions for a given request. ## Comparison with Manifest Version 2