From b6a97bcbb33b667a7ee4acb2eb8e482333e95a1b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 07:50:19 +0200 Subject: Merging upstream version 1.57.0+dfsg. Signed-off-by: Daniel Baumann --- .eslintrc.yml | 26 + .github/workflows/main.yml | 2 +- CHANGELOG.md | 73 + Makefile | 4 +- assets/assets.dev.json | 188 +- assets/assets.json | 195 +- assets/resources/scriptlets.js | 1126 +- dist/chromium/publish-beta.py | 4 +- dist/firefox/publish-signed-beta.py | 4 +- dist/firefox/updates.json | 4 +- dist/mv3/firefox/publish-signed-beta.py | 4 +- dist/version | 2 +- platform/chromium/manifest.json | 4 + platform/chromium/webext.js | 12 +- platform/common/vapi-background.js | 133 +- platform/common/vapi-client.js | 29 +- platform/firefox/manifest.json | 3 + platform/mv3/description/webstore.be.txt | 2 +- platform/mv3/description/webstore.br_FR.txt | 2 +- platform/mv3/description/webstore.cy.txt | 30 + platform/mv3/description/webstore.et.txt | 10 +- platform/mv3/description/webstore.ms.txt | 30 +- platform/mv3/description/webstore.pl.txt | 6 +- platform/mv3/description/webstore.pt_PT.txt | 4 +- platform/mv3/extension/_locales/ar/messages.json | 4 + platform/mv3/extension/_locales/az/messages.json | 6 +- platform/mv3/extension/_locales/be/messages.json | 4 + platform/mv3/extension/_locales/bg/messages.json | 4 + platform/mv3/extension/_locales/bn/messages.json | 10 +- .../mv3/extension/_locales/br_FR/messages.json | 8 +- platform/mv3/extension/_locales/bs/messages.json | 4 + platform/mv3/extension/_locales/ca/messages.json | 4 + platform/mv3/extension/_locales/cs/messages.json | 8 +- platform/mv3/extension/_locales/cv/messages.json | 6 +- platform/mv3/extension/_locales/cy/messages.json | 162 + platform/mv3/extension/_locales/da/messages.json | 6 +- platform/mv3/extension/_locales/de/messages.json | 6 +- platform/mv3/extension/_locales/el/messages.json | 4 + platform/mv3/extension/_locales/en/messages.json | 6 +- .../mv3/extension/_locales/en_GB/messages.json | 4 + platform/mv3/extension/_locales/eo/messages.json | 6 +- platform/mv3/extension/_locales/es/messages.json | 6 +- platform/mv3/extension/_locales/et/messages.json | 4 + platform/mv3/extension/_locales/eu/messages.json | 8 +- platform/mv3/extension/_locales/fa/messages.json | 6 +- platform/mv3/extension/_locales/fi/messages.json | 4 + platform/mv3/extension/_locales/fil/messages.json | 6 +- platform/mv3/extension/_locales/fr/messages.json | 6 +- platform/mv3/extension/_locales/fy/messages.json | 4 + platform/mv3/extension/_locales/gl/messages.json | 4 + platform/mv3/extension/_locales/gu/messages.json | 6 +- platform/mv3/extension/_locales/he/messages.json | 6 +- platform/mv3/extension/_locales/hi/messages.json | 10 +- platform/mv3/extension/_locales/hr/messages.json | 6 +- platform/mv3/extension/_locales/hu/messages.json | 4 + platform/mv3/extension/_locales/hy/messages.json | 4 + platform/mv3/extension/_locales/id/messages.json | 6 +- platform/mv3/extension/_locales/it/messages.json | 14 +- platform/mv3/extension/_locales/ja/messages.json | 4 + platform/mv3/extension/_locales/ka/messages.json | 4 + platform/mv3/extension/_locales/kk/messages.json | 6 +- platform/mv3/extension/_locales/kn/messages.json | 46 +- platform/mv3/extension/_locales/ko/messages.json | 4 + platform/mv3/extension/_locales/lt/messages.json | 6 +- platform/mv3/extension/_locales/lv/messages.json | 4 + platform/mv3/extension/_locales/mk/messages.json | 6 +- platform/mv3/extension/_locales/ml/messages.json | 4 + platform/mv3/extension/_locales/mr/messages.json | 6 +- platform/mv3/extension/_locales/ms/messages.json | 34 +- platform/mv3/extension/_locales/nb/messages.json | 4 + platform/mv3/extension/_locales/nl/messages.json | 4 + platform/mv3/extension/_locales/oc/messages.json | 6 +- platform/mv3/extension/_locales/pa/messages.json | 4 + platform/mv3/extension/_locales/pl/messages.json | 6 +- .../mv3/extension/_locales/pt_BR/messages.json | 4 + .../mv3/extension/_locales/pt_PT/messages.json | 8 +- platform/mv3/extension/_locales/ro/messages.json | 4 + platform/mv3/extension/_locales/ru/messages.json | 6 +- platform/mv3/extension/_locales/si/messages.json | 6 +- platform/mv3/extension/_locales/sk/messages.json | 6 +- platform/mv3/extension/_locales/sl/messages.json | 6 +- platform/mv3/extension/_locales/so/messages.json | 6 +- platform/mv3/extension/_locales/sq/messages.json | 6 +- platform/mv3/extension/_locales/sr/messages.json | 4 + platform/mv3/extension/_locales/sv/messages.json | 6 +- platform/mv3/extension/_locales/sw/messages.json | 6 +- platform/mv3/extension/_locales/ta/messages.json | 6 +- platform/mv3/extension/_locales/te/messages.json | 4 + platform/mv3/extension/_locales/th/messages.json | 8 +- platform/mv3/extension/_locales/tr/messages.json | 4 + platform/mv3/extension/_locales/uk/messages.json | 4 + platform/mv3/extension/_locales/ur/messages.json | 6 +- platform/mv3/extension/_locales/vi/messages.json | 4 + .../mv3/extension/_locales/zh_CN/messages.json | 4 + .../mv3/extension/_locales/zh_TW/messages.json | 4 + platform/mv3/extension/css/settings.css | 8 + platform/mv3/extension/dashboard.html | 13 +- platform/mv3/extension/js/background.js | 68 +- platform/mv3/extension/js/mode-manager.js | 45 +- .../mv3/extension/js/scripting/css-procedural.js | 41 +- platform/mv3/extension/js/settings.js | 34 +- platform/mv3/extension/js/utils.js | 15 +- platform/mv3/make-rulesets.js | 64 +- platform/mv3/salvage-ruleids.mjs | 117 + platform/mv3/scriptlets/scriptlet.template.js | 2 +- platform/opera/manifest.json | 4 + src/1p-filters.html | 7 +- src/3p-filters.html | 8 +- src/_locales/ar/messages.json | 24 +- src/_locales/az/messages.json | 24 +- src/_locales/be/messages.json | 30 +- src/_locales/bg/messages.json | 26 +- src/_locales/bn/messages.json | 26 +- src/_locales/br_FR/messages.json | 62 +- src/_locales/bs/messages.json | 24 +- src/_locales/ca/messages.json | 24 +- src/_locales/cs/messages.json | 24 +- src/_locales/cv/messages.json | 24 +- src/_locales/cy/messages.json | 1306 ++ src/_locales/da/messages.json | 34 +- src/_locales/de/messages.json | 28 +- src/_locales/el/messages.json | 24 +- src/_locales/en/messages.json | 24 +- src/_locales/en_GB/messages.json | 24 +- src/_locales/eo/messages.json | 34 +- src/_locales/es/messages.json | 24 +- src/_locales/et/messages.json | 24 +- src/_locales/eu/messages.json | 32 +- src/_locales/fa/messages.json | 38 +- src/_locales/fi/messages.json | 24 +- src/_locales/fil/messages.json | 24 +- src/_locales/fr/messages.json | 24 +- src/_locales/fy/messages.json | 24 +- src/_locales/gl/messages.json | 24 +- src/_locales/gu/messages.json | 24 +- src/_locales/he/messages.json | 40 +- src/_locales/hi/messages.json | 54 +- src/_locales/hr/messages.json | 24 +- src/_locales/hu/messages.json | 24 +- src/_locales/hy/messages.json | 24 +- src/_locales/id/messages.json | 26 +- src/_locales/it/messages.json | 26 +- src/_locales/ja/messages.json | 24 +- src/_locales/ka/messages.json | 84 +- src/_locales/kk/messages.json | 24 +- src/_locales/kn/messages.json | 136 +- src/_locales/ko/messages.json | 24 +- src/_locales/ku/messages.json | 1290 -- src/_locales/lt/messages.json | 38 +- src/_locales/lv/messages.json | 24 +- src/_locales/mk/messages.json | 24 +- src/_locales/ml/messages.json | 30 +- src/_locales/mr/messages.json | 24 +- src/_locales/ms/messages.json | 42 +- src/_locales/nb/messages.json | 24 +- src/_locales/nl/messages.json | 24 +- src/_locales/oc/messages.json | 24 +- src/_locales/pa/messages.json | 24 +- src/_locales/pl/messages.json | 28 +- src/_locales/pt_BR/messages.json | 24 +- src/_locales/pt_PT/messages.json | 24 +- src/_locales/ro/messages.json | 26 +- src/_locales/ru/messages.json | 24 +- src/_locales/si/messages.json | 24 +- src/_locales/sk/messages.json | 24 +- src/_locales/sl/messages.json | 24 +- src/_locales/so/messages.json | 24 +- src/_locales/sq/messages.json | 24 +- src/_locales/sr/messages.json | 24 +- src/_locales/sv/messages.json | 32 +- src/_locales/sw/messages.json | 24 +- src/_locales/ta/messages.json | 24 +- src/_locales/te/messages.json | 24 +- src/_locales/th/messages.json | 92 +- src/_locales/tr/messages.json | 28 +- src/_locales/uk/messages.json | 24 +- src/_locales/ur/messages.json | 24 +- src/_locales/vi/messages.json | 24 +- src/_locales/zh_CN/messages.json | 28 +- src/_locales/zh_TW/messages.json | 80 +- src/css/1p-filters.css | 7 +- src/css/3p-filters.css | 27 +- src/css/advanced-settings.css | 1 + src/css/asset-viewer.css | 1 + src/css/code-viewer.css | 1 + src/css/codemirror.css | 47 +- src/css/common.css | 40 +- src/css/dashboard.css | 12 +- src/css/devtools.css | 1 + src/css/document-blocked.css | 6 +- src/css/dom-inspector.css | 1 + src/css/dyna-rules.css | 1 + src/css/epicker-ui.css | 142 +- src/css/fa-icons.css | 2 + src/css/logger-ui.css | 126 +- src/css/popup-fenix.css | 3 +- src/css/whitelist.css | 1 + src/dashboard.html | 33 +- src/devtools.html | 2 + src/dyna-rules.html | 4 +- src/img/flags-of-the-world/np.png | Bin 588 -> 1371 bytes src/img/fontawesome/fontawesome-defs.svg | 2 + src/js/1p-filters.js | 95 +- src/js/3p-filters.js | 102 +- src/js/asset-viewer.js | 1 + src/js/assets.js | 183 +- src/js/background.js | 51 +- src/js/base64-custom.js | 103 +- src/js/benchmarks.js | 58 +- src/js/biditrie.js | 31 +- src/js/broadcast.js | 18 +- src/js/cachestorage.js | 983 +- src/js/click2load.js | 5 +- src/js/codemirror/search.js | 86 +- src/js/codemirror/ubo-static-filtering.js | 447 +- src/js/commands.js | 10 + src/js/contentscript-extra.js | 56 +- src/js/contentscript.js | 31 - src/js/contextmenu.js | 6 +- src/js/cosmetic-filtering.js | 68 +- src/js/dashboard.js | 18 +- src/js/devtools.js | 22 + src/js/dom.js | 4 +- src/js/dyna-rules.js | 168 +- src/js/epicker-ui.js | 57 +- src/js/fa-icons.js | 2 + src/js/filtering-context.js | 2 - src/js/hntrie.js | 35 +- src/js/i18n.js | 36 +- src/js/logger-ui.js | 124 +- src/js/logger.js | 32 +- src/js/messaging.js | 99 +- src/js/pagestore.js | 44 +- src/js/popup-fenix.js | 69 +- src/js/redirect-engine.js | 45 +- src/js/reverselookup.js | 2 +- src/js/s14e-serializer.js | 1405 ++ src/js/scriptlet-filtering-core.js | 28 +- src/js/scriptlet-filtering.js | 202 +- src/js/scriptlets/epicker.js | 45 +- src/js/scriptlets/scriptlet-loglevel-1.js | 49 + src/js/scriptlets/scriptlet-loglevel-2.js | 49 + src/js/scriptlets/should-inject-contentscript.js | 2 +- src/js/settings.js | 53 +- src/js/start.js | 183 +- src/js/static-dnr-filtering.js | 6 +- src/js/static-ext-filtering-db.js | 12 +- src/js/static-ext-filtering.js | 45 +- src/js/static-filtering-parser.js | 52 +- src/js/static-net-filtering.js | 299 +- src/js/storage.js | 355 +- src/js/traffic.js | 24 +- src/js/ublock.js | 2 +- src/js/whitelist.js | 52 +- src/lib/publicsuffixlist/publicsuffixlist.js | 10 +- src/logger-ui.html | 28 +- src/web_accessible_resources/chartbeat.js | 3 + src/web_accessible_resources/epicker-ui.html | 13 +- src/whitelist.html | 7 +- tools/make-assets.sh | 4 +- tools/make-firefox.sh | 2 +- tools/make-mv3.sh | 116 +- uAssets/.github/ISSUE_TEMPLATE/bug_report.yml | 10 +- uAssets/.github/ISSUE_TEMPLATE/report_from_ubo.yml | 10 +- .../ISSUE_TEMPLATE/specific_report_from_ubo.yml | 10 +- uAssets/.github/workflows/main.yml | 2 +- uAssets/.github/workflows/on-youtube-issue.yml | 4 +- uAssets/.github/workflows/update-easylist.yml | 3 +- uAssets/.gitignore | 2 +- uAssets/Makefile | 8 + uAssets/filters/annoyances-cookies.txt | 407 +- uAssets/filters/annoyances-others.txt | 407 +- uAssets/filters/badlists.txt | 7 +- uAssets/filters/badware.txt | 819 +- uAssets/filters/filters-2020.txt | 326 +- uAssets/filters/filters-2021.txt | 300 +- uAssets/filters/filters-2022.txt | 619 +- uAssets/filters/filters-2023.txt | 634 +- uAssets/filters/filters-2024.txt | 986 +- uAssets/filters/filters-mobile.txt | 10 +- uAssets/filters/filters.txt | 1119 +- uAssets/filters/lan-block.txt | 7 + uAssets/filters/privacy.txt | 131 +- uAssets/filters/quick-fixes.txt | 292 +- uAssets/filters/resource-abuse.txt | 5 +- uAssets/filters/ubo-link-shorteners.txt | 419 +- uAssets/filters/unbreak.txt | 293 +- .../thirdparties/easylist/easylist-annoyances.txt | 194 +- uAssets/thirdparties/easylist/easylist-chat.txt | 13 + uAssets/thirdparties/easylist/easylist-cookies.txt | 1322 +- .../thirdparties/easylist/easylist-newsletters.txt | 401 +- .../easylist/easylist-notifications.txt | 96 +- uAssets/thirdparties/easylist/easylist-social.txt | 821 +- uAssets/thirdparties/easylist/easylist.txt | 18357 ++++++++++++------- uAssets/thirdparties/easylist/easyprivacy.txt | 8356 ++++++++- .../publicsuffix.org/list/effective_tld_names.dat | 273 +- .../urlhaus-filter/urlhaus-filter-online.txt | 2486 ++- 297 files changed, 36086 insertions(+), 17377 deletions(-) create mode 100644 .eslintrc.yml create mode 100644 platform/mv3/description/webstore.cy.txt create mode 100644 platform/mv3/extension/_locales/cy/messages.json create mode 100644 platform/mv3/salvage-ruleids.mjs create mode 100644 src/_locales/cy/messages.json delete mode 100644 src/_locales/ku/messages.json create mode 100644 src/js/s14e-serializer.js create mode 100644 src/js/scriptlets/scriptlet-loglevel-1.js create mode 100644 src/js/scriptlets/scriptlet-loglevel-2.js diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 0000000..c888f4c --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,26 @@ +env: + browser: true + es2022: true +extends: eslint:recommended +parserOptions: + sourceType: module +rules: + eqeqeq: + - warn + - always + indent: + - error + - 4 + - ignoredNodes: + - Program > IfStatement > BlockStatement + - Program > ExpressionStatement > CallExpression > ArrowFunctionExpression > BlockStatement + - CallExpression > MemberExpression + - ArrayExpression > Literal + no-control-regex: off + no-empty: off + sort-imports: warn + strict: warn +globals: + browser: readonly + chrome: readonly + vAPI: readonly diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ed4445a..5ce7af1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ jobs: if: startsWith(github.ref, 'refs/tags/') steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Clone uAssets diff --git a/CHANGELOG.md b/CHANGELOG.md index ef76821..c5cfa18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,78 @@ ## Fixes / changes +- [Do not block large media resources when loaded as top-level document](https://github.com/gorhill/uBlock/commit/3919a16bb8) +- [Properly manage cache storage regarding managed user filters](https://github.com/gorhill/uBlock/commit/90ab1a76ab) +- [Improve `[trusted-]set-cookie` scriptlets](https://github.com/gorhill/uBlock/commit/11a48561e0) +- [Fixed Belgian and Nepali flags for Windows Chromium users](https://github.com/gorhill/uBlock/commit/499c80bd8a) (by @DandelionSprout) +- [Mind that `tabs.sendMessage` can throw](https://github.com/gorhill/uBlock/commit/3f7374c1f1) +- [Improve `set-cookie` scriptlet](https://github.com/gorhill/uBlock/commit/9146134874) +- [Append wildcard character only when filter starts & ends with `/`](https://github.com/gorhill/uBlock/commit/1cb190e102) +- [Fix failure to create popup logger window sometimes](https://github.com/gorhill/uBlock/commit/c8762945d9) +- [Improve json-prune-related scriptlets](https://github.com/gorhill/uBlock/commit/e7a0f8c781) +- [Support maximizing editor to viewport size](https://github.com/gorhill/uBlock/commit/664dd95700) +- [Add advanced setting to force popup panel orientation](https://github.com/gorhill/uBlock/commit/0d77ccded7) +- [Add checkboxes to "My filters" pane](https://github.com/gorhill/uBlock/commit/46ea5519c1) +- [Assume UTF-8 when no encoding can be looked up](https://github.com/gorhill/uBlock/commit/63acdcbdeb) +- [Fix issue with "My filters" pane on mobile](https://github.com/gorhill/uBlock/commit/24d94e559d) +- [Support aborting "Pick" mode in element picker](https://github.com/gorhill/uBlock/commit/a557f62112) +- [Remove sections with no lists in "Filter lists" pane](https://github.com/gorhill/uBlock/commit/0f4e50db07) +- [Add "Social widgets", "Cookie notices" sections in "Filter lists" pane](https://github.com/gorhill/uBlock/commit/21a76e32a1) +- [No longer disable generic cosmetic filters by default on mobile](https://github.com/gorhill/uBlock/commit/7a768e7b1a) +- [Improve `spoof-css` scriptlet](https://github.com/gorhill/uBlock/commit/603239970d) +- [Make asset updater compatible with non-persistent background page](https://github.com/gorhill/uBlock/commit/96704f2fda) +- [Move dragbar to the top of element picker dialog](https://github.com/gorhill/uBlock/commit/953c978d59) + - [Move "Quit" button to top bar in element picker](https://github.com/gorhill/uBlock/commit/6266c4718d) +- [Add advanced setting `requestStatsDisabled`](https://github.com/gorhill/uBlock/commit/e02ea69c86) +- [First lookup matching stock lists when importing URLs](https://github.com/gorhill/uBlock/commit/2b16a10b82) +- [Reset filter lists in worker when creating filters via "Block element"](https://github.com/gorhill/uBlock/commit/b0067b79d5) +- [Remove trusted-source requirement when using `badfilter`](https://github.com/gorhill/uBlock/commit/3c299b8632) +- [Redesign cache storage](https://github.com/gorhill/uBlock/commit/086766a924) +- [Don't match network filter-derived regexes against non-network URIs](https://github.com/gorhill/uBlock/commit/2262a129ec) +- [Remove obsolete trusted directives](https://github.com/gorhill/uBlock/commit/439a059cca) +- [Support logging details of calls to `json-prune-fetch-response`](https://github.com/gorhill/uBlock/commit/e527a8f9af) +- [Escape special whitespace characters in attribute values](https://github.com/gorhill/uBlock/commit/be3e366019) + +---------- + +# 1.56.0 + +## Fixes / changes + +- [Mind that multiple `uritransform` may apply to a single request](https://github.com/gorhill/uBlock/commit/2a5a444482) +- [Fix incorrect built-in filtering expression in logger](https://github.com/gorhill/uBlock/commit/9bff0c2f94) +- [Fix improper invalidation of valid `uritransform` exception filters](https://github.com/gorhill/uBlock/commit/21ec5a277c) +- [Improve `prevent-addEventListener` scriptlet](https://github.com/gorhill/uBlock/commit/b22b3d729b) +- [Fix Chartbeat flicker control `div`'s](https://github.com/gorhill/uBlock/commit/397d6d47b9) (by @ryanbr) +- [Fix potential exfiltration of browsing history by a rogue list author through `permissions=`](https://github.com/gorhill/uBlock/commit/7b138b58c6) +- [Ignore event handler-related attributes in `set-attr` scriptlet](https://github.com/gorhill/uBlock/commit/3037ae5f04) (suggested by @distinctmondaylilac) +- [Fix potential exfiltration of browsing history by a rogue list author through `csp=`](https://github.com/gorhill/uBlock/commit/db5656f607) (reported by @distinctmondaylilac) +- [Output scriptlet logging information to the logger](https://github.com/gorhill/uBlock/commit/869a653fdf) +- [Fix decompiling of scriptlet parameters](https://github.com/gorhill/uBlock/commit/49dd68ef3d) +- [Add support for `extraMatch` in `trusted-click-element` scriptlet](https://github.com/gorhill/uBlock/commit/45e62c939f) +- [Remove minimum height constraint from "My filters" pane](https://github.com/gorhill/uBlock/commit/f624c835c2) +- [Unregister all scriptlets when disabling uBO on a specific site](https://github.com/gorhill/uBlock/commit/13dcd844a7) +- [Allow `uritransform` to process the hash part of a URL](https://github.com/gorhill/uBlock/commit/b19094339f) +- [Remember presentation state of "My rules" pane](https://github.com/gorhill/uBlock/commit/3d1b100646) +- [Fix improperly assembled `!#include` sublists](https://github.com/gorhill/uBlock/commit/0e00010b91) +- [Mark procedural filters with pseudo-elements selector as invalid](https://github.com/gorhill/uBlock/commit/757b8be9cd) +- [Prevent access to picker when "My filters" is not enabled](https://github.com/gorhill/uBlock/commit/bc641fc024) +- [Provide visual feedback when applying changes in "Filter lists" pane](https://github.com/gorhill/uBlock/commit/c4bb8a0f64) +- [Empty query parameters must still use `=`](https://github.com/gorhill/uBlock/commit/1cac61a9a4) +- [Add support to toggle no-scripting switch with keyboard shortcut](https://github.com/gorhill/uBlock/commit/936444883f) +- [Do not exceed rate-limited calls to `handlerBehaviorChanged()`](https://github.com/gorhill/uBlock/commit/63fe18a761) +- [Shield some code paths against potentially tampered global properties](https://github.com/gorhill/uBlock/commit/534d877e95) (in scriptlets) +- [Do not prevent applying changes when lists are updating](https://github.com/gorhill/uBlock/commit/f6b726136c) +- [Add `elements` vararg to `prevent-addEventListener` scriptlet](https://github.com/gorhill/uBlock/commit/060f9d68fc) +- [Do not use tab character as field separator](https://github.com/gorhill/uBlock/commit/a9eb9630cf) (in logger) +- [Prevent `:others()` from hiding `html` tag](https://github.com/gorhill/uBlock/commit/9a104bcbd2) + +---------- + +# 1.55.0 + +## Fixes / changes + +- [Discard repeating adjacent entries in the logger](https://github.com/gorhill/uBlock/commit/55e4cee6e8) - [Mind drop events in filter expression field of logger](https://github.com/gorhill/uBlock/commit/c8b7d1a526) - [Improve `xml-prune` scriptlet](https://github.com/gorhill/uBlock/commit/d7063a052f) - [Fix message entries overflowing in logger](https://github.com/gorhill/uBlock/commit/49c8310e22) diff --git a/Makefile b/Makefile index 9c03018..194a3af 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # https://stackoverflow.com/a/6273809 run_options := $(filter-out $@,$(MAKECMDGOALS)) -.PHONY: all clean test lint chromium opera firefox npm dig mv3 mv3-quick \ +.PHONY: all clean cleanassets test lint chromium opera firefox npm dig mv3 mv3-quick \ compare maxcost medcost mincost modifiers record wasm sources := $(wildcard assets/* assets/*/* dist/version src/* src/*/* src/*/*/* src/*/*/*/*) @@ -73,6 +73,8 @@ dist/build/uAssets: clean: rm -rf dist/build tmp/node_modules +cleanassets: + rm -rf dist/build/mv3-data dist/build/uAssets # Not real targets, just convenient for auto-completion at shell prompt compare: diff --git a/assets/assets.dev.json b/assets/assets.dev.json index 129cc75..94e1b8c 100644 --- a/assets/assets.dev.json +++ b/assets/assets.dev.json @@ -125,7 +125,7 @@ "https://ublockorigin.github.io/uAssetsCDN/filters/quick-fixes.min.txt", "https://ublockorigin.pages.dev/filters/quick-fixes.min.txt", "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/quick-fixes.min.txt", - "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/quick-fixes.min.txt?dev=1" + "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/quick-fixes.min.txt" ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, @@ -155,10 +155,10 @@ "group": "ads", "title": "EasyList", "tags": "ads", + "preferred": true, "contentURL": [ "https://ublockorigin.github.io/uAssets/thirdparties/easylist.txt", - "assets/thirdparties/easylist/easylist.txt", - "assets/thirdparties/easylist-downloads.adblockplus.org/easylist.txt" + "assets/thirdparties/easylist/easylist.txt" ], "cdnURLs": [ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/thirdparties/easylist.txt", @@ -206,10 +206,10 @@ "group": "privacy", "title": "EasyPrivacy", "tags": "privacy", + "preferred": true, "contentURL": [ "https://ublockorigin.github.io/uAssets/thirdparties/easyprivacy.txt", - "assets/thirdparties/easylist/easyprivacy.txt", - "assets/thirdparties/easylist-downloads.adblockplus.org/easyprivacy.txt" + "assets/thirdparties/easylist/easyprivacy.txt" ], "cdnURLs": [ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/thirdparties/easyprivacy.txt", @@ -246,21 +246,11 @@ ], "supportURL": "https://gitlab.com/malware-filter/phishing-filter#phishing-url-blocklist" }, - "adguard-social": { - "content": "filters", - "group": "annoyances", - "parent": "AdGuard – Annoyances", - "off": true, - "title": "AdGuard – Social Media", - "tags": "annoyances social", - "contentURL": "https://filters.adtidy.org/extension/ublock/filters/4.txt", - "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" - }, "adguard-cookies": { "content": "filters", "group": "annoyances", - "parent": "AdGuard – Annoyances|AdGuard/uBO – Cookie Notices", + "group2": "cookies", + "parent": "AdGuard/uBO – Cookie Notices", "off": true, "title": "AdGuard – Cookie Notices", "tags": "annoyances cookies", @@ -271,10 +261,51 @@ "ublock-cookies-adguard": { "content": "filters", "group": "annoyances", - "parent": "AdGuard – Annoyances|AdGuard/uBO – Cookie Notices", + "group2": "cookies", + "parent": "AdGuard/uBO – Cookie Notices", + "off": true, + "title": "uBlock filters – Cookie Notices", + "tags": "annoyances cookies", + "contentURL": "https://ublockorigin.github.io/uAssets/filters/annoyances-cookies.txt", + "cdnURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/annoyances-cookies.txt", + "https://ublockorigin.pages.dev/filters/annoyances-cookies.txt", + "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/annoyances-cookies.txt", + "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/annoyances-cookies.txt" + ], + "supportURL": "https://github.com/uBlockOrigin/uAssets" + }, + "fanboy-cookiemonster": { + "content": "filters", + "group": "annoyances", + "group2": "cookies", + "parent": "EasyList/uBO – Cookie Notices", + "off": true, + "title": "EasyList – Cookie Notices", + "tags": "annoyances cookies", + "preferred": true, + "contentURL": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist-cookies.txt", + "https://secure.fanboy.co.nz/fanboy-cookiemonster_ubo.txt" + ], + "cdnURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/thirdparties/easylist-cookies.txt", + "https://ublockorigin.pages.dev/thirdparties/easylist-cookies.txt", + "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/thirdparties/easylist-cookies.txt", + "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easylist-cookies.txt", + "https://secure.fanboy.co.nz/fanboy-cookiemonster_ubo.txt" + ], + "supportURL": "https://github.com/easylist/easylist#fanboy-lists" + }, + "ublock-cookies-easylist": { + "content": "filters", + "group": "annoyances", + "group2": "cookies", + "parent": "EasyList/uBO – Cookie Notices", "off": true, "title": "uBlock filters – Cookie Notices", "tags": "annoyances cookies", + "preferred": true, "contentURL": "https://ublockorigin.github.io/uAssets/filters/annoyances-cookies.txt", "cdnURLs": [ "https://ublockorigin.github.io/uAssetsCDN/filters/annoyances-cookies.txt", @@ -284,6 +315,50 @@ ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, + "adguard-social": { + "content": "filters", + "group": "annoyances", + "group2": "social", + "parent": null, + "off": true, + "title": "AdGuard – Social Widgets", + "tags": "annoyances social", + "contentURL": "https://filters.adtidy.org/extension/ublock/filters/4.txt", + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", + "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + }, + "fanboy-social": { + "content": "filters", + "group": "annoyances", + "group2": "social", + "parent": null, + "off": true, + "title": "EasyList – Social Widgets", + "tags": "annoyances social", + "preferred": true, + "contentURL": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist-social.txt", + "https://secure.fanboy.co.nz/fanboy-social_ubo.txt" + ], + "cdnURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/thirdparties/easylist-social.txt", + "https://ublockorigin.pages.dev/thirdparties/easylist-social.txt", + "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/thirdparties/easylist-social.txt", + "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easylist-social.txt", + "https://secure.fanboy.co.nz/fanboy-social_ubo.txt" + ], + "supportURL": "https://easylist.to/" + }, + "fanboy-thirdparty_social": { + "content": "filters", + "group": "annoyances", + "group2": "social", + "off": true, + "title": "Fanboy – Anti-Facebook", + "tags": "privacy", + "contentURL": "https://secure.fanboy.co.nz/fanboy-antifacebook.txt", + "supportURL": "https://github.com/ryanbr/fanboy-adblock/issues" + }, "adguard-popup-overlays": { "content": "filters", "group": "annoyances", @@ -328,15 +403,6 @@ "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" }, - "fanboy-thirdparty_social": { - "content": "filters", - "group": "annoyances", - "off": true, - "title": "Fanboy – Anti-Facebook", - "tags": "privacy", - "contentURL": "https://secure.fanboy.co.nz/fanboy-antifacebook.txt", - "supportURL": "https://github.com/ryanbr/fanboy-adblock/issues" - }, "easylist-annoyances": { "content": "filters", "group": "annoyances", @@ -344,6 +410,7 @@ "off": true, "title": "EasyList – Other Annoyances", "tags": "annoyances", + "preferred": true, "contentURL": "https://ublockorigin.github.io/uAssets/thirdparties/easylist-annoyances.txt", "cdnURLs": [ "https://ublockorigin.github.io/uAssetsCDN/thirdparties/easylist-annoyances.txt", @@ -360,6 +427,7 @@ "off": true, "title": "EasyList – Chat Widgets", "tags": "annoyances", + "preferred": true, "contentURL": "https://ublockorigin.github.io/uAssets/thirdparties/easylist-chat.txt", "cdnURLs": [ "https://ublockorigin.github.io/uAssetsCDN/thirdparties/easylist-chat.txt", @@ -369,42 +437,6 @@ ], "supportURL": "https://github.com/easylist/easylist#fanboy-lists" }, - "fanboy-cookiemonster": { - "content": "filters", - "group": "annoyances", - "parent": "EasyList – Annoyances|EasyList/uBO – Cookie Notices", - "off": true, - "title": "EasyList – Cookie Notices", - "tags": "annoyances cookies", - "contentURL": [ - "https://ublockorigin.github.io/uAssets/thirdparties/easylist-cookies.txt", - "https://secure.fanboy.co.nz/fanboy-cookiemonster_ubo.txt" - ], - "cdnURLs": [ - "https://ublockorigin.github.io/uAssetsCDN/thirdparties/easylist-cookies.txt", - "https://ublockorigin.pages.dev/thirdparties/easylist-cookies.txt", - "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/thirdparties/easylist-cookies.txt", - "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easylist-cookies.txt", - "https://secure.fanboy.co.nz/fanboy-cookiemonster_ubo.txt" - ], - "supportURL": "https://github.com/easylist/easylist#fanboy-lists" - }, - "ublock-cookies-easylist": { - "content": "filters", - "group": "annoyances", - "parent": "EasyList – Annoyances|EasyList/uBO – Cookie Notices", - "off": true, - "title": "uBlock filters – Cookie Notices", - "tags": "annoyances cookies", - "contentURL": "https://ublockorigin.github.io/uAssets/filters/annoyances-cookies.txt", - "cdnURLs": [ - "https://ublockorigin.github.io/uAssetsCDN/filters/annoyances-cookies.txt", - "https://ublockorigin.pages.dev/filters/annoyances-cookies.txt", - "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/annoyances-cookies.txt", - "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/annoyances-cookies.txt" - ], - "supportURL": "https://github.com/uBlockOrigin/uAssets" - }, "easylist-newsletters": { "content": "filters", "group": "annoyances", @@ -412,6 +444,7 @@ "off": true, "title": "EasyList – Newsletter Notices", "tags": "annoyances", + "preferred": true, "contentURL": [ "https://ublockorigin.github.io/uAssets/thirdparties/easylist-newsletters.txt" ], @@ -430,6 +463,7 @@ "off": true, "title": "EasyList – Notifications", "tags": "annoyances", + "preferred": true, "contentURL": [ "https://ublockorigin.github.io/uAssets/thirdparties/easylist-notifications.txt" ], @@ -441,26 +475,6 @@ ], "supportURL": "https://easylist.to/" }, - "fanboy-social": { - "content": "filters", - "group": "annoyances", - "parent": "EasyList – Annoyances", - "off": true, - "title": "EasyList – Social Widgets", - "tags": "annoyances social", - "contentURL": [ - "https://ublockorigin.github.io/uAssets/thirdparties/easylist-social.txt", - "https://secure.fanboy.co.nz/fanboy-social_ubo.txt" - ], - "cdnURLs": [ - "https://ublockorigin.github.io/uAssetsCDN/thirdparties/easylist-social.txt", - "https://ublockorigin.pages.dev/thirdparties/easylist-social.txt", - "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/thirdparties/easylist-social.txt", - "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easylist-social.txt", - "https://secure.fanboy.co.nz/fanboy-social_ubo.txt" - ], - "supportURL": "https://easylist.to/" - }, "ublock-annoyances": { "content": "filters", "group": "annoyances", @@ -492,6 +506,7 @@ "updateAfter": 13, "title": "Peter Lowe’s Ad and tracking server list", "tags": "ads privacy security", + "preferred": true, "contentURL": [ "https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=1&mimetype=plaintext", "assets/thirdparties/pgl.yoyo.org/as/serverlist.txt", @@ -651,8 +666,7 @@ "lang": "fa ps tg", "contentURL": [ "https://raw.githubusercontent.com/MasterKia/PersianBlocker/main/PersianBlocker.txt", - "https://cdn.statically.io/gh/MasterKia/PersianBlocker/main/PersianBlocker.txt", - "https://raw.githubusercontent.com/MasterKia/PersianBlocker/main/PersianBlocker.txt" + "https://cdn.statically.io/gh/MasterKia/PersianBlocker/main/PersianBlocker.txt" ], "cdnURLs": [ "https://cdn.jsdelivr.net/gh/MasterKia/PersianBlocker@main/PersianBlocker.txt", @@ -866,6 +880,10 @@ "tags": "ads swedish svenska", "lang": "sv", "contentURL": "https://raw.githubusercontent.com/lassekongo83/Frellwits-filter-lists/master/Frellwits-Swedish-Filter.txt", + "cdnURLs": [ + "https://raw.githubusercontent.com/lassekongo83/Frellwits-filter-lists/swefilter/swefilter.min.txt", + "https://cdn.jsdelivr.net/gh/lassekongo83/Frellwits-filter-lists@swefilter/swefilter.min.txt" + ], "supportURL": "https://github.com/lassekongo83/Frellwits-filter-lists" }, "THA-0": { diff --git a/assets/assets.json b/assets/assets.json index 7773314..50131ec 100644 --- a/assets/assets.json +++ b/assets/assets.json @@ -124,7 +124,8 @@ "cdnURLs": [ "https://ublockorigin.github.io/uAssetsCDN/filters/quick-fixes.min.txt", "https://ublockorigin.pages.dev/filters/quick-fixes.min.txt", - "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/quick-fixes.min.txt" + "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/quick-fixes.min.txt", + "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/quick-fixes.min.txt" ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, @@ -154,16 +155,15 @@ "group": "ads", "title": "EasyList", "tags": "ads", + "preferred": true, "contentURL": [ "https://ublockorigin.github.io/uAssets/thirdparties/easylist.txt", - "assets/thirdparties/easylist/easylist.txt", - "assets/thirdparties/easylist-downloads.adblockplus.org/easylist.txt" + "assets/thirdparties/easylist/easylist.txt" ], "cdnURLs": [ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/thirdparties/easylist.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easylist.txt", - "https://ublockorigin.pages.dev/thirdparties/easylist.txt", - "https://easylist.to/easylist/easylist.txt" + "https://ublockorigin.pages.dev/thirdparties/easylist.txt" ], "supportURL": "https://easylist.to/" }, @@ -206,16 +206,15 @@ "group": "privacy", "title": "EasyPrivacy", "tags": "privacy", + "preferred": true, "contentURL": [ "https://ublockorigin.github.io/uAssets/thirdparties/easyprivacy.txt", - "assets/thirdparties/easylist/easyprivacy.txt", - "assets/thirdparties/easylist-downloads.adblockplus.org/easyprivacy.txt" + "assets/thirdparties/easylist/easyprivacy.txt" ], "cdnURLs": [ "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/thirdparties/easyprivacy.txt", "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easyprivacy.txt", - "https://ublockorigin.pages.dev/thirdparties/easyprivacy.txt", - "https://easylist.to/easylist/easyprivacy.txt" + "https://ublockorigin.pages.dev/thirdparties/easyprivacy.txt" ], "supportURL": "https://easylist.to/" }, @@ -247,21 +246,11 @@ ], "supportURL": "https://gitlab.com/malware-filter/phishing-filter#phishing-url-blocklist" }, - "adguard-social": { - "content": "filters", - "group": "annoyances", - "parent": "AdGuard – Annoyances", - "off": true, - "title": "AdGuard – Social Media", - "tags": "annoyances social", - "contentURL": "https://filters.adtidy.org/extension/ublock/filters/4.txt", - "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", - "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" - }, "adguard-cookies": { "content": "filters", "group": "annoyances", - "parent": "AdGuard – Annoyances|AdGuard/uBO – Cookie Notices", + "group2": "cookies", + "parent": "AdGuard/uBO – Cookie Notices", "off": true, "title": "AdGuard – Cookie Notices", "tags": "annoyances cookies", @@ -272,10 +261,51 @@ "ublock-cookies-adguard": { "content": "filters", "group": "annoyances", - "parent": "AdGuard – Annoyances|AdGuard/uBO – Cookie Notices", + "group2": "cookies", + "parent": "AdGuard/uBO – Cookie Notices", + "off": true, + "title": "uBlock filters – Cookie Notices", + "tags": "annoyances cookies", + "contentURL": "https://ublockorigin.github.io/uAssets/filters/annoyances-cookies.txt", + "cdnURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/filters/annoyances-cookies.txt", + "https://ublockorigin.pages.dev/filters/annoyances-cookies.txt", + "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/annoyances-cookies.txt", + "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/annoyances-cookies.txt" + ], + "supportURL": "https://github.com/uBlockOrigin/uAssets" + }, + "fanboy-cookiemonster": { + "content": "filters", + "group": "annoyances", + "group2": "cookies", + "parent": "EasyList/uBO – Cookie Notices", + "off": true, + "title": "EasyList – Cookie Notices", + "tags": "annoyances cookies", + "preferred": true, + "contentURL": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist-cookies.txt", + "https://secure.fanboy.co.nz/fanboy-cookiemonster_ubo.txt" + ], + "cdnURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/thirdparties/easylist-cookies.txt", + "https://ublockorigin.pages.dev/thirdparties/easylist-cookies.txt", + "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/thirdparties/easylist-cookies.txt", + "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easylist-cookies.txt", + "https://secure.fanboy.co.nz/fanboy-cookiemonster_ubo.txt" + ], + "supportURL": "https://github.com/easylist/easylist#fanboy-lists" + }, + "ublock-cookies-easylist": { + "content": "filters", + "group": "annoyances", + "group2": "cookies", + "parent": "EasyList/uBO – Cookie Notices", "off": true, "title": "uBlock filters – Cookie Notices", "tags": "annoyances cookies", + "preferred": true, "contentURL": "https://ublockorigin.github.io/uAssets/filters/annoyances-cookies.txt", "cdnURLs": [ "https://ublockorigin.github.io/uAssetsCDN/filters/annoyances-cookies.txt", @@ -285,6 +315,50 @@ ], "supportURL": "https://github.com/uBlockOrigin/uAssets" }, + "adguard-social": { + "content": "filters", + "group": "annoyances", + "group2": "social", + "parent": null, + "off": true, + "title": "AdGuard – Social Widgets", + "tags": "annoyances social", + "contentURL": "https://filters.adtidy.org/extension/ublock/filters/4.txt", + "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", + "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" + }, + "fanboy-social": { + "content": "filters", + "group": "annoyances", + "group2": "social", + "parent": null, + "off": true, + "title": "EasyList – Social Widgets", + "tags": "annoyances social", + "preferred": true, + "contentURL": [ + "https://ublockorigin.github.io/uAssets/thirdparties/easylist-social.txt", + "https://secure.fanboy.co.nz/fanboy-social_ubo.txt" + ], + "cdnURLs": [ + "https://ublockorigin.github.io/uAssetsCDN/thirdparties/easylist-social.txt", + "https://ublockorigin.pages.dev/thirdparties/easylist-social.txt", + "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/thirdparties/easylist-social.txt", + "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easylist-social.txt", + "https://secure.fanboy.co.nz/fanboy-social_ubo.txt" + ], + "supportURL": "https://easylist.to/" + }, + "fanboy-thirdparty_social": { + "content": "filters", + "group": "annoyances", + "group2": "social", + "off": true, + "title": "Fanboy – Anti-Facebook", + "tags": "privacy", + "contentURL": "https://secure.fanboy.co.nz/fanboy-antifacebook.txt", + "supportURL": "https://github.com/ryanbr/fanboy-adblock/issues" + }, "adguard-popup-overlays": { "content": "filters", "group": "annoyances", @@ -329,15 +403,6 @@ "supportURL": "https://github.com/AdguardTeam/AdguardFilters#adguard-filters", "instructionURL": "https://kb.adguard.com/en/general/adguard-ad-filters" }, - "fanboy-thirdparty_social": { - "content": "filters", - "group": "annoyances", - "off": true, - "title": "Fanboy – Anti-Facebook", - "tags": "privacy", - "contentURL": "https://secure.fanboy.co.nz/fanboy-antifacebook.txt", - "supportURL": "https://github.com/ryanbr/fanboy-adblock/issues" - }, "easylist-annoyances": { "content": "filters", "group": "annoyances", @@ -345,6 +410,7 @@ "off": true, "title": "EasyList – Other Annoyances", "tags": "annoyances", + "preferred": true, "contentURL": "https://ublockorigin.github.io/uAssets/thirdparties/easylist-annoyances.txt", "cdnURLs": [ "https://ublockorigin.github.io/uAssetsCDN/thirdparties/easylist-annoyances.txt", @@ -361,6 +427,7 @@ "off": true, "title": "EasyList – Chat Widgets", "tags": "annoyances", + "preferred": true, "contentURL": "https://ublockorigin.github.io/uAssets/thirdparties/easylist-chat.txt", "cdnURLs": [ "https://ublockorigin.github.io/uAssetsCDN/thirdparties/easylist-chat.txt", @@ -370,42 +437,6 @@ ], "supportURL": "https://github.com/easylist/easylist#fanboy-lists" }, - "fanboy-cookiemonster": { - "content": "filters", - "group": "annoyances", - "parent": "EasyList – Annoyances|EasyList/uBO – Cookie Notices", - "off": true, - "title": "EasyList – Cookie Notices", - "tags": "annoyances cookies", - "contentURL": [ - "https://ublockorigin.github.io/uAssets/thirdparties/easylist-cookies.txt", - "https://secure.fanboy.co.nz/fanboy-cookiemonster_ubo.txt" - ], - "cdnURLs": [ - "https://ublockorigin.github.io/uAssetsCDN/thirdparties/easylist-cookies.txt", - "https://ublockorigin.pages.dev/thirdparties/easylist-cookies.txt", - "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/thirdparties/easylist-cookies.txt", - "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easylist-cookies.txt", - "https://secure.fanboy.co.nz/fanboy-cookiemonster_ubo.txt" - ], - "supportURL": "https://github.com/easylist/easylist#fanboy-lists" - }, - "ublock-cookies-easylist": { - "content": "filters", - "group": "annoyances", - "parent": "EasyList – Annoyances|EasyList/uBO – Cookie Notices", - "off": true, - "title": "uBlock filters – Cookie Notices", - "tags": "annoyances cookies", - "contentURL": "https://ublockorigin.github.io/uAssets/filters/annoyances-cookies.txt", - "cdnURLs": [ - "https://ublockorigin.github.io/uAssetsCDN/filters/annoyances-cookies.txt", - "https://ublockorigin.pages.dev/filters/annoyances-cookies.txt", - "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/filters/annoyances-cookies.txt", - "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/filters/annoyances-cookies.txt" - ], - "supportURL": "https://github.com/uBlockOrigin/uAssets" - }, "easylist-newsletters": { "content": "filters", "group": "annoyances", @@ -413,6 +444,7 @@ "off": true, "title": "EasyList – Newsletter Notices", "tags": "annoyances", + "preferred": true, "contentURL": [ "https://ublockorigin.github.io/uAssets/thirdparties/easylist-newsletters.txt" ], @@ -431,6 +463,7 @@ "off": true, "title": "EasyList – Notifications", "tags": "annoyances", + "preferred": true, "contentURL": [ "https://ublockorigin.github.io/uAssets/thirdparties/easylist-notifications.txt" ], @@ -442,26 +475,6 @@ ], "supportURL": "https://easylist.to/" }, - "fanboy-social": { - "content": "filters", - "group": "annoyances", - "parent": "EasyList – Annoyances", - "off": true, - "title": "EasyList – Social Widgets", - "tags": "annoyances social", - "contentURL": [ - "https://ublockorigin.github.io/uAssets/thirdparties/easylist-social.txt", - "https://secure.fanboy.co.nz/fanboy-social_ubo.txt" - ], - "cdnURLs": [ - "https://ublockorigin.github.io/uAssetsCDN/thirdparties/easylist-social.txt", - "https://ublockorigin.pages.dev/thirdparties/easylist-social.txt", - "https://cdn.jsdelivr.net/gh/uBlockOrigin/uAssetsCDN@main/thirdparties/easylist-social.txt", - "https://cdn.statically.io/gh/uBlockOrigin/uAssetsCDN/main/thirdparties/easylist-social.txt", - "https://secure.fanboy.co.nz/fanboy-social_ubo.txt" - ], - "supportURL": "https://easylist.to/" - }, "ublock-annoyances": { "content": "filters", "group": "annoyances", @@ -493,6 +506,7 @@ "updateAfter": 13, "title": "Peter Lowe’s Ad and tracking server list", "tags": "ads privacy security", + "preferred": true, "contentURL": [ "https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=1&mimetype=plaintext", "assets/thirdparties/pgl.yoyo.org/as/serverlist.txt", @@ -652,8 +666,7 @@ "lang": "fa ps tg", "contentURL": [ "https://raw.githubusercontent.com/MasterKia/PersianBlocker/main/PersianBlocker.txt", - "https://cdn.statically.io/gh/MasterKia/PersianBlocker/main/PersianBlocker.txt", - "https://raw.githubusercontent.com/MasterKia/PersianBlocker/main/PersianBlocker.txt" + "https://cdn.statically.io/gh/MasterKia/PersianBlocker/main/PersianBlocker.txt" ], "cdnURLs": [ "https://cdn.jsdelivr.net/gh/MasterKia/PersianBlocker@main/PersianBlocker.txt", @@ -867,6 +880,10 @@ "tags": "ads swedish svenska", "lang": "sv", "contentURL": "https://raw.githubusercontent.com/lassekongo83/Frellwits-filter-lists/master/Frellwits-Swedish-Filter.txt", + "cdnURLs": [ + "https://raw.githubusercontent.com/lassekongo83/Frellwits-filter-lists/swefilter/swefilter.min.txt", + "https://cdn.jsdelivr.net/gh/lassekongo83/Frellwits-filter-lists@swefilter/swefilter.min.txt" + ], "supportURL": "https://github.com/lassekongo83/Frellwits-filter-lists" }, "THA-0": { diff --git a/assets/resources/scriptlets.js b/assets/resources/scriptlets.js index 6e2654f..bbef272 100644 --- a/assets/resources/scriptlets.js +++ b/assets/resources/scriptlets.js @@ -22,11 +22,11 @@ web page context. */ +/* eslint no-prototype-builtins: 0 */ + // Externally added to the private namespace in which scriptlets execute. /* global scriptletGlobals */ -'use strict'; - export const builtinScriptlets = []; /******************************************************************************* @@ -42,8 +42,8 @@ builtinScriptlets.push({ fn: safeSelf, }); function safeSelf() { - if ( scriptletGlobals.has('safeSelf') ) { - return scriptletGlobals.get('safeSelf'); + if ( scriptletGlobals.safeSelf ) { + return scriptletGlobals.safeSelf; } const self = globalThis; const safe = { @@ -55,7 +55,10 @@ function safeSelf() { 'Math_max': Math.max, 'Math_min': Math.min, 'Math_random': Math.random, + 'Object': Object, 'Object_defineProperty': Object.defineProperty.bind(Object), + 'Object_fromEntries': Object.fromEntries.bind(Object), + 'Object_getOwnPropertyDescriptor': Object.getOwnPropertyDescriptor.bind(Object), 'RegExp': self.RegExp, 'RegExp_test': self.RegExp.prototype.test, 'RegExp_exec': self.RegExp.prototype.exec, @@ -70,11 +73,25 @@ function safeSelf() { 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), 'log': console.log.bind(console), + // Properties + logLevel: 0, + // Methods + makeLogPrefix(...args) { + return this.sendToLogger && `[${args.join(' \u205D ')}]` || ''; + }, uboLog(...args) { - if ( scriptletGlobals.has('canDebug') === false ) { return; } - if ( args.length === 0 ) { return; } - if ( `${args[0]}` === '' ) { return; } - this.log('[uBO]', ...args); + if ( this.sendToLogger === undefined ) { return; } + if ( args === undefined || args[0] === '' ) { return; } + return this.sendToLogger('info', ...args); + + }, + uboErr(...args) { + if ( this.sendToLogger === undefined ) { return; } + if ( args === undefined || args[0] === '' ) { return; } + return this.sendToLogger('error', ...args); + }, + escapeRegexChars(s) { + return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }, initPattern(pattern, options = {}) { if ( pattern === '' ) { @@ -96,8 +113,7 @@ function safeSelf() { } if ( options.flags !== undefined ) { return { - re: new this.RegExp(pattern.replace( - /[.*+?^${}()|[\]\\]/g, '\\$&'), + re: new this.RegExp(this.escapeRegexChars(pattern), options.flags ), expect, @@ -116,7 +132,7 @@ function safeSelf() { if ( pattern === '' ) { return /^/; } const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern); if ( match === null ) { - const reStr = pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const reStr = this.escapeRegexChars(pattern); return new RegExp(verbatim ? `^${reStr}$` : reStr, flags); } try { @@ -137,10 +153,42 @@ function safeSelf() { } return out; }, []); - return Object.fromEntries(entries); + return this.Object_fromEntries(entries); }, }; - scriptletGlobals.set('safeSelf', safe); + scriptletGlobals.safeSelf = safe; + if ( scriptletGlobals.bcSecret === undefined ) { return safe; } + // This is executed only when the logger is opened + const bc = new self.BroadcastChannel(scriptletGlobals.bcSecret); + let bcBuffer = []; + safe.logLevel = scriptletGlobals.logLevel || 1; + safe.sendToLogger = (type, ...args) => { + if ( args.length === 0 ) { return; } + const text = `[${document.location.hostname || document.location.href}]${args.join(' ')}`; + if ( bcBuffer === undefined ) { + return bc.postMessage({ what: 'messageToLogger', type, text }); + } + bcBuffer.push({ type, text }); + }; + bc.onmessage = ev => { + const msg = ev.data; + switch ( msg ) { + case 'iamready!': + if ( bcBuffer === undefined ) { break; } + bcBuffer.forEach(({ type, text }) => + bc.postMessage({ what: 'messageToLogger', type, text }) + ); + bcBuffer = undefined; + break; + case 'setScriptletLogLevelToOne': + safe.logLevel = 1; + break; + case 'setScriptletLogLevelToTwo': + safe.logLevel = 2; + break; + } + }; + bc.postMessage('areyouready?'); return safe; } @@ -176,18 +224,7 @@ builtinScriptlets.push({ }); function shouldDebug(details) { if ( details instanceof Object === false ) { return false; } - return scriptletGlobals.has('canDebug') && details.debug; -} - -/******************************************************************************/ - -builtinScriptlets.push({ - name: 'should-log.fn', - fn: shouldLog, -}); -function shouldLog(details) { - if ( details instanceof Object === false ) { return false; } - return scriptletGlobals.has('canDebug') && details.log; + return scriptletGlobals.canDebug && details.debug; } /******************************************************************************/ @@ -292,12 +329,12 @@ function generateContentFn(directive) { return Promise.resolve(randomize(len | 0)); } } - if ( directive.startsWith('war:') && scriptletGlobals.has('warOrigin') ) { + if ( directive.startsWith('war:') && scriptletGlobals.warOrigin ) { return new Promise(resolve => { - const warOrigin = scriptletGlobals.get('warOrigin'); + const warOrigin = scriptletGlobals.warOrigin; const warName = directive.slice(4); const fullpath = [ warOrigin, '/', warName ]; - const warSecret = scriptletGlobals.get('warSecret'); + const warSecret = scriptletGlobals.warSecret; if ( warSecret !== undefined ) { fullpath.push('?secret=', warSecret); } @@ -322,7 +359,6 @@ builtinScriptlets.push({ 'get-exception-token.fn', 'safe-self.fn', 'should-debug.fn', - 'should-log.fn', ], }); // Issues to mind before changing anything: @@ -335,6 +371,7 @@ function abortCurrentScriptCore( if ( typeof target !== 'string' ) { return; } if ( target === '' ) { return; } const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('abort-current-script', target, needle, context); const reNeedle = safe.patternToRegex(needle); const reContext = safe.patternToRegex(context); const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); @@ -358,7 +395,6 @@ function abortCurrentScriptCore( value = owner[prop]; desc = undefined; } - const log = shouldLog(extraArgs); const debug = shouldDebug(extraArgs); const exceptionToken = getExceptionToken(); const scriptTexts = new WeakMap(); @@ -388,20 +424,29 @@ function abortCurrentScriptCore( if ( e instanceof HTMLScriptElement === false ) { return; } if ( e === thisScript ) { return; } if ( context !== '' && reContext.test(e.src) === false ) { - if ( debug === 'nomatch' || debug === 'all' ) { debugger; } // jshint ignore: line + // eslint-disable-next-line no-debugger + if ( debug === 'nomatch' || debug === 'all' ) { debugger; } return; } - if ( log && e.src !== '' ) { safe.uboLog(`matched src: ${e.src}`); } + if ( safe.logLevel > 1 && context !== '' ) { + safe.uboLog(logPrefix, `Matched src\n${e.src}`); + } const scriptText = getScriptText(e); if ( reNeedle.test(scriptText) === false ) { - if ( debug === 'nomatch' || debug === 'all' ) { debugger; } // jshint ignore: line + // eslint-disable-next-line no-debugger + if ( debug === 'nomatch' || debug === 'all' ) { debugger; } return; } - if ( log ) { safe.uboLog(`matched script text: ${scriptText}`); } - if ( debug === 'match' || debug === 'all' ) { debugger; } // jshint ignore: line + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Matched text\n${scriptText}`); + } + // eslint-disable-next-line no-debugger + if ( debug === 'match' || debug === 'all' ) { debugger; } + safe.uboLog(logPrefix, 'Aborted'); throw new ReferenceError(exceptionToken); }; - if ( debug === 'install' ) { debugger; } // jshint ignore: line + // eslint-disable-next-line no-debugger + if ( debug === 'install' ) { debugger; } try { Object.defineProperty(owner, prop, { get: function() { @@ -420,40 +465,97 @@ function abortCurrentScriptCore( } }); } catch(ex) { - if ( log ) { safe.uboLog(ex); } + safe.uboErr(logPrefix, `Error: ${ex}`); } } /******************************************************************************/ builtinScriptlets.push({ - name: 'set-constant-core.fn', - fn: setConstantCore, + name: 'validate-constant.fn', + fn: validateConstantFn, dependencies: [ - 'run-at.fn', 'safe-self.fn', ], }); +function validateConstantFn(trusted, raw) { + const safe = safeSelf(); + const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); + let value; + if ( raw === 'undefined' ) { + value = undefined; + } else if ( raw === 'false' ) { + value = false; + } else if ( raw === 'true' ) { + value = true; + } else if ( raw === 'null' ) { + value = null; + } else if ( raw === "''" || raw === '' ) { + value = ''; + } else if ( raw === '[]' || raw === 'emptyArr' ) { + value = []; + } else if ( raw === '{}' || raw === 'emptyObj' ) { + value = {}; + } else if ( raw === 'noopFunc' ) { + value = function(){}; + } else if ( raw === 'trueFunc' ) { + value = function(){ return true; }; + } else if ( raw === 'falseFunc' ) { + value = function(){ return false; }; + } else if ( /^-?\d+$/.test(raw) ) { + value = parseInt(raw); + if ( isNaN(raw) ) { return; } + if ( Math.abs(raw) > 0x7FFF ) { return; } + } else if ( trusted ) { + if ( raw.startsWith('{') && raw.endsWith('}') ) { + try { value = safe.JSON_parse(raw).value; } catch(ex) { return; } + } + } else { + return; + } + if ( extraArgs.as !== undefined ) { + if ( extraArgs.as === 'function' ) { + return ( ) => value; + } else if ( extraArgs.as === 'callback' ) { + return ( ) => (( ) => value); + } else if ( extraArgs.as === 'resolved' ) { + return Promise.resolve(value); + } else if ( extraArgs.as === 'rejected' ) { + return Promise.reject(value); + } + } + return value; +} + +/******************************************************************************/ -function setConstantCore( +builtinScriptlets.push({ + name: 'set-constant.fn', + fn: setConstantFn, + dependencies: [ + 'run-at.fn', + 'safe-self.fn', + 'validate-constant.fn', + ], +}); +function setConstantFn( trusted = false, chain = '', - cValue = '' + rawValue = '' ) { if ( chain === '' ) { return; } const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('set-constant', chain, rawValue); const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - function setConstant(chain, cValue) { + function setConstant(chain, rawValue) { const trappedProp = (( ) => { const pos = chain.lastIndexOf('.'); if ( pos === -1 ) { return chain; } return chain.slice(pos+1); })(); - if ( trappedProp === '' ) { return; } - const thisScript = document.currentScript; const cloakFunc = fn => { safe.Object_defineProperty(fn, 'name', { value: trappedProp }); - const proxy = new Proxy(fn, { + return new Proxy(fn, { defineProperty(target, prop) { if ( prop !== 'toString' ) { return Reflect.defineProperty(...arguments); @@ -475,50 +577,12 @@ function setConstantCore( return Reflect.get(...arguments); }, }); - return proxy; }; - if ( cValue === 'undefined' ) { - cValue = undefined; - } else if ( cValue === 'false' ) { - cValue = false; - } else if ( cValue === 'true' ) { - cValue = true; - } else if ( cValue === 'null' ) { - cValue = null; - } else if ( cValue === "''" || cValue === '' ) { - cValue = ''; - } else if ( cValue === '[]' || cValue === 'emptyArr' ) { - cValue = []; - } else if ( cValue === '{}' || cValue === 'emptyObj' ) { - cValue = {}; - } else if ( cValue === 'noopFunc' ) { - cValue = cloakFunc(function(){}); - } else if ( cValue === 'trueFunc' ) { - cValue = cloakFunc(function(){ return true; }); - } else if ( cValue === 'falseFunc' ) { - cValue = cloakFunc(function(){ return false; }); - } else if ( /^-?\d+$/.test(cValue) ) { - cValue = parseInt(cValue); - if ( isNaN(cValue) ) { return; } - if ( Math.abs(cValue) > 0x7FFF ) { return; } - } else if ( trusted ) { - if ( cValue.startsWith('{') && cValue.endsWith('}') ) { - try { cValue = safe.JSON_parse(cValue).value; } catch(ex) { return; } - } - } else { - return; - } - if ( extraArgs.as !== undefined ) { - const value = cValue; - if ( extraArgs.as === 'function' ) { - cValue = ( ) => value; - } else if ( extraArgs.as === 'callback' ) { - cValue = ( ) => (( ) => value); - } else if ( extraArgs.as === 'resolved' ) { - cValue = Promise.resolve(value); - } else if ( extraArgs.as === 'rejected' ) { - cValue = Promise.reject(value); - } + if ( trappedProp === '' ) { return; } + const thisScript = document.currentScript; + let normalValue = validateConstantFn(trusted, rawValue); + if ( rawValue === 'noopFunc' || rawValue === 'trueFunc' || rawValue === 'falseFunc' ) { + normalValue = cloakFunc(normalValue); } let aborted = false; const mustAbort = function(v) { @@ -526,18 +590,21 @@ function setConstantCore( if ( aborted ) { return true; } aborted = (v !== undefined && v !== null) && - (cValue !== undefined && cValue !== null) && - (typeof v !== typeof cValue); + (normalValue !== undefined && normalValue !== null) && + (typeof v !== typeof normalValue); + if ( aborted ) { + safe.uboLog(logPrefix, `Aborted because value set to ${v}`); + } return aborted; }; // https://github.com/uBlockOrigin/uBlock-issues/issues/156 // Support multiple trappers for the same property. const trapProp = function(owner, prop, configurable, handler) { - if ( handler.init(configurable ? owner[prop] : cValue) === false ) { return; } - const odesc = Object.getOwnPropertyDescriptor(owner, prop); + if ( handler.init(configurable ? owner[prop] : normalValue) === false ) { return; } + const odesc = safe.Object_getOwnPropertyDescriptor(owner, prop); let prevGetter, prevSetter; - if ( odesc instanceof Object ) { - owner[prop] = cValue; + if ( odesc instanceof safe.Object ) { + owner[prop] = normalValue; if ( odesc.get instanceof Function ) { prevGetter = odesc.get; } @@ -552,7 +619,7 @@ function setConstantCore( if ( prevGetter !== undefined ) { prevGetter(); } - return handler.getter(); // cValue + return handler.getter(); }, set(a) { if ( prevSetter !== undefined ) { @@ -561,7 +628,9 @@ function setConstantCore( handler.setter(a); } }); + safe.uboLog(logPrefix, 'Trap installed'); } catch(ex) { + safe.uboErr(logPrefix, ex); } }; const trapChain = function(owner, chain) { @@ -575,13 +644,15 @@ function setConstantCore( return true; }, getter: function() { - return document.currentScript === thisScript - ? this.v - : cValue; + if ( document.currentScript === thisScript ) { + return this.v; + } + safe.uboLog(logPrefix, 'Property read'); + return normalValue; }, setter: function(a) { if ( mustAbort(a) === false ) { return; } - cValue = a; + normalValue = a; } }); return; @@ -589,7 +660,7 @@ function setConstantCore( const prop = chain.slice(0, pos); const v = owner[prop]; chain = chain.slice(pos + 1); - if ( v instanceof Object || typeof v === 'object' && v !== null ) { + if ( v instanceof safe.Object || typeof v === 'object' && v !== null ) { trapChain(v, chain); return; } @@ -604,7 +675,7 @@ function setConstantCore( }, setter: function(a) { this.v = a; - if ( a instanceof Object ) { + if ( a instanceof safe.Object ) { trapChain(a, chain); } } @@ -613,7 +684,7 @@ function setConstantCore( trapChain(window, chain); } runAt(( ) => { - setConstant(chain, cValue); + setConstant(chain, rawValue); }, extraArgs.runAt); } @@ -633,18 +704,18 @@ function replaceNodeTextFn( replacement = '' ) { const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('replace-node-text.fn', ...Array.from(arguments)); const reNodeName = safe.patternToRegex(nodeName, 'i', true); const rePattern = safe.patternToRegex(pattern, 'gms'); const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - const shouldLog = scriptletGlobals.has('canDebug') && extraArgs.log || 0; const reCondition = safe.patternToRegex(extraArgs.condition || '', 'ms'); const stop = (takeRecord = true) => { if ( takeRecord ) { handleMutations(observer.takeRecords()); } observer.disconnect(); - if ( shouldLog !== 0 ) { - safe.uboLog(`replace-node-text-core.fn: quitting "${pattern}" => "${replacement}"`); + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, 'Quitting'); } }; let sedCount = extraArgs.sedCount || 0; @@ -659,10 +730,10 @@ function replaceNodeTextFn( ? before.replace(rePattern, replacement) : replacement; node.textContent = after; - if ( shouldLog !== 0 ) { - safe.uboLog('replace-node-text.fn before:\n', before); - safe.uboLog('replace-node-text.fn after:\n', after); + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Text before:\n${before.trim()}`); } + safe.uboLog(logPrefix, `Text after:\n${after.trim()}`); return sedCount === 0 || (sedCount -= 1) !== 0; }; const handleMutations = mutations => { @@ -690,9 +761,7 @@ function replaceNodeTextFn( if ( handleNode(node) ) { continue; } stop(); break; } - if ( shouldLog !== 0 ) { - safe.uboLog(`replace-node-text-core.fn ${count} nodes present before installing mutation observer`); - } + safe.uboLog(logPrefix, `${count} nodes present before installing mutation observer`); } if ( extraArgs.stay ) { return; } runAt(( ) => { @@ -713,8 +782,6 @@ builtinScriptlets.push({ dependencies: [ 'matches-stack-trace.fn', 'object-find-owner.fn', - 'safe-self.fn', - 'should-log.fn', ], }); // When no "prune paths" argument is provided, the scriptlet is @@ -731,15 +798,12 @@ function objectPruneFn( extraArgs = {} ) { if ( typeof rawPrunePaths !== 'string' ) { return; } - const safe = safeSelf(); const prunePaths = rawPrunePaths !== '' ? rawPrunePaths.split(/ +/) : []; const needlePaths = prunePaths.length !== 0 && rawNeedlePaths !== '' ? rawNeedlePaths.split(/ +/) : []; - const logLevel = shouldLog({ log: rawPrunePaths === '' || extraArgs.log }); - const reLogNeedle = safe.patternToRegex(logLevel === true ? rawNeedlePaths : ''); if ( stackNeedleDetails.matchAll !== true ) { if ( matchesStackTrace(stackNeedleDetails, extraArgs.logstack) === false ) { return; @@ -754,14 +818,6 @@ function objectPruneFn( } return true; }; - objectPruneFn.logJson = (json, msg, reNeedle) => { - if ( reNeedle.test(json) === false ) { return; } - safeSelf().uboLog(`objectPrune()`, msg, location.hostname, json); - }; - } - const jsonBefore = logLevel ? safe.JSON_stringify(obj, null, 2) : ''; - if ( logLevel === true || logLevel === 'all' ) { - objectPruneFn.logJson(jsonBefore, `prune:"${rawPrunePaths}" log:"${logLevel}"`, reLogNeedle); } if ( prunePaths.length === 0 ) { return; } let outcome = 'nomatch'; @@ -772,9 +828,6 @@ function objectPruneFn( } } } - if ( logLevel === outcome ) { - objectPruneFn.logJson(jsonBefore, `prune:"${rawPrunePaths}" log:"${logLevel}"`, reLogNeedle); - } if ( outcome === 'match' ) { return obj; } } @@ -812,14 +865,33 @@ function objectFindOwnerFn( return modified; } const prop = chain.slice(0, pos); + const next = chain.slice(pos + 1); + let found = false; + if ( prop === '[-]' && Array.isArray(owner) ) { + let i = owner.length; + while ( i-- ) { + if ( objectFindOwnerFn(owner[i], next) === false ) { continue; } + owner.splice(i, 1); + found = true; + } + return found; + } + if ( prop === '{-}' && owner instanceof Object ) { + for ( const key of Object.keys(owner) ) { + if ( objectFindOwnerFn(owner[key], next) === false ) { continue; } + delete owner[key]; + found = true; + } + return found; + } if ( prop === '[]' && Array.isArray(owner) || + prop === '{}' && owner instanceof Object || prop === '*' && owner instanceof Object ) { - const next = chain.slice(pos + 1); - let found = false; for ( const key of Object.keys(owner) ) { - found = objectFindOwnerFn(owner[key], next, prune) || found; + if (objectFindOwnerFn(owner[key], next, prune) === false ) { continue; } + found = true; } return found; } @@ -827,7 +899,57 @@ function objectFindOwnerFn( owner = owner[prop]; chain = chain.slice(pos + 1); } - return true; +} + +/******************************************************************************/ + +builtinScriptlets.push({ + name: 'get-all-cookies.fn', + fn: getAllCookiesFn, +}); +function getAllCookiesFn() { + return document.cookie.split(/\s*;\s*/).map(s => { + const pos = s.indexOf('='); + if ( pos === 0 ) { return; } + if ( pos === -1 ) { return `${s.trim()}=`; } + const key = s.slice(0, pos).trim(); + const value = s.slice(pos+1).trim(); + return { key, value }; + }).filter(s => s !== undefined); +} + +/******************************************************************************/ + +builtinScriptlets.push({ + name: 'get-all-local-storage.fn', + fn: getAllLocalStorageFn, +}); +function getAllLocalStorageFn(which = 'localStorage') { + const storage = self[which]; + const out = []; + for ( let i = 0; i < storage.length; i++ ) { + const key = storage.key(i); + const value = storage.getItem(key); + return { key, value }; + } + return out; +} + +/******************************************************************************/ + +builtinScriptlets.push({ + name: 'get-cookie.fn', + fn: getCookieFn, +}); +function getCookieFn( + name = '' +) { + for ( const s of document.cookie.split(/\s*;\s*/) ) { + const pos = s.indexOf('='); + if ( pos === -1 ) { continue; } + if ( s.slice(0, pos) !== name ) { continue; } + return s.slice(pos+1).trim(); + } } /******************************************************************************/ @@ -835,6 +957,9 @@ function objectFindOwnerFn( builtinScriptlets.push({ name: 'set-cookie.fn', fn: setCookieFn, + dependencies: [ + 'get-cookie.fn', + ], }); function setCookieFn( trusted = false, @@ -844,16 +969,17 @@ function setCookieFn( path = '', options = {}, ) { - const getCookieValue = name => { - for ( const s of document.cookie.split(/\s*;\s*/) ) { - const pos = s.indexOf('='); - if ( pos === -1 ) { continue; } - if ( s.slice(0, pos) !== name ) { continue; } - return s.slice(pos+1); - } - }; + // https://datatracker.ietf.org/doc/html/rfc2616#section-2.2 + // https://github.com/uBlockOrigin/uBlock-issues/issues/2777 + if ( trusted === false && /[^!#$%&'*+\-.0-9A-Z[\]^_`a-z|~]/.test(name) ) { + name = encodeURIComponent(name); + } + // https://datatracker.ietf.org/doc/html/rfc6265#section-4.1.1 + if ( /[^!#-+\--:<-[\]-~]/.test(value) ) { + value = encodeURIComponent(value); + } - const cookieBefore = getCookieValue(name); + const cookieBefore = getCookieFn(name); if ( cookieBefore !== undefined && options.dontOverwrite ) { return; } if ( cookieBefore === value && options.reload ) { return; } @@ -881,9 +1007,12 @@ function setCookieFn( } catch(_) { } - if ( options.reload && getCookieValue(name) === value ) { + const done = getCookieFn(name) === value; + if ( done && options.reload ) { window.location.reload(); } + + return done; } /******************************************************************************/ @@ -1070,7 +1199,7 @@ function matchObjectProperties(propNeedles, ...objs) { let value = haystack[prop]; if ( value === undefined ) { continue; } if ( typeof value !== 'string' ) { - try { value = JSON.stringify(value); } + try { value = safe.JSON_stringify(value); } catch(ex) { } if ( typeof value !== 'string' ) { continue; } } @@ -1090,7 +1219,6 @@ builtinScriptlets.push({ 'object-prune.fn', 'parse-properties-to-match.fn', 'safe-self.fn', - 'should-log.fn', ], }); function jsonPruneFetchResponseFn( @@ -1098,23 +1226,22 @@ function jsonPruneFetchResponseFn( rawNeedlePaths = '' ) { const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('json-prune-fetch-response', rawPrunePaths, rawNeedlePaths); const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); - const logLevel = shouldLog({ log: rawPrunePaths === '' || extraArgs.log, }); - const log = logLevel ? ((...args) => { safe.uboLog(...args); }) : (( ) => { }); const propNeedles = parsePropertiesToMatch(extraArgs.propsToMatch, 'url'); const stackNeedle = safe.initPattern(extraArgs.stackToMatch || '', { canNegate: true }); + const logall = rawPrunePaths === ''; const applyHandler = function(target, thisArg, args) { const fetchPromise = Reflect.apply(target, thisArg, args); - if ( logLevel === true ) { - log('json-prune-fetch-response:', JSON.stringify(Array.from(args)).slice(1,-1)); - } - if ( rawPrunePaths === '' ) { return fetchPromise; } - let outcome = 'match'; + let outcome = logall ? 'nomatch' : 'match'; if ( propNeedles.size !== 0 ) { const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ]; if ( objs[0] instanceof Request ) { - try { objs[0] = safe.Request_clone.call(objs[0]); } - catch(ex) { log(ex); } + try { + objs[0] = safe.Request_clone.call(objs[0]); + } catch(ex) { + safe.uboErr(logPrefix, 'Error:', ex); + } } if ( args[1] instanceof Object ) { objs.push(args[1]); @@ -1122,19 +1249,19 @@ function jsonPruneFetchResponseFn( if ( matchObjectProperties(propNeedles, ...objs) === false ) { outcome = 'nomatch'; } - if ( outcome === logLevel || logLevel === 'all' ) { - log( - `json-prune-fetch-response (${outcome})`, - `\n\tfetchPropsToMatch: ${JSON.stringify(Array.from(propNeedles)).slice(1,-1)}`, - '\n\tprops:', ...objs, - ); - } } - if ( outcome === 'nomatch' ) { return fetchPromise; } + if ( logall === false && outcome === 'nomatch' ) { return fetchPromise; } + if ( safe.logLevel > 1 && outcome !== 'nomatch' && propNeedles.size !== 0 ) { + safe.uboLog(logPrefix, `Matched optional "propsToMatch"\n${extraArgs.propsToMatch}`); + } return fetchPromise.then(responseBefore => { const response = responseBefore.clone(); return response.json().then(objBefore => { if ( typeof objBefore !== 'object' ) { return responseBefore; } + if ( logall ) { + safe.uboLog(logPrefix, safe.JSON_stringify(objBefore, null, 2)); + return responseBefore; + } const objAfter = objectPruneFn( objBefore, rawPrunePaths, @@ -1143,6 +1270,7 @@ function jsonPruneFetchResponseFn( extraArgs ); if ( typeof objAfter !== 'object' ) { return responseBefore; } + safe.uboLog(logPrefix, 'Pruned'); const responseAfter = Response.json(objAfter, { status: responseBefore.status, statusText: responseBefore.statusText, @@ -1156,11 +1284,11 @@ function jsonPruneFetchResponseFn( }); return responseAfter; }).catch(reason => { - log('json-prune-fetch-response:', reason); + safe.uboErr(logPrefix, 'Error:', reason); return responseBefore; }); }).catch(reason => { - log('json-prune-fetch-response:', reason); + safe.uboErr(logPrefix, 'Error:', reason); return fetchPromise; }); }; @@ -1178,7 +1306,6 @@ builtinScriptlets.push({ 'match-object-properties.fn', 'parse-properties-to-match.fn', 'safe-self.fn', - 'should-log.fn', ], }); function replaceFetchResponseFn( @@ -1189,27 +1316,24 @@ function replaceFetchResponseFn( ) { if ( trusted !== true ) { return; } const safe = safeSelf(); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 4); - const logLevel = shouldLog({ - log: pattern === '' || extraArgs.log, - }); - const log = logLevel ? ((...args) => { safe.uboLog(...args); }) : (( ) => { }); + const logPrefix = safe.makeLogPrefix('replace-fetch-response', pattern, replacement, propsToMatch); if ( pattern === '*' ) { pattern = '.*'; } const rePattern = safe.patternToRegex(pattern); const propNeedles = parsePropertiesToMatch(propsToMatch, 'url'); self.fetch = new Proxy(self.fetch, { apply: function(target, thisArg, args) { - if ( logLevel === true ) { - log('replace-fetch-response:', JSON.stringify(Array.from(args)).slice(1,-1)); - } const fetchPromise = Reflect.apply(target, thisArg, args); if ( pattern === '' ) { return fetchPromise; } let outcome = 'match'; if ( propNeedles.size !== 0 ) { const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ]; if ( objs[0] instanceof Request ) { - try { objs[0] = safe.Request_clone.call(objs[0]); } - catch(ex) { log(ex); } + try { + objs[0] = safe.Request_clone.call(objs[0]); + } + catch(ex) { + safe.uboErr(logPrefix, ex); + } } if ( args[1] instanceof Object ) { objs.push(args[1]); @@ -1217,28 +1341,18 @@ function replaceFetchResponseFn( if ( matchObjectProperties(propNeedles, ...objs) === false ) { outcome = 'nomatch'; } - if ( outcome === logLevel || logLevel === 'all' ) { - log( - `replace-fetch-response (${outcome})`, - `\n\tpropsToMatch: ${JSON.stringify(Array.from(propNeedles)).slice(1,-1)}`, - '\n\tprops:', ...args, - ); - } } if ( outcome === 'nomatch' ) { return fetchPromise; } + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Matched "propsToMatch"\n${propsToMatch}`); + } return fetchPromise.then(responseBefore => { const response = responseBefore.clone(); return response.text().then(textBefore => { const textAfter = textBefore.replace(rePattern, replacement); const outcome = textAfter !== textBefore ? 'match' : 'nomatch'; - if ( outcome === logLevel || logLevel === 'all' ) { - log( - `replace-fetch-response (${outcome})`, - `\n\tpattern: ${pattern}`, - `\n\treplacement: ${replacement}`, - ); - } if ( outcome === 'nomatch' ) { return responseBefore; } + safe.uboLog(logPrefix, 'Replaced'); const responseAfter = new Response(textAfter, { status: responseBefore.status, statusText: responseBefore.statusText, @@ -1252,17 +1366,48 @@ function replaceFetchResponseFn( }); return responseAfter; }).catch(reason => { - log('replace-fetch-response:', reason); + safe.uboErr(logPrefix, reason); return responseBefore; }); }).catch(reason => { - log('replace-fetch-response:', reason); + safe.uboErr(logPrefix, reason); return fetchPromise; }); } }); } +/******************************************************************************/ + +builtinScriptlets.push({ + name: 'proxy-apply.fn', + fn: proxyApplyFn, + dependencies: [ + 'safe-self.fn', + ], +}); +function proxyApplyFn( + target = '', + handler = '' +) { + let context = globalThis; + let prop = target; + for (;;) { + const pos = prop.indexOf('.'); + if ( pos === -1 ) { break; } + context = context[prop.slice(0, pos)]; + if ( context instanceof Object === false ) { return; } + prop = prop.slice(pos+1); + } + const fn = context[prop]; + if ( typeof fn !== 'function' ) { return; } + if ( fn.prototype && fn.prototype.constructor === fn ) { + context[prop] = new Proxy(fn, { construct: handler }); + return (...args) => { return Reflect.construct(...args); }; + } + context[prop] = new Proxy(fn, { apply: handler }); + return (...args) => { return Reflect.apply(...args); }; +} /******************************************************************************* @@ -1303,6 +1448,7 @@ builtinScriptlets.push({ fn: abortOnPropertyRead, dependencies: [ 'get-exception-token.fn', + 'safe-self.fn', ], }); function abortOnPropertyRead( @@ -1310,8 +1456,11 @@ function abortOnPropertyRead( ) { if ( typeof chain !== 'string' ) { return; } if ( chain === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('abort-on-property-read', chain); const exceptionToken = getExceptionToken(); const abort = function() { + safe.uboLog(logPrefix, 'Aborted'); throw new ReferenceError(exceptionToken); }; const makeProxy = function(owner, chain) { @@ -1359,6 +1508,7 @@ builtinScriptlets.push({ fn: abortOnPropertyWrite, dependencies: [ 'get-exception-token.fn', + 'safe-self.fn', ], }); function abortOnPropertyWrite( @@ -1366,6 +1516,8 @@ function abortOnPropertyWrite( ) { if ( typeof prop !== 'string' ) { return; } if ( prop === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('abort-on-property-write', prop); const exceptionToken = getExceptionToken(); let owner = window; for (;;) { @@ -1378,6 +1530,7 @@ function abortOnPropertyWrite( delete owner[prop]; Object.defineProperty(owner, prop, { set: function() { + safe.uboLog(logPrefix, 'Aborted'); throw new ReferenceError(exceptionToken); } }); @@ -1462,7 +1615,6 @@ builtinScriptlets.push({ 'run-at.fn', 'safe-self.fn', 'should-debug.fn', - 'should-log.fn', ], }); // https://github.com/uBlockOrigin/uAssets/issues/9123#issuecomment-848255120 @@ -1472,32 +1624,68 @@ function addEventListenerDefuser( ) { const safe = safeSelf(); const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); + const logPrefix = safe.makeLogPrefix('prevent-addEventListener', type, pattern); const reType = safe.patternToRegex(type, undefined, true); const rePattern = safe.patternToRegex(pattern); - const log = shouldLog(extraArgs); const debug = shouldDebug(extraArgs); + const targetSelector = extraArgs.elements || undefined; + const elementMatches = elem => { + if ( elem && elem.matches && elem.matches(targetSelector) ) { return true; } + const elems = Array.from(document.querySelectorAll(targetSelector)); + return elems.includes(elem); + }; + const elementDetails = elem => { + if ( elem instanceof Window ) { return 'window'; } + if ( elem instanceof Document ) { return 'document'; } + if ( elem instanceof Element === false ) { return '?'; } + const parts = []; + if ( elem.id !== '' ) { parts.push(`#${CSS.escape(elem.id)}`); } + for ( let i = 0; i < elem.classList.length; i++ ) { + parts.push(`.${CSS.escape(elem.classList.item(i))}`); + } + for ( let i = 0; i < elem.attributes.length; i++ ) { + const attr = elem.attributes.item(i); + if ( attr.name === 'id' ) { continue; } + if ( attr.name === 'class' ) { continue; } + parts.push(`[${CSS.escape(attr.name)}="${attr.value}"]`); + } + return parts.join(''); + }; + const shouldPrevent = (thisArg, type, handler) => { + const matchesType = safe.RegExp_test.call(reType, type); + const matchesHandler = safe.RegExp_test.call(rePattern, handler); + const matchesEither = matchesType || matchesHandler; + const matchesBoth = matchesType && matchesHandler; + if ( debug === 1 && matchesBoth || debug === 2 && matchesEither ) { + debugger; // eslint-disable-line no-debugger + } + if ( matchesBoth && targetSelector !== undefined ) { + if ( elementMatches(thisArg) === false ) { return false; } + } + return matchesBoth; + }; const trapEddEventListeners = ( ) => { const eventListenerHandler = { apply: function(target, thisArg, args) { - let type, handler; + let t, h; try { - type = String(args[0]); - handler = args[1] instanceof Function - ? String(safe.Function_toString(args[1])) - : String(args[1]); + t = String(args[0]); + if ( typeof args[1] === 'function' ) { + h = String(safe.Function_toString(args[1])); + } else if ( typeof args[1] === 'object' && args[1] !== null ) { + if ( typeof args[1].handleEvent === 'function' ) { + h = String(safe.Function_toString(args[1].handleEvent)); + } + } else { + h = String(args[1]); + } } catch(ex) { } - const matchesType = safe.RegExp_test.call(reType, type); - const matchesHandler = safe.RegExp_test.call(rePattern, handler); - const matchesEither = matchesType || matchesHandler; - const matchesBoth = matchesType && matchesHandler; - if ( log === 1 && matchesBoth || log === 2 && matchesEither || log === 3 ) { - safe.uboLog(`addEventListener('${type}', ${handler})`); + if ( type === '' && pattern === '' ) { + safe.uboLog(logPrefix, `Called: ${t}\n${h}\n${elementDetails(thisArg)}`); + } else if ( shouldPrevent(thisArg, t, h) ) { + return safe.uboLog(logPrefix, `Prevented: ${t}\n${h}\n${elementDetails(thisArg)}`); } - if ( debug === 1 && matchesBoth || debug === 2 && matchesEither ) { - debugger; // jshint ignore:line - } - if ( matchesBoth ) { return; } return Reflect.apply(target, thisArg, args); }, get(target, prop, receiver) { @@ -1533,19 +1721,28 @@ function jsonPrune( stackNeedle = '' ) { const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('json-prune', rawPrunePaths, rawNeedlePaths, stackNeedle); const stackNeedleDetails = safe.initPattern(stackNeedle, { canNegate: true }); const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); JSON.parse = new Proxy(JSON.parse, { apply: function(target, thisArg, args) { const objBefore = Reflect.apply(target, thisArg, args); + if ( rawPrunePaths === '' ) { + safe.uboLog(logPrefix, safe.JSON_stringify(objBefore, null, 2)); + } const objAfter = objectPruneFn( objBefore, rawPrunePaths, rawNeedlePaths, stackNeedleDetails, extraArgs - ); - return objAfter || objBefore; + ); + if ( objAfter === undefined ) { return objBefore; } + safe.uboLog(logPrefix, 'Pruned'); + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `After pruning:\n${safe.JSON_stringify(objAfter, null, 2)}`); + } + return objAfter; }, }); } @@ -1579,7 +1776,6 @@ builtinScriptlets.push({ 'object-prune.fn', 'parse-properties-to-match.fn', 'safe-self.fn', - 'should-log.fn', ], }); function jsonPruneXhrResponse( @@ -1587,10 +1783,9 @@ function jsonPruneXhrResponse( rawNeedlePaths = '' ) { const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('json-prune-xhr-response', rawPrunePaths, rawNeedlePaths); const xhrInstances = new WeakMap(); const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); - const logLevel = shouldLog({ log: rawPrunePaths === '' || extraArgs.log, }); - const log = logLevel ? ((...args) => { safe.uboLog(...args); }) : (( ) => { }); const propNeedles = parsePropertiesToMatch(extraArgs.propsToMatch, 'url'); const stackNeedle = safe.initPattern(extraArgs.stackToMatch || '', { canNegate: true }); self.XMLHttpRequest = class extends self.XMLHttpRequest { @@ -1602,10 +1797,10 @@ function jsonPruneXhrResponse( outcome = 'nomatch'; } } - if ( outcome === logLevel || outcome === 'all' ) { - log(`xhr.open(${method}, ${url}, ${args.join(', ')})`); - } if ( outcome === 'match' ) { + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Matched optional "propsToMatch", "${extraArgs.propsToMatch}"`); + } xhrInstances.set(this, xhrDetails); } return super.open(method, url, ...args); @@ -1630,8 +1825,10 @@ function jsonPruneXhrResponse( if ( typeof innerResponse === 'object' ) { objBefore = innerResponse; } else if ( typeof innerResponse === 'string' ) { - try { objBefore = safe.JSON_parse(innerResponse); } - catch(ex) { } + try { + objBefore = safe.JSON_parse(innerResponse); + } catch(ex) { + } } if ( typeof objBefore !== 'object' ) { return (xhrDetails.response = innerResponse); @@ -1648,6 +1845,7 @@ function jsonPruneXhrResponse( outerResponse = typeof innerResponse === 'string' ? safe.JSON_stringify(objAfter) : objAfter; + safe.uboLog(logPrefix, 'Pruned'); } else { outerResponse = innerResponse; } @@ -1826,9 +2024,9 @@ function noEvalIf( /******************************************************************************/ builtinScriptlets.push({ - name: 'no-fetch-if.js', + name: 'prevent-fetch.js', aliases: [ - 'prevent-fetch.js', + 'no-fetch-if.js', ], fn: noFetchIf, dependencies: [ @@ -1842,6 +2040,7 @@ function noFetchIf( ) { if ( typeof propsToMatch !== 'string' ) { return; } const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('prevent-fetch', propsToMatch, responseBody); const needles = []; for ( const condition of propsToMatch.split(/\s+/) ) { if ( condition === '' ) { continue; } @@ -1856,7 +2055,6 @@ function noFetchIf( } needles.push({ key, re: safe.patternToRegex(value) }); } - const log = needles.length === 0 ? console.log.bind(console) : undefined; self.fetch = new Proxy(self.fetch, { apply: function(target, thisArg, args) { const details = args[0] instanceof self.Request @@ -1868,17 +2066,16 @@ function noFetchIf( for ( const prop in details ) { let v = details[prop]; if ( typeof v !== 'string' ) { - try { v = JSON.stringify(v); } + try { v = safe.JSON_stringify(v); } catch(ex) { } } if ( typeof v !== 'string' ) { continue; } props.set(prop, v); } - if ( log !== undefined ) { - const out = Array.from(props) - .map(a => `${a[0]}:${a[1]}`) - .join(' '); - log(`uBO: fetch(${out})`); + if ( propsToMatch === '' && responseBody === '' ) { + const out = Array.from(props).map(a => `${a[0]}:${a[1]}`); + safe.uboLog(logPrefix, `Called: ${out.join('\n')}`); + return Reflect.apply(target, thisArg, args); } proceed = needles.length === 0; for ( const { key, re } of needles ) { @@ -1902,21 +2099,23 @@ function noFetchIf( responseType = desURL.origin !== document.location.origin ? 'cors' : 'basic'; - } catch(_) { + } catch(ex) { + safe.uboErr(logPrefix, `Error: ${ex}`); } } return generateContentFn(responseBody).then(text => { + safe.uboLog(logPrefix, `Prevented with response "${text}"`); const response = new Response(text, { statusText: 'OK', headers: { 'Content-Length': text.length, } }); - Object.defineProperty(response, 'url', { + safe.Object_defineProperty(response, 'url', { value: details.url }); if ( responseType !== '' ) { - Object.defineProperty(response, 'type', { + safe.Object_defineProperty(response, 'type', { value: responseType }); } @@ -1937,6 +2136,7 @@ builtinScriptlets.push({ world: 'ISOLATED', dependencies: [ 'run-at.fn', + 'safe-self.fn', ], }); // https://www.reddit.com/r/uBlockOrigin/comments/q0frv0/while_reading_a_sports_article_i_was_redirected/hf7wo9v/ @@ -1944,9 +2144,12 @@ function preventRefresh( arg1 = '' ) { if ( typeof arg1 !== 'string' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('prevent-refresh', arg1); const defuse = ( ) => { const meta = document.querySelector('meta[http-equiv="refresh" i][content]'); if ( meta === null ) { return; } + safe.uboLog(logPrefix, `Prevented "${meta.textContent}"`); const s = arg1 === '' ? meta.getAttribute('content') : arg1; @@ -2146,13 +2349,13 @@ builtinScriptlets.push({ ], fn: setConstant, dependencies: [ - 'set-constant-core.fn' + 'set-constant.fn' ], }); function setConstant( ...args ) { - setConstantCore(false, ...args); + setConstantFn(false, ...args); } /******************************************************************************/ @@ -2175,6 +2378,7 @@ function noSetIntervalIf( ) { if ( typeof needle !== 'string' ) { return; } const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('prevent-setInterval', needle, delay); const needleNot = needle.charAt(0) === '!'; if ( needleNot ) { needle = needle.slice(1); } if ( delay === '' ) { delay = undefined; } @@ -2184,9 +2388,6 @@ function noSetIntervalIf( if ( delayNot ) { delay = delay.slice(1); } delay = parseInt(delay, 10); } - const log = needleNot === false && needle === '' && delay === undefined - ? console.log - : undefined; const reNeedle = safe.patternToRegex(needle); self.setInterval = new Proxy(self.setInterval, { apply: function(target, thisArg, args) { @@ -2194,19 +2395,20 @@ function noSetIntervalIf( ? String(safe.Function_toString(args[0])) : String(args[0]); const b = args[1]; - if ( log !== undefined ) { - log('uBO: setInterval("%s", %s)', a, b); - } else { - let defuse; - if ( needle !== '' ) { - defuse = reNeedle.test(a) !== needleNot; - } - if ( defuse !== false && delay !== undefined ) { - defuse = (b === delay || isNaN(b) && isNaN(delay) ) !== delayNot; - } - if ( defuse ) { - args[0] = function(){}; - } + if ( needle === '' && delay === undefined ) { + safe.uboLog(logPrefix, `Called:\n${a}\n${b}`); + return Reflect.apply(target, thisArg, args); + } + let defuse; + if ( needle !== '' ) { + defuse = reNeedle.test(a) !== needleNot; + } + if ( defuse !== false && delay !== undefined ) { + defuse = (b === delay || isNaN(b) && isNaN(delay) ) !== delayNot; + } + if ( defuse ) { + args[0] = function(){}; + safe.uboLog(logPrefix, `Prevented:\n${a}\n${b}`); } return Reflect.apply(target, thisArg, args); }, @@ -2239,6 +2441,7 @@ function noSetTimeoutIf( ) { if ( typeof needle !== 'string' ) { return; } const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('prevent-setTimeout', needle, delay); const needleNot = needle.charAt(0) === '!'; if ( needleNot ) { needle = needle.slice(1); } if ( delay === '' ) { delay = undefined; } @@ -2248,9 +2451,6 @@ function noSetTimeoutIf( if ( delayNot ) { delay = delay.slice(1); } delay = parseInt(delay, 10); } - const log = needleNot === false && needle === '' && delay === undefined - ? console.log - : undefined; const reNeedle = safe.patternToRegex(needle); self.setTimeout = new Proxy(self.setTimeout, { apply: function(target, thisArg, args) { @@ -2258,19 +2458,20 @@ function noSetTimeoutIf( ? String(safe.Function_toString(args[0])) : String(args[0]); const b = args[1]; - if ( log !== undefined ) { - log('uBO: setTimeout("%s", %s)', a, b); - } else { - let defuse; - if ( needle !== '' ) { - defuse = reNeedle.test(a) !== needleNot; - } - if ( defuse !== false && delay !== undefined ) { - defuse = (b === delay || isNaN(b) && isNaN(delay) ) !== delayNot; - } - if ( defuse ) { - args[0] = function(){}; - } + if ( needle === '' && delay === undefined ) { + safe.uboLog(logPrefix, `Called:\n${a}\n${b}`); + return Reflect.apply(target, thisArg, args); + } + let defuse; + if ( needle !== '' ) { + defuse = reNeedle.test(a) !== needleNot; + } + if ( defuse !== false && delay !== undefined ) { + defuse = (b === delay || isNaN(b) && isNaN(delay) ) !== delayNot; + } + if ( defuse ) { + args[0] = function(){}; + safe.uboLog(logPrefix, `Prevented:\n${a}\n${b}`); } return Reflect.apply(target, thisArg, args); }, @@ -2371,10 +2572,11 @@ function noXhrIf( directive = '' ) { if ( typeof propsToMatch !== 'string' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('prevent-xhr', propsToMatch, directive); const xhrInstances = new WeakMap(); const propNeedles = parsePropertiesToMatch(propsToMatch, 'url'); - const log = propNeedles.size === 0 ? console.log.bind(console) : undefined; - const warOrigin = scriptletGlobals.get('warOrigin'); + const warOrigin = scriptletGlobals.warOrigin; const headers = { 'date': '', 'content-type': '', @@ -2382,15 +2584,15 @@ function noXhrIf( }; self.XMLHttpRequest = class extends self.XMLHttpRequest { open(method, url, ...args) { - if ( log !== undefined ) { - log(`uBO: xhr.open(${method}, ${url}, ${args.join(', ')})`); - return super.open(method, url, ...args); - } xhrInstances.delete(this); if ( warOrigin !== undefined && url.startsWith(warOrigin) ) { return super.open(method, url, ...args); } const haystack = { method, url }; + if ( propsToMatch === '' && directive === '' ) { + safe.uboLog(logPrefix, `Called: ${safe.JSON_stringify(haystack, null, 2)}`); + return super.open(method, url, ...args); + } if ( matchObjectProperties(propNeedles, haystack) ) { xhrInstances.set(this, haystack); } @@ -2468,6 +2670,7 @@ function noXhrIf( details.xhr.dispatchEvent(new Event('readystatechange')); details.xhr.dispatchEvent(new Event('load')); details.xhr.dispatchEvent(new Event('loadend')); + safe.uboLog(logPrefix, `Prevented with response:\n${details.xhr.response}`); }); } getResponseHeader(headerName) { @@ -2507,7 +2710,6 @@ builtinScriptlets.push({ fn: noWindowOpenIf, dependencies: [ 'safe-self.fn', - 'should-log.fn', ], }); function noWindowOpenIf( @@ -2516,6 +2718,7 @@ function noWindowOpenIf( decoy = '' ) { const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('no-window-open-if', pattern, delay, decoy); const targetMatchResult = pattern.startsWith('!') === false; if ( targetMatchResult === false ) { pattern = pattern.slice(1); @@ -2525,8 +2728,6 @@ function noWindowOpenIf( if ( isNaN(autoRemoveAfter) ) { autoRemoveAfter = -1; } - const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - const logLevel = shouldLog(extraArgs); const createDecoy = function(tag, urlProp, url) { const decoyElem = document.createElement(tag); decoyElem[urlProp] = url; @@ -2541,12 +2742,13 @@ function noWindowOpenIf( window.open = new Proxy(window.open, { apply: function(target, thisArg, args) { const haystack = args.join(' '); - if ( logLevel ) { - safe.uboLog('window.open:', haystack); - } if ( rePattern.test(haystack) !== targetMatchResult ) { + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Allowed (${args.join(', ')})`); + } return Reflect.apply(target, thisArg, args); } + safe.uboLog(logPrefix, `Prevented (${args.join(', ')})`); if ( autoRemoveAfter < 0 ) { return null; } const decoyElem = decoy === 'obj' ? createDecoy('object', 'data', ...args) @@ -2568,14 +2770,14 @@ function noWindowOpenIf( }, }); } - if ( logLevel ) { + if ( safe.logLevel !== 0 ) { popup = new Proxy(popup, { get: function(target, prop) { - safe.uboLog('window.open / get', prop, '===', target[prop]); + safe.uboLog(logPrefix, 'window.open / get', prop, '===', target[prop]); return Reflect.get(...arguments); }, set: function(target, prop, value) { - safe.uboLog('window.open / set', prop, '=', value); + safe.uboLog(logPrefix, 'window.open / set', prop, '=', value); return Reflect.set(...arguments); }, }); @@ -2757,31 +2959,6 @@ function noWebrtc() { /******************************************************************************/ -builtinScriptlets.push({ - name: 'golem.de.js', - fn: golemDe, -}); -// https://github.com/uBlockOrigin/uAssets/issues/88 -function golemDe() { - const rael = window.addEventListener; - window.addEventListener = function(a, b) { - rael(...arguments); - let haystack; - try { - haystack = b.toString(); - } catch(ex) { - } - if ( - typeof haystack === 'string' && - /^\s*function\s*\(\)\s*\{\s*window\.clearTimeout\(r\)\s*\}\s*$/.test(haystack) - ) { - b(); - } - }.bind(window); -} - -/******************************************************************************/ - builtinScriptlets.push({ name: 'disable-newtab-links.js', fn: disableNewtabLinks, @@ -2884,7 +3061,6 @@ builtinScriptlets.push({ fn: xmlPrune, dependencies: [ 'safe-self.fn', - 'should-log.fn', ], }); function xmlPrune( @@ -2895,9 +3071,9 @@ function xmlPrune( if ( typeof selector !== 'string' ) { return; } if ( selector === '' ) { return; } const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('xml-prune', selector, selectorCheck, urlPattern); const reUrl = safe.patternToRegex(urlPattern); const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - const log = shouldLog(extraArgs) ? ((...args) => { safe.uboLog(...args); }) : (( ) => { }); const queryAll = (xmlDoc, selector) => { const isXpath = /^xpath\(.+\)$/.test(selector); if ( isXpath === false ) { @@ -2924,21 +3100,21 @@ function xmlPrune( } if ( extraArgs.logdoc ) { const serializer = new XMLSerializer(); - log(`xmlPrune: document is\n\t${serializer.serializeToString(xmlDoc)}`); + safe.uboLog(logPrefix, `Document is\n\t${serializer.serializeToString(xmlDoc)}`); } const items = queryAll(xmlDoc, selector); if ( items.length === 0 ) { return xmlDoc; } - log(`xmlPrune: removing ${items.length} items`); + safe.uboLog(logPrefix, `Removing ${items.length} items`); for ( const item of items ) { if ( item.nodeType === 1 ) { item.remove(); } else if ( item.nodeType === 2 ) { item.ownerElement.removeAttribute(item.nodeName); } - log(`xmlPrune: ${item.constructor.name}.${item.nodeName} removed`); + safe.uboLog(logPrefix, `${item.constructor.name}.${item.nodeName} removed`); } } catch(ex) { - log(ex); + safe.uboErr(logPrefix, `Error: ${ex}`); } return xmlDoc; }; @@ -3030,7 +3206,6 @@ builtinScriptlets.push({ fn: m3uPrune, dependencies: [ 'safe-self.fn', - 'should-log.fn', ], }); // https://en.wikipedia.org/wiki/M3U @@ -3040,9 +3215,8 @@ function m3uPrune( ) { if ( typeof m3uPattern !== 'string' ) { return; } const safe = safeSelf(); - const options = safe.getExtraArgs(Array.from(arguments), 2); - const logLevel = shouldLog(options); - const uboLog = logLevel ? ((...args) => safe.uboLog(...args)) : (( ) => { }); + const logPrefix = safe.makeLogPrefix('m3u-prune', m3uPattern, urlPattern); + const toLog = []; const regexFromArg = arg => { if ( arg === '' ) { return /^/; } const match = /^\/(.+)\/([gms]*)$/.exec(arg); @@ -3061,22 +3235,22 @@ function m3uPrune( if ( lines[i].startsWith('#EXT-X-CUE:TYPE="SpliceOut"') === false ) { return false; } - uboLog('m3u-prune: discarding', `\n\t${lines[i]}`); + toLog.push(`\t${lines[i]}`); lines[i] = undefined; i += 1; if ( lines[i].startsWith('#EXT-X-ASSET:CAID') ) { - uboLog(`\t${lines[i]}`); + toLog.push(`\t${lines[i]}`); lines[i] = undefined; i += 1; } if ( lines[i].startsWith('#EXT-X-SCTE35:') ) { - uboLog(`\t${lines[i]}`); + toLog.push(`\t${lines[i]}`); lines[i] = undefined; i += 1; } if ( lines[i].startsWith('#EXT-X-CUE-IN') ) { - uboLog(`\t${lines[i]}`); + toLog.push(`\t${lines[i]}`); lines[i] = undefined; i += 1; } if ( lines[i].startsWith('#EXT-X-SCTE35:') ) { - uboLog(`\t${lines[i]}`); + toLog.push(`\t${lines[i]}`); lines[i] = undefined; i += 1; } return true; @@ -3084,10 +3258,10 @@ function m3uPrune( const pruneInfBlock = (lines, i) => { if ( lines[i].startsWith('#EXTINF') === false ) { return false; } if ( reM3u.test(lines[i+1]) === false ) { return false; } - uboLog('m3u-prune: discarding', `\n\t${lines[i]}, \n\t${lines[i+1]}`); + toLog.push('Discarding', `\t${lines[i]}, \t${lines[i+1]}`); lines[i] = lines[i+1] = undefined; i += 2; if ( lines[i].startsWith('#EXT-X-DISCONTINUITY') ) { - uboLog(`\t${lines[i]}`); + toLog.push(`\t${lines[i]}`); lines[i] = undefined; i += 1; } return true; @@ -3124,9 +3298,7 @@ function m3uPrune( } text = before.trim() + '\n' + after.trim(); reM3u.lastIndex = before.length + 1; - uboLog('m3u-prune: discarding\n', - discard.split(/\n+/).map(s => `\t${s}`).join('\n') - ); + toLog.push('Discarding', ...discard.split(/\n+/).map(s => `\t${s}`)); if ( reM3u.global === false ) { break; } } return text; @@ -3151,13 +3323,18 @@ function m3uPrune( return Reflect.apply(target, thisArg, args); } return realFetch(...args).then(realResponse => - realResponse.text().then(text => - new Response(pruner(text), { + realResponse.text().then(text => { + const response = new Response(pruner(text), { status: realResponse.status, statusText: realResponse.statusText, headers: realResponse.headers, - }) - ) + }); + if ( toLog.length !== 0 ) { + toLog.unshift(logPrefix); + safe.uboLog(toLog.join('\n')); + } + return response; + }) ); } }); @@ -3175,6 +3352,10 @@ function m3uPrune( if ( textout === textin ) { return; } Object.defineProperty(thisArg, 'response', { value: textout }); Object.defineProperty(thisArg, 'responseText', { value: textout }); + if ( toLog.length !== 0 ) { + toLog.unshift(logPrefix); + safe.uboLog(toLog.join('\n')); + } }); return Reflect.apply(target, thisArg, args); } @@ -3220,6 +3401,7 @@ builtinScriptlets.push({ world: 'ISOLATED', dependencies: [ 'run-at.fn', + 'safe-self.fn', ], }); function hrefSanitizer( @@ -3228,6 +3410,8 @@ function hrefSanitizer( ) { if ( typeof selector !== 'string' ) { return; } if ( selector === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('href-sanitizer', selector, source); if ( source === '' ) { source = 'text'; } const sanitizeCopycats = (href, text) => { let elems = []; @@ -3239,6 +3423,7 @@ function hrefSanitizer( for ( const elem of elems ) { elem.setAttribute('href', text); } + return elems.length; }; const validateURL = text => { if ( text === '' ) { return ''; } @@ -3266,7 +3451,7 @@ function hrefSanitizer( return elem.textContent .replace(/^[^\x21-\x7e]+/, '') // remove leading invalid characters .replace(/[^\x21-\x7e]+$/, '') // remove trailing invalid characters - ; + ; } return ''; }; @@ -3287,7 +3472,8 @@ function hrefSanitizer( if ( hrefAfter === '' ) { continue; } if ( hrefAfter === href ) { continue; } elem.setAttribute('href', hrefAfter); - sanitizeCopycats(href, hrefAfter); + const count = sanitizeCopycats(href, hrefAfter); + safe.uboLog(logPrefix, `Sanitized ${count+1} links to\n${hrefAfter}`); } return true; }; @@ -3305,7 +3491,7 @@ function hrefSanitizer( if ( shouldSanitize ) { break; } } if ( shouldSanitize === false ) { return; } - timer = self.requestAnimationFrame(( ) => { + timer = self.requestIdleCallback(( ) => { timer = undefined; sanitize(); }); @@ -3402,21 +3588,28 @@ function spoofCSS( propToValueMap.set(toCamelCase(args[i+0]), args[i+1]); } const safe = safeSelf(); - const canDebug = scriptletGlobals.has('canDebug'); + const logPrefix = safe.makeLogPrefix('spoof-css', selector, ...args); + const canDebug = scriptletGlobals.canDebug; const shouldDebug = canDebug && propToValueMap.get('debug') || 0; - const shouldLog = canDebug && propToValueMap.has('log') || 0; + const instanceProperties = [ 'cssText', 'length', 'parentRule' ]; const spoofStyle = (prop, real) => { const normalProp = toCamelCase(prop); const shouldSpoof = propToValueMap.has(normalProp); const value = shouldSpoof ? propToValueMap.get(normalProp) : real; - if ( shouldLog === 2 || shouldSpoof && shouldLog === 1 ) { - safe.uboLog(prop, value); + if ( shouldSpoof ) { + safe.uboLog(logPrefix, `Spoofing ${prop} to ${value}`); } return value; }; + const cloackFunc = (fn, thisArg, name) => { + const trap = fn.bind(thisArg); + Object.defineProperty(trap, 'name', { value: name }); + return trap; + }; self.getComputedStyle = new Proxy(self.getComputedStyle, { apply: function(target, thisArg, args) { - if ( shouldDebug !== 0 ) { debugger; } // jshint ignore: line + // eslint-disable-next-line no-debugger + if ( shouldDebug !== 0 ) { debugger; } const style = Reflect.apply(target, thisArg, args); const targetElements = new WeakSet(document.querySelectorAll(selector)); if ( targetElements.has(args[0]) === false ) { return style; } @@ -3424,11 +3617,14 @@ function spoofCSS( get(target, prop, receiver) { if ( typeof target[prop] === 'function' ) { if ( prop === 'getPropertyValue' ) { - return (function(prop) { + return cloackFunc(function(prop) { return spoofStyle(prop, target[prop]); - }).bind(target); + }, target, 'getPropertyValue'); } - return target[prop].bind(target); + return cloackFunc(target[prop], target, prop); + } + if ( instanceProperties.includes(prop) ) { + return Reflect.get(target, prop); } return spoofStyle(prop, Reflect.get(target, prop, receiver)); }, @@ -3455,7 +3651,8 @@ function spoofCSS( }); Element.prototype.getBoundingClientRect = new Proxy(Element.prototype.getBoundingClientRect, { apply: function(target, thisArg, args) { - if ( shouldDebug !== 0 ) { debugger; } // jshint ignore: line + // eslint-disable-next-line no-debugger + if ( shouldDebug !== 0 ) { debugger; } const rect = Reflect.apply(target, thisArg, args); const targetElements = new WeakSet(document.querySelectorAll(selector)); if ( targetElements.has(thisArg) === false ) { return rect; } @@ -3524,7 +3721,8 @@ function setCookie( path = '' ) { if ( name === '' ) { return; } - name = encodeURIComponent(name); + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('set-cookie', name, value, path); const validValues = [ 'accept', 'reject', @@ -3545,17 +3743,21 @@ function setCookie( if ( validValues.includes(unquoted) === false ) { if ( /^\d+$/.test(unquoted) === false ) { return; } const n = parseInt(value, 10); - if ( n > 15 ) { return; } + if ( n > 32767 ) { return; } } - setCookieFn( + const done = setCookieFn( false, name, value, '', path, - safeSelf().getExtraArgs(Array.from(arguments), 3) + safe.getExtraArgs(Array.from(arguments), 3) ); + + if ( done ) { + safe.uboLog(logPrefix, 'Done'); + } } // For compatibility with AdGuard @@ -3641,6 +3843,7 @@ builtinScriptlets.push({ world: 'ISOLATED', dependencies: [ 'run-at.fn', + 'safe-self.fn', ], }); function setAttr( @@ -3648,9 +3851,11 @@ function setAttr( attr = '', value = '' ) { - if ( typeof selector !== 'string' ) { return; } if ( selector === '' ) { return; } + if ( attr === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('set-attr', attr, value); const validValues = [ '', 'false', 'true' ]; let copyFrom = ''; @@ -3685,7 +3890,11 @@ function setAttr( const before = elem.getAttribute(attr); const after = extractValue(elem); if ( after === before ) { continue; } + if ( after !== '' && /^on/i.test(attr) ) { + if ( attr.toLowerCase() in elem ) { continue; } + } elem.setAttribute(attr, after); + safe.uboLog(logPrefix, `${attr}="${after}"`); } return true; }; @@ -3806,6 +4015,58 @@ function multiup() { document.addEventListener('click', handler, { capture: true }); } +/******************************************************************************/ + +builtinScriptlets.push({ + name: 'remove-cache-storage-item.js', + fn: removeCacheStorageItem, + world: 'ISOLATED', + dependencies: [ + 'safe-self.fn', + ], +}); +function removeCacheStorageItem( + cacheNamePattern = '', + requestPattern = '' +) { + if ( cacheNamePattern === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('remove-cache-storage-item', cacheNamePattern, requestPattern); + const cacheStorage = self.caches; + if ( cacheStorage instanceof Object === false ) { return; } + const reCache = safe.patternToRegex(cacheNamePattern, undefined, true); + const reRequest = safe.patternToRegex(requestPattern, undefined, true); + cacheStorage.keys().then(cacheNames => { + for ( const cacheName of cacheNames ) { + if ( reCache.test(cacheName) === false ) { continue; } + if ( requestPattern === '' ) { + cacheStorage.delete(cacheName).then(result => { + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Deleting ${cacheName}`); + } + if ( result !== true ) { return; } + safe.uboLog(logPrefix, `Deleted ${cacheName}: ${result}`); + }); + continue; + } + cacheStorage.open(cacheName).then(cache => { + cache.keys().then(requests => { + for ( const request of requests ) { + if ( reRequest.test(request.url) === false ) { continue; } + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Deleting ${cacheName}/${request.url}`); + } + cache.delete(request).then(result => { + if ( result !== true ) { return; } + safe.uboLog(logPrefix, `Deleted ${cacheName}/${request.url}: ${result}`); + }); + } + }); + }); + } + }); +} + /******************************************************************************* * @@ -3883,13 +4144,13 @@ builtinScriptlets.push({ ], fn: trustedSetConstant, dependencies: [ - 'set-constant-core.fn' + 'set-constant.fn' ], }); function trustedSetConstant( ...args ) { - setConstantCore(true, ...args); + setConstantFn(true, ...args); } /******************************************************************************* @@ -3921,6 +4182,8 @@ function trustedSetCookie( ) { if ( name === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('set-cookie', name, value, path); const time = new Date(); if ( value === '$now$' ) { @@ -3942,7 +4205,7 @@ function trustedSetCookie( expires = time.toUTCString(); } - setCookieFn( + const done = setCookieFn( true, name, value, @@ -3950,6 +4213,10 @@ function trustedSetCookie( path, safeSelf().getExtraArgs(Array.from(arguments), 4) ); + + if ( done ) { + safe.uboLog(logPrefix, 'Done'); + } } // For compatibility with AdGuard @@ -4018,6 +4285,9 @@ function trustedSetSessionStorageItem(key = '', value = '') { builtinScriptlets.push({ name: 'trusted-replace-fetch-response.js', requiresTrust: true, + aliases: [ + 'trusted-rpfr.js', + ], fn: trustedReplaceFetchResponse, dependencies: [ 'replace-fetch-response.fn', @@ -4037,7 +4307,6 @@ builtinScriptlets.push({ 'match-object-properties.fn', 'parse-properties-to-match.fn', 'safe-self.fn', - 'should-log.fn', ], }); function trustedReplaceXhrResponse( @@ -4046,12 +4315,8 @@ function trustedReplaceXhrResponse( propsToMatch = '' ) { const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('trusted-replace-xhr-response', pattern, replacement, propsToMatch); const xhrInstances = new WeakMap(); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - const logLevel = shouldLog({ - log: pattern === '' && 'all' || extraArgs.log, - }); - const log = logLevel ? ((...args) => { safe.uboLog(...args); }) : (( ) => { }); if ( pattern === '*' ) { pattern = '.*'; } const rePattern = safe.patternToRegex(pattern); const propNeedles = parsePropertiesToMatch(propsToMatch, 'url'); @@ -4065,10 +4330,10 @@ function trustedReplaceXhrResponse( outcome = 'nomatch'; } } - if ( outcome === logLevel || outcome === 'all' ) { - log(`xhr.open(${method}, ${url}, ${args.join(', ')})`); - } if ( outcome === 'match' ) { + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, `Matched "propsToMatch"`); + } xhrInstances.set(outerXhr, xhrDetails); } return super.open(method, url, ...args); @@ -4094,13 +4359,8 @@ function trustedReplaceXhrResponse( } const textBefore = innerResponse; const textAfter = textBefore.replace(rePattern, replacement); - const outcome = textAfter !== textBefore ? 'match' : 'nomatch'; - if ( outcome === logLevel || logLevel === 'all' ) { - log( - `trusted-replace-xhr-response (${outcome})`, - `\n\tpattern: ${pattern}`, - `\n\treplacement: ${replacement}`, - ); + if ( textAfter !== textBefore ) { + safe.uboLog(logPrefix, 'Match'); } return (xhrDetails.response = textAfter); } @@ -4129,22 +4389,63 @@ builtinScriptlets.push({ fn: trustedClickElement, world: 'ISOLATED', dependencies: [ + 'get-all-cookies.fn', + 'get-all-local-storage.fn', 'run-at-html-element.fn', 'safe-self.fn', ], }); function trustedClickElement( selectors = '', - extraMatch = '', // not yet supported + extraMatch = '', delay = '' ) { - if ( extraMatch !== '' ) { return; } - const safe = safeSelf(); - const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - const uboLog = extraArgs.log !== undefined - ? ((...args) => { safe.uboLog(...args); }) - : (( ) => { }); + const logPrefix = safe.makeLogPrefix('trusted-click-element', selectors, extraMatch, delay); + + if ( extraMatch !== '' ) { + const assertions = extraMatch.split(',').map(s => { + const pos1 = s.indexOf(':'); + const s1 = pos1 !== -1 ? s.slice(0, pos1) : s; + const not = s1.startsWith('!'); + const type = not ? s1.slice(1) : s1; + const s2 = pos1 !== -1 ? s.slice(pos1+1).trim() : ''; + if ( s2 === '' ) { return; } + const out = { not, type }; + const match = /^\/(.+)\/(i?)$/.exec(s2); + if ( match !== null ) { + out.re = new RegExp(match[1], match[2] || undefined); + return out; + } + const pos2 = s2.indexOf('='); + const key = pos2 !== -1 ? s2.slice(0, pos2).trim() : s2; + const value = pos2 !== -1 ? s2.slice(pos2+1).trim() : ''; + out.re = new RegExp(`^${this.escapeRegexChars(key)}=${this.escapeRegexChars(value)}`); + return out; + }).filter(details => details !== undefined); + const allCookies = assertions.some(o => o.type === 'cookie') + ? getAllCookiesFn() + : []; + const allStorageItems = assertions.some(o => o.type === 'localStorage') + ? getAllLocalStorageFn() + : []; + const hasNeedle = (haystack, needle) => { + for ( const { key, value } of haystack ) { + if ( needle.test(`${key}=${value}`) ) { return true; } + } + return false; + }; + for ( const { not, type, re } of assertions ) { + switch ( type ) { + case 'cookie': + if ( hasNeedle(allCookies, re) === not ) { return; } + break; + case 'localStorage': + if ( hasNeedle(allStorageItems, re) === not ) { return; } + break; + } + } + } const querySelectorEx = (selector, context = document) => { const pos = selector.indexOf(' >>> '); @@ -4181,12 +4482,12 @@ function trustedClickElement( const next = notFound => { if ( selectorList.length === 0 ) { - uboLog(`trusted-click-element: Completed`); + safe.uboLog(logPrefix, 'Completed'); return terminate(); } const tnow = Date.now(); if ( tnow >= tbye ) { - uboLog(`trusted-click-element: Timed out`); + safe.uboLog(logPrefix, 'Timed out'); return terminate(); } if ( notFound ) { observe(); } @@ -4195,7 +4496,7 @@ function trustedClickElement( next.timer = undefined; process(); }, delay); - uboLog(`trusted-click-element: Waiting for ${selectorList[0]}...`); + safe.uboLog(logPrefix, `Waiting for ${selectorList[0]}...`); }; next.stop = ( ) => { if ( next.timer === undefined ) { return; } @@ -4239,7 +4540,7 @@ function trustedClickElement( selectorList.unshift(selector); return next(true); } - uboLog(`trusted-click-element: Clicked ${selector}`); + safe.uboLog(logPrefix, `Clicked ${selector}`); elem.click(); tnext += clickDelay; next(); @@ -4336,40 +4637,67 @@ builtinScriptlets.push({ fn: trustedPruneOutboundObject, dependencies: [ 'object-prune.fn', + 'proxy-apply.fn', 'safe-self.fn', ], }); function trustedPruneOutboundObject( - entryPoint = '', + propChain = '', rawPrunePaths = '', rawNeedlePaths = '' ) { - if ( entryPoint === '' ) { return; } - let context = globalThis; - let prop = entryPoint; - for (;;) { - const pos = prop.indexOf('.'); - if ( pos === -1 ) { break; } - context = context[prop.slice(0, pos)]; - if ( context instanceof Object === false ) { return; } - prop = prop.slice(pos+1); - } - if ( typeof context[prop] !== 'function' ) { return; } + if ( propChain === '' ) { return; } const safe = safeSelf(); const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); - context[prop] = new Proxy(context[prop], { - apply: function(target, thisArg, args) { - const objBefore = Reflect.apply(target, thisArg, args); - if ( objBefore instanceof Object === false ) { return objBefore; } - const objAfter = objectPruneFn( - objBefore, - rawPrunePaths, - rawNeedlePaths, - { matchAll: true }, - extraArgs - ); - return objAfter || objBefore; - }, + const reflector = proxyApplyFn(propChain, function(...args) { + const objBefore = reflector(...args); + if ( objBefore instanceof Object === false ) { return objBefore; } + const objAfter = objectPruneFn( + objBefore, + rawPrunePaths, + rawNeedlePaths, + { matchAll: true }, + extraArgs + ); + return objAfter || objBefore; + }); +} + +/******************************************************************************/ + +builtinScriptlets.push({ + name: 'trusted-replace-argument.js', + requiresTrust: true, + fn: trustedReplaceArgument, + dependencies: [ + 'proxy-apply.fn', + 'safe-self.fn', + 'validate-constant.fn', + ], +}); +function trustedReplaceArgument( + propChain = '', + argpos = '', + argraw = '' +) { + if ( propChain === '' ) { return; } + if ( argpos === '' ) { return; } + if ( argraw === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('trusted-replace-argument', propChain, argpos, argraw); + const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); + const normalValue = validateConstantFn(true, argraw); + const reCondition = extraArgs.condition + ? safe.patternToRegex(extraArgs.condition) + : /^/; + const reflector = proxyApplyFn(propChain, function(...args) { + const arglist = args[args.length-1]; + if ( Array.isArray(arglist) === false ) { return reflector(...args); } + const argBefore = arglist[argpos]; + if ( reCondition.test(argBefore) === false ) { return reflector(...args); } + arglist[argpos] = normalValue; + safe.uboLog(logPrefix, `Replaced argument:\nBefore: ${JSON.stringify(argBefore)}\nAfter: ${normalValue}`); + return reflector(...args); }); } diff --git a/dist/chromium/publish-beta.py b/dist/chromium/publish-beta.py index 5a6e19f..a731e9b 100755 --- a/dist/chromium/publish-beta.py +++ b/dist/chromium/publish-beta.py @@ -43,9 +43,9 @@ github_owner = 'gorhill' github_repo = 'uBlock' # Load/save auth secrets -# The build directory is excluded from git +# The tmp directory is excluded from git ubo_secrets = dict() -ubo_secrets_filename = os.path.join(projdir, 'dist', 'build', 'ubo_secrets') +ubo_secrets_filename = os.path.join(projdir, 'tmp', 'ubo_secrets') if os.path.isfile(ubo_secrets_filename): with open(ubo_secrets_filename) as f: ubo_secrets = json.load(f) diff --git a/dist/firefox/publish-signed-beta.py b/dist/firefox/publish-signed-beta.py index 2e56d12..ed542ef 100755 --- a/dist/firefox/publish-signed-beta.py +++ b/dist/firefox/publish-signed-beta.py @@ -69,9 +69,9 @@ github_owner = 'gorhill' github_repo = 'uBlock' # Load/save auth secrets -# The build directory is excluded from git +# The tmp directory is excluded from git ubo_secrets = dict() -ubo_secrets_filename = os.path.join(projdir, 'dist', 'build', 'ubo_secrets') +ubo_secrets_filename = os.path.join(projdir, 'tmp', 'ubo_secrets') if os.path.isfile(ubo_secrets_filename): with open(ubo_secrets_filename) as f: ubo_secrets = json.load(f) diff --git a/dist/firefox/updates.json b/dist/firefox/updates.json index 880063f..0eab531 100644 --- a/dist/firefox/updates.json +++ b/dist/firefox/updates.json @@ -3,9 +3,9 @@ "uBlock0@raymondhill.net": { "updates": [ { - "version": "1.54.1.102", + "version": "1.56.1.105", "browser_specific_settings": { "gecko": { "strict_min_version": "78.0" } }, - "update_link": "https://github.com/gorhill/uBlock/releases/download/1.54.1rc2/uBlock0_1.54.1rc2.firefox.signed.xpi" + "update_link": "https://github.com/gorhill/uBlock/releases/download/1.56.1rc5/uBlock0_1.56.1rc5.firefox.signed.xpi" } ] } diff --git a/dist/mv3/firefox/publish-signed-beta.py b/dist/mv3/firefox/publish-signed-beta.py index 0c5f8cd..f298cc8 100755 --- a/dist/mv3/firefox/publish-signed-beta.py +++ b/dist/mv3/firefox/publish-signed-beta.py @@ -64,9 +64,9 @@ github_owner = 'gorhill' github_repo = 'uBlock' # Load/save auth secrets -# The build directory is excluded from git +# The tmp directory is excluded from git ubo_secrets = dict() -ubo_secrets_filename = os.path.join(projdir, 'dist', 'build', 'ubo_secrets') +ubo_secrets_filename = os.path.join(projdir, 'tmp', 'ubo_secrets') if os.path.isfile(ubo_secrets_filename): with open(ubo_secrets_filename) as f: ubo_secrets = json.load(f) diff --git a/dist/version b/dist/version index 094d6ad..373aea9 100644 --- a/dist/version +++ b/dist/version @@ -1 +1 @@ -1.55.0 +1.57.0 diff --git a/platform/chromium/manifest.json b/platform/chromium/manifest.json index 28ceec5..df686a0 100644 --- a/platform/chromium/manifest.json +++ b/platform/chromium/manifest.json @@ -30,6 +30,9 @@ }, "toggle-cosmetic-filtering": { "description": "__MSG_toggleCosmeticFiltering__" + }, + "toggle-javascript": { + "description": "__MSG_toggleJavascript__" } }, "content_scripts": [ @@ -94,6 +97,7 @@ "open_in_tab": true }, "permissions": [ + "alarms", "contextMenus", "privacy", "storage", diff --git a/platform/chromium/webext.js b/platform/chromium/webext.js index 851b653..f044649 100644 --- a/platform/chromium/webext.js +++ b/platform/chromium/webext.js @@ -19,8 +19,6 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - // `webext` is a promisified api of `chrome`. Entries are added as // the promisification of uBO progress. @@ -54,6 +52,15 @@ const promisify = function(thisArg, fnName) { }; const webext = { + // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/alarms + alarms: { + clear: promisifyNoFail(chrome.alarms, 'clear'), + clearAll: promisifyNoFail(chrome.alarms, 'clearAll'), + create: promisifyNoFail(chrome.alarms, 'create'), + get: promisifyNoFail(chrome.alarms, 'get'), + getAll: promisifyNoFail(chrome.alarms, 'getAll'), + onAlarm: chrome.alarms.onAlarm, + }, // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/browserAction browserAction: { setBadgeBackgroundColor: promisifyNoFail(chrome.browserAction, 'setBadgeBackgroundColor'), @@ -95,6 +102,7 @@ const webext = { query: promisifyNoFail(chrome.tabs, 'query', tabs => Array.isArray(tabs) ? tabs : []), reload: promisifyNoFail(chrome.tabs, 'reload'), remove: promisifyNoFail(chrome.tabs, 'remove'), + sendMessage: promisifyNoFail(chrome.tabs, 'sendMessage'), update: promisifyNoFail(chrome.tabs, 'update', tab => tab instanceof Object ? tab : null), }, // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webNavigation diff --git a/platform/common/vapi-background.js b/platform/common/vapi-background.js index 0d6fcdd..2ff99ac 100644 --- a/platform/common/vapi-background.js +++ b/platform/common/vapi-background.js @@ -87,6 +87,19 @@ vAPI.app = { }, }; +/******************************************************************************/ + +// Generate segments of random six alphanumeric characters, thus one segment +// is a value out of 36^6 = over 2x10^9 values. + +vAPI.generateSecret = (size = 1) => { + let secret = ''; + while ( size-- ) { + secret += (Math.floor(Math.random() * 2176782336) + 2176782336).toString(36).slice(1); + } + return secret; +}; + /******************************************************************************* * * https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/storage/session @@ -96,9 +109,9 @@ vAPI.app = { * * */ -vAPI.sessionStorage = { +vAPI.sessionStorage = browser.storage.session || { get() { - return Promise.resolve({}); + return Promise.resolve(); }, set() { return Promise.resolve(); @@ -109,7 +122,7 @@ vAPI.sessionStorage = { clear() { return Promise.resolve(); }, - implemented: false, + unavailable: true, }; /******************************************************************************* @@ -124,46 +137,21 @@ vAPI.sessionStorage = { vAPI.storage = { get(key, ...args) { - if ( vAPI.sessionStorage.implemented !== true ) { - return webext.storage.local.get(key, ...args).catch(reason => { - console.log(reason); - }); - } - return vAPI.sessionStorage.get(key, ...args).then(bin => { - const size = Object.keys(bin).length; - if ( size === 1 && typeof key === 'string' && bin[key] === null ) { - return {}; - } - if ( size !== 0 ) { return bin; } - return webext.storage.local.get(key, ...args).then(bin => { - if ( bin instanceof Object === false ) { return bin; } - // Mirror empty result as null value in order to prevent - // from falling back to storage.local when there is no need. - const tomirror = Object.assign({}, bin); - if ( typeof key === 'string' && Object.keys(bin).length === 0 ) { - Object.assign(tomirror, { [key]: null }); - } - vAPI.sessionStorage.set(tomirror); - return bin; - }).catch(reason => { - console.log(reason); - }); + return webext.storage.local.get(key, ...args).catch(reason => { + console.log(reason); }); }, set(...args) { - vAPI.sessionStorage.set(...args); return webext.storage.local.set(...args).catch(reason => { console.log(reason); }); }, remove(...args) { - vAPI.sessionStorage.remove(...args); return webext.storage.local.remove(...args).catch(reason => { console.log(reason); }); }, clear(...args) { - vAPI.sessionStorage.clear(...args); return webext.storage.local.clear(...args).catch(reason => { console.log(reason); }); @@ -328,10 +316,10 @@ vAPI.Tabs = class { }); } - async executeScript() { + async executeScript(...args) { let result; try { - result = await webext.tabs.executeScript(...arguments); + result = await webext.tabs.executeScript(...args); } catch(reason) { } @@ -445,22 +433,26 @@ vAPI.Tabs = class { // For some reasons, some platforms do not honor the left,top // position when specified. I found that further calling // windows.update again with the same position _may_ help. + // + // https://github.com/uBlockOrigin/uBlock-issues/issues/2249 + // Mind that the creation of the popup window might fail. if ( details.popup !== undefined && vAPI.windows instanceof Object ) { - const createDetails = { + const basicDetails = { url: details.url, type: details.popup, }; - if ( details.box instanceof Object ) { - Object.assign(createDetails, details.box); + const shouldRestorePosition = details.box instanceof Object; + const extraDetails = shouldRestorePosition + ? Object.assign({}, basicDetails, details.box) + : basicDetails; + const win = await vAPI.windows.create(extraDetails); + if ( win === null ) { + if ( shouldRestorePosition === false ) { return; } + return vAPI.windows.create(basicDetails); } - const win = await vAPI.windows.create(createDetails); - if ( win === null ) { return; } - if ( details.box instanceof Object === false ) { return; } - if ( - win.left === details.box.left && - win.top === details.box.top - ) { - return; + if ( shouldRestorePosition === false ) { return; } + if ( win.left === details.box.left ) { + if ( win.top === details.box.top ) { return; } } vAPI.windows.update(win.id, { left: details.box.left, @@ -556,7 +548,7 @@ vAPI.Tabs = class { targetURL = vAPI.getURL(targetURL); } - vAPI.tabs.update(tabId, { url: targetURL }); + return vAPI.tabs.update(tabId, { url: targetURL }); } async remove(tabId) { @@ -1165,11 +1157,6 @@ vAPI.messaging = { // Support using a new secret for every network request. { - // Generate a 6-character alphanumeric string, thus one random value out - // of 36^6 = over 2x10^9 values. - const generateSecret = ( ) => - (Math.floor(Math.random() * 2176782336) + 2176782336).toString(36).slice(1); - const root = vAPI.getURL('/'); const reSecret = /\?secret=(\w+)/; const shortSecrets = []; @@ -1207,7 +1194,7 @@ vAPI.messaging = { } } lastShortSecretTime = Date.now(); - const secret = generateSecret(); + const secret = vAPI.generateSecret(); shortSecrets.push(secret); return secret; }, @@ -1215,7 +1202,7 @@ vAPI.messaging = { if ( previous !== undefined ) { longSecrets.delete(previous); } - const secret = `${generateSecret()}${generateSecret()}${generateSecret()}`; + const secret = vAPI.generateSecret(3); longSecrets.add(secret); return secret; }, @@ -1663,10 +1650,7 @@ vAPI.cloud = (( ) => { const push = async function(details) { const { datakey, data, encode } = details; - if ( - data === undefined || - typeof data === 'string' && data === '' - ) { + if ( data === undefined || typeof data === 'string' && data === '' ) { return deleteChunks(datakey, 0); } const item = { @@ -1674,10 +1658,9 @@ vAPI.cloud = (( ) => { tstamp: Date.now(), data, }; - const json = JSON.stringify(item); const encoded = encode instanceof Function - ? await encode(json) - : json; + ? await encode(item) + : JSON.stringify(item); // Chunkify taking into account QUOTA_BYTES_PER_ITEM: // https://developer.chrome.com/extensions/storage#property-sync @@ -1742,13 +1725,16 @@ vAPI.cloud = (( ) => { i += 1; } encoded = encoded.join(''); - const json = decode instanceof Function - ? await decode(encoded) - : encoded; + let entry = null; try { - entry = JSON.parse(json); - } catch(ex) { + if ( decode instanceof Function ) { + entry = await decode(encoded) || null; + } + if ( typeof entry === 'string' ) { + entry = JSON.parse(entry); + } + } catch(_) { } return entry; }; @@ -1797,15 +1783,24 @@ vAPI.cloud = (( ) => { /******************************************************************************/ /******************************************************************************/ -vAPI.alarms = browser.alarms || { - create() { +vAPI.alarms = { + create(...args) { + webext.alarms.create(...args); }, - clear() { + createIfNotPresent(name, ...args) { + webext.alarms.get(name).then(details => { + if ( details !== undefined ) { return; } + webext.alarms.create(name, ...args); + }); + }, + async clear(...args) { + return webext.alarms.clear(...args); }, onAlarm: { - addListener() { - } - } + addListener(...args) { + webext.alarms.onAlarm.addListener(...args); + }, + }, }; /******************************************************************************/ diff --git a/platform/common/vapi-client.js b/platform/common/vapi-client.js index 9375e88..a6d46c6 100644 --- a/platform/common/vapi-client.js +++ b/platform/common/vapi-client.js @@ -22,10 +22,6 @@ // For non-background page -/* globals browser */ - -'use strict'; - /******************************************************************************/ // https://github.com/chrisaljoudi/uBlock/issues/456 @@ -85,6 +81,7 @@ vAPI.messaging = { portTimerDelay: 10000, msgIdGenerator: 1, pending: new Map(), + waitStartTime: 0, shuttingDown: false, shutdown: function() { @@ -115,16 +112,11 @@ vAPI.messaging = { // revisited to isolate the picker dialog DOM from the page DOM. messageListener: function(details) { if ( typeof details !== 'object' || details === null ) { return; } - - // Response to specific message previously sent - if ( details.msgId !== undefined ) { - const resolver = this.pending.get(details.msgId); - if ( resolver !== undefined ) { - this.pending.delete(details.msgId); - resolver(details.msg); - return; - } - } + if ( details.msgId === undefined ) { return; } + const resolver = this.pending.get(details.msgId); + if ( resolver === undefined ) { return; } + this.pending.delete(details.msgId); + resolver(details.msg); }, messageListenerBound: null, @@ -203,13 +195,18 @@ vAPI.messaging = { // the main process is no longer reachable: memory leaks and bad // performance become a risk -- especially for long-lived, dynamic // pages. Guard against this. - if ( this.pending.size > 50 ) { - vAPI.shutdown.exec(); + if ( this.pending.size > 64 ) { + if ( (Date.now() - this.waitStartTime) > 60000 ) { + vAPI.shutdown.exec(); + } } const port = this.getPort(); if ( port === null ) { return Promise.resolve(); } + if ( this.pending.size === 0 ) { + this.waitStartTime = Date.now(); + } const msgId = this.msgIdGenerator++; const promise = new Promise(resolve => { this.pending.set(msgId, resolve); diff --git a/platform/firefox/manifest.json b/platform/firefox/manifest.json index 4ee0b56..db021f2 100644 --- a/platform/firefox/manifest.json +++ b/platform/firefox/manifest.json @@ -43,6 +43,9 @@ }, "toggle-cosmetic-filtering": { "description": "__MSG_toggleCosmeticFiltering__" + }, + "toggle-javascript": { + "description": "__MSG_toggleJavascript__" } }, "content_scripts": [ diff --git a/platform/mv3/description/webstore.be.txt b/platform/mv3/description/webstore.be.txt index e03fa80..d5a2e98 100644 --- a/platform/mv3/description/webstore.be.txt +++ b/platform/mv3/description/webstore.be.txt @@ -27,4 +27,4 @@ Keep in mind this is still a work in progress, with these end goals: - No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. -- Entirely declarative for reliability and CPU/memory efficiency. +- Цалкам дэкларатыўная ацэнка надзейнасці і эфектыўнасці работы працэсара/памяці. diff --git a/platform/mv3/description/webstore.br_FR.txt b/platform/mv3/description/webstore.br_FR.txt index bfc4ce6..0335493 100644 --- a/platform/mv3/description/webstore.br_FR.txt +++ b/platform/mv3/description/webstore.br_FR.txt @@ -1,4 +1,4 @@ -uBO Lite (uBOL) zo ur stanker noazadurioù *hep aotreoù* diazezet war ar manifesto MV3. +uBO Lite (uBOL) zo ur stanker noazadurioù *hep aotre rekis ebet* diazezet war ar manifesto MV3. Ar reolennoù dre ziouer a glot gant silañ dre ziouer uBlock Origin: diff --git a/platform/mv3/description/webstore.cy.txt b/platform/mv3/description/webstore.cy.txt new file mode 100644 index 0000000..e03fa80 --- /dev/null +++ b/platform/mv3/description/webstore.cy.txt @@ -0,0 +1,30 @@ +uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. + +The default ruleset corresponds to uBlock Origin's default filterset: + +- uBlock Origin's built-in filter lists +- EasyList +- EasyPrivacy +- Peter Lowe’s Ad and tracking server list + +You can add more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. + +uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. + +uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. + +However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. + +To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. + +The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. + +If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. + +You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. + +Keep in mind this is still a work in progress, with these end goals: + +- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. + +- Entirely declarative for reliability and CPU/memory efficiency. diff --git a/platform/mv3/description/webstore.et.txt b/platform/mv3/description/webstore.et.txt index d3bf236..520e4ce 100644 --- a/platform/mv3/description/webstore.et.txt +++ b/platform/mv3/description/webstore.et.txt @@ -17,14 +17,14 @@ Kuid uBOL võimaldab *selgesõnaliselt* anda täpsemaid lubasid teie valitud vee Veebilehele täpsustatud lubade andmiseks ava hüpikpaneel ja vali põhjalikum filtreerimisrežiim, näiteks Optimaalne või Põhjalik. -Seejärel hoiatab brauser teid praeguse saidi laienduse taotletud täiendavate õiguste andmise tagajärgede eest ja peate brauserile ütlema, kas nõustute taotlusega või keeldute sellest. +Seejärel hoiatab veebilehitseja praeguse veebilehe laienduse taotletud täiendavate õiguste andmise tagajärgede eest ja peate veebilehitsejale ütlema, kas nõustute taotlusega või keeldute sellest. -Kui nõustute uBOLi taotlusega täiendavate õiguste saamiseks praegusel saidil, saab see praeguse saidi sisu paremini filtreerida. +Kui nõustute uBOLi taotlusega täiendavate õiguste saamiseks praegusel veebilehel, saab see praeguse veebilehe sisu paremini filtreerida. -Vaikimisi filtreerimisrežiimi saate määrata uBOLi suvandite lehelt Kui määrate optimaalse või põhjaliku režiimi tavaliseks, peate andma uBOLile loa kõikide veebilehtede andmete lugemiseks ja muutmiseks. +Fltreerimise tavarežiimi saate määrata uBOLi valikute lehelt. Kui määrate optimaalse või põhjaliku režiimi tavaliseks, peate andma uBOLile loa kõikide veebilehtede andmete lugemiseks ja muutmiseks. -Pidage meeles, et see on veel pooleliolev töö, mille lõppeesmärgid on järgmised: +Pidage meeles, et see on veel arendamisel, mille lõppeesmärgid on järgmised: -- Installimise ajal laialdased hostiõigused puuduvad – kasutaja annab laiendatud load selgesõnaliselt saidipõhiselt. +- Paigaldamise ajal laialdased hostiõigused puuduvad – kasutaja annab laiendatud load selgesõnaliselt ja veebilehe põhiselt. - Täiesti deklaratiivne töökindluse ja protsessori/mälu tõhususe osas. diff --git a/platform/mv3/description/webstore.ms.txt b/platform/mv3/description/webstore.ms.txt index e03fa80..2a48cf6 100644 --- a/platform/mv3/description/webstore.ms.txt +++ b/platform/mv3/description/webstore.ms.txt @@ -1,30 +1,30 @@ -uBO Lite (uBOL) is a *permission-less* MV3-based content blocker. +uBO Lite (uBOL) ialah penyekat kandungan berasaskan MV3. -The default ruleset corresponds to uBlock Origin's default filterset: +Set peraturan lalai sepadan dengan set penapis lalai uBlock Origin: -- uBlock Origin's built-in filter lists +- Senarai penapis terbina dalam uBlock Origin - EasyList - EasyPrivacy -- Peter Lowe’s Ad and tracking server list +- Senarai pelayan iklan dan penjejakan 'Peter Lowe' -You can add more rulesets by visiting the options page -- click the _Cogs_ icon in the popup panel. +Anda boleh menambah lebih banyak set peraturan dengan melawat halaman pilihan -- klik the _Cogs_ icon pada panel timbul. -uBOL is entirely declarative, meaning there is no need for a permanent uBOL process for the filtering to occur, and CSS/JS injection-based content filtering is performed reliably by the browser itself rather than by the extension. This means that uBOL itself does not consume CPU/memory resources while content blocking is ongoing -- uBOL's service worker process is required _only_ when you interact with the popup panel or the option pages. +uBOL adalah deklaratif sepenuhnya, bermakna tidak ada keperluan untuk proses uBOL kekal untuk penapisan berlaku, dan penapisan kandungan berasaskan suntikan CSS/JS dilakukan sepenuhnya oleh penyemak imbas itu sendiri dan bukannya oleh sambungan. Ini bermakna uBOL sendiri tidak menggunakan sumber CPU/memori semasa penyekatan kandungan sedang berjalan -- proses pekerja perkhidmatan uBOL diperlukan _hanya_ apabila anda berinteraksi dengan panel timbul atau halaman pilihan. -uBOL does not require broad "read and modify data" permission at install time, hence its limited capabilities out of the box compared to uBlock Origin or other content blockers requiring broad "read and modify data" permissions at install time. +uBOL tidak memerlukan kebenaran "baca dan ubah suai data" yang luas pada masa pemasangan, oleh itu keupayaan terhadnya di luar kotak berbanding dengan uBlock Origin atau penyekat kandungan lain yang memerlukan kebenaran "baca dan ubah suai data" yang luas pada masa pemasangan. -However, uBOL allows you to *explicitly* grant extended permissions on specific sites of your choice so that it can better filter on those sites using cosmetic filtering and scriptlet injections. +Walau bagaimanapun, uBOL membenarkan anda *dengan jelas* memberikan kebenaran lanjutan pada tapak tertentu pilihan anda supaya ia boleh menapis dengan lebih baik pada tapak tersebut menggunakan penapisan kosmetik dan suntikan skrip. -To grant extended permissions on a given site, open the popup panel and pick a higher filtering mode such as Optimal or Complete. +Untuk memberikan kebenaran lanjutan pada tapak tertentu, buka panel timbul dan pilih mod penapisan yang lebih tinggi seperti Optimum atau Lengkap. -The browser will then warn you about the effects of granting the additional permissions requested by the extension on the current site, and you will have to tell the browser whether you accept or decline the request. +Penyemak imbas kemudian akan memberi amaran kepada anda tentang kesan pemberian kebenaran tambahan yang diminta oleh sambungan pada tapak semasa dan anda perlu memberitahu penyemak imbas sama ada anda menerima atau menolak permintaan tersebut. -If you accept uBOL's request for additional permissions on the current site, it will be able to better filter content for the current site. +Jika anda menerima permintaan uBOL untuk mendapatkan kebenaran tambahan pada tapak semasa, ia akan dapat menapis kandungan dengan lebih baik untuk tapak semasa. -You can set the default filtering mode from uBOL's options page. If you pick the Optimal or Complete mode as the default one, you will need to grant uBOL the permission to read and modify data on all websites. +Anda boleh menetapkan mod penapisan lalai dari halaman pilihan 'uBOL'. Jika anda memilih mod Optimum atau Lengkap sebagai mod lalai, anda perlu memberikan uBOL kebenaran untuk membaca dan mengubah suai data pada semua tapak web. -Keep in mind this is still a work in progress, with these end goals: +Perlu diingat bahawa ini masih dalam proses, dengan matlamat akhir ini: -- No broad host permissions at install time -- extended permissions are granted explicitly by the user on a per-site basis. +- Tiada kebenaran hos pada masa pemasangan -- kebenaran lanjutan diberikan secara eksplisit oleh pengguna pada asas setiap tapak. -- Entirely declarative for reliability and CPU/memory efficiency. +- Deklaratif sepenuhnya untuk kebolehpercayaan dan kecekapan CPU/memori. diff --git a/platform/mv3/description/webstore.pl.txt b/platform/mv3/description/webstore.pl.txt index a65d0db..4f5c524 100644 --- a/platform/mv3/description/webstore.pl.txt +++ b/platform/mv3/description/webstore.pl.txt @@ -1,13 +1,13 @@ -uBO Lite (uBOL) to *niewymagający uprawnień* bloker treści bazujący na MV3. +uBO Lite (uBOL) to *niewymagający uprawnień* bloker treści oparty na MV3. Domyślny zestaw reguł odpowiada domyślnemu zestawowi filtrów uBlock Origin: -– wbudowane listy filtrów uBlock Origin +– wbudowane listy filtrów rozszerzenia uBlock Origin – EasyList – EasyPrivacy – lista serwerów śledzących i reklam Petera Lowe'a -Możesz dodać więcej zestawów reguł, odwiedzając stronę opcji – kliknij ikonę _Trybika_ w wyskakującym panelu. +Możesz dodać więcej zestawów reguł, odwiedzając stronę opcji – kliknij ikonę _koła zębatego_ w wyskakującym panelu. uBOL jest całkowicie deklaratywny, co oznacza, że nie jest potrzebny stały proces uBOL w celu filtrowania, a filtrowanie treści oparte na wstrzykiwaniu CSS/JS jest wykonywane niezawodnie przez samą przeglądarkę, a nie przez rozszerzenie. Oznacza to, że sam uBOL nie zużywa zasobów procesora/pamięci, gdy trwa blokowanie treści – proces Service Worker uBOL jest wymagany _tylko_ podczas interakcji z panelem wyskakującym lub stronami opcji. diff --git a/platform/mv3/description/webstore.pt_PT.txt b/platform/mv3/description/webstore.pt_PT.txt index f390d5d..fcd3823 100644 --- a/platform/mv3/description/webstore.pt_PT.txt +++ b/platform/mv3/description/webstore.pt_PT.txt @@ -7,7 +7,7 @@ O conjunto de regras padrão corresponde ao conjunto de filtros padrão do uBloc - EasyPrivacy - Peter Lowe’s Ad and tracking server list -Pode adicionar mais conjuntos de regras visitando a página de opções -- clique no ícone _Cogs_ no painel pop-up. +Pode adicionar mais conjuntos de regras visitando a página de opções -- clique no ícone _Cogs_ na janela flutuante. O uBOL é totalmente declarativo, o que elimina a necessidade de um processo ativo constante para a filtragem ocorrer. A injeção de CSS e JS para filtragem de conteúdo é efetuada de maneira confiável pelo navegador, não dependendo da extensão. Isso significa que o uBOL por si só não gasta recursos de CPU/memória enquanto o bloqueio de conteúdo está a acontecer -- o processo do trabalhador de serviço do uBOL é necessário apenas quando se interage com a janela flutuante ou as páginas de opções. @@ -25,6 +25,6 @@ Pode definir o modo de filtragem padrão na página de opções do uBOL. Se esco Tenha em mente que este ainda é um trabalho em curso, com estes objetivos finais: -Sem permissões amplas de anfitrião no momento da instalação -- permissões estendidas são concedidas explicitamente pelo utilizador numa base por site. +- Sem permissões amplas de anfitrião no momento da instalação -- permissões estendidas são concedidas explicitamente pelo utilizador numa base por site. - Totalmente declarativo para fiabilidade e eficiência de CPU/memória diff --git a/platform/mv3/extension/_locales/ar/messages.json b/platform/mv3/extension/_locales/ar/messages.json index d907faa..6b6b476 100644 --- a/platform/mv3/extension/_locales/ar/messages.json +++ b/platform/mv3/extension/_locales/ar/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "إعادة تحميل الصفحة تلقائيًا عند تغيير وضع التصفية", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "إظهار عدد الطلبات المحظورة على أيقونة شريط الأدوات", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/az/messages.json b/platform/mv3/extension/_locales/az/messages.json index 59b7d81..deef8d2 100644 --- a/platform/mv3/extension/_locales/az/messages.json +++ b/platform/mv3/extension/_locales/az/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/be/messages.json b/platform/mv3/extension/_locales/be/messages.json index 795f961..3e96e72 100644 --- a/platform/mv3/extension/_locales/be/messages.json +++ b/platform/mv3/extension/_locales/be/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Аўтаматычна абнаўляць старонку пры змене рэжыму фільтравання", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/bg/messages.json b/platform/mv3/extension/_locales/bg/messages.json index c440a4b..f4606dd 100644 --- a/platform/mv3/extension/_locales/bg/messages.json +++ b/platform/mv3/extension/_locales/bg/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Автоматично презареждане на страницата при промяна на режима на филтриране", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Показване на брояч в иконката за блокираните заявки", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/bn/messages.json b/platform/mv3/extension/_locales/bn/messages.json index ba12b5d..1232fc7 100644 --- a/platform/mv3/extension/_locales/bn/messages.json +++ b/platform/mv3/extension/_locales/bn/messages.json @@ -16,7 +16,7 @@ "description": "English: uBO Lite — Dashboard" }, "settingsPageName": { - "message": "পছন্দসমূহ", + "message": "সেটিংস", "description": "appears as tab name in dashboard" }, "aboutPageName": { @@ -116,7 +116,7 @@ "description": "This describes the default filtering mode setting" }, "filteringMode0Name": { - "message": "ছাঁকনি নেই", + "message": "ফিল্টারিং নেই", "description": "Name of blocking mode 0" }, "filteringMode1Name": { @@ -152,7 +152,11 @@ "description": "The header text for the 'Behavior' section" }, "autoReloadLabel": { - "message": "ফিল্টারিং মোড পরিবর্তন করার সময় স্বয়ংক্রিয়ভাবে পেজ পুনরায় লোড করুন", + "message": "ফিল্টারিং মোড পরিবর্তন করার সময় স্বয়ংক্রিয়ভাবে পুনরায় লোড করুন", + "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/br_FR/messages.json b/platform/mv3/extension/_locales/br_FR/messages.json index 48f7013..3039596 100644 --- a/platform/mv3/extension/_locales/br_FR/messages.json +++ b/platform/mv3/extension/_locales/br_FR/messages.json @@ -88,7 +88,7 @@ "description": "Link text to source code repo" }, "aboutTranslations": { - "message": "Troidigezhioù", + "message": "Treiñ", "description": "Link text to translations repo" }, "aboutFilterLists": { @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Roll eus anvioù domanioù el-lec'h ne vo silañ ebet", + "message": "Roll anvioù domanioù ha ne vint ket silet.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Adkargañ ar bajenn ent-emgefreek pa vez cheñchet an doare silañ", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Diskouez an niver a rekedoù bet stanket war arouez ar varrenn-ostilhoù", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/bs/messages.json b/platform/mv3/extension/_locales/bs/messages.json index 14e847d..ab768f6 100644 --- a/platform/mv3/extension/_locales/bs/messages.json +++ b/platform/mv3/extension/_locales/bs/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatski ponovo učitajte stranicu prilikom promjene načina filtriranja", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/ca/messages.json b/platform/mv3/extension/_locales/ca/messages.json index abe76eb..5e1f1eb 100644 --- a/platform/mv3/extension/_locales/ca/messages.json +++ b/platform/mv3/extension/_locales/ca/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Recarrega automàticament la pàgina quan canvieu el mode de filtratge", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Mostra el nombre de sol·licituds blocades a la icona de la barra d'eines", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/cs/messages.json b/platform/mv3/extension/_locales/cs/messages.json index abc5164..db051f0 100644 --- a/platform/mv3/extension/_locales/cs/messages.json +++ b/platform/mv3/extension/_locales/cs/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Experimentální blokátor obsahu vyžadující méně oprávnění. Blokuje reklamy, sledovače, těžaře a jiné ihned po instalaci.", + "message": "Blokátor obsahu vyžadující méně oprávnění. Blokuje reklamy, sledovače, těžaře a jiné ihned po instalaci.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -80,7 +80,7 @@ "description": "English: Source code (GPLv3)" }, "aboutContributors": { - "message": "Přispívající", + "message": "Přispěvatelé", "description": "English: Contributors" }, "aboutSourceCode": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automaticky znovu načíst stránku při změně filtrovacího režimu", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Zobrazit počet blokovaných požadavků u ikony v panelu nástrojů", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/cv/messages.json b/platform/mv3/extension/_locales/cv/messages.json index 627857e..4bbb5e3 100644 --- a/platform/mv3/extension/_locales/cv/messages.json +++ b/platform/mv3/extension/_locales/cv/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/cy/messages.json b/platform/mv3/extension/_locales/cy/messages.json new file mode 100644 index 0000000..c9d0e36 --- /dev/null +++ b/platform/mv3/extension/_locales/cy/messages.json @@ -0,0 +1,162 @@ +{ + "extName": { + "message": "uBlock Origin Lite", + "description": "extension name." + }, + "extShortDesc": { + "message": "Rhwystrydd cynnwys nad yw'n gofyn am hawliau. Rhwystrwch hysbysebion, tracwyr, cloddwyr, a mwy, yn syth ar ôl gosod.", + "description": "this will be in the Chrome web store: must be 132 characters or less" + }, + "perRulesetStats": { + "message": "{{ruleCount}} rules, converted from {{filterCount}} network filters", + "description": "Appears aside each filter list in the _3rd-party filters_ pane" + }, + "dashboardName": { + "message": "uBO Lite — Dashfwrdd", + "description": "English: uBO Lite — Dashboard" + }, + "settingsPageName": { + "message": "Gosodiadau", + "description": "appears as tab name in dashboard" + }, + "aboutPageName": { + "message": "Ynghylch", + "description": "appears as tab name in dashboard" + }, + "aboutPrivacyPolicy": { + "message": "Polisi preifatrwydd", + "description": "Link to privacy policy on GitHub (English)" + }, + "popupFilteringModeLabel": { + "message": "modd hidlo", + "description": "Label in the popup panel for the current filtering mode" + }, + "popupTipDashboard": { + "message": "Agor y dashfwrdd", + "description": "English: Click to open the dashboard" + }, + "popupMoreButton": { + "message": "Mwy", + "description": "Label to be used to show popup panel sections" + }, + "popupLessButton": { + "message": "Llai", + "description": "Label to be used to hide popup panel sections" + }, + "3pGroupDefault": { + "message": "Default", + "description": "Header for a ruleset section in 'Filter lists pane'" + }, + "3pGroupAds": { + "message": "Hysbysebion", + "description": "Header for a ruleset section in 'Filter lists pane'" + }, + "3pGroupPrivacy": { + "message": "Preifatrwydd", + "description": "Header for a ruleset section in 'Filter lists pane'" + }, + "3pGroupMalware": { + "message": "Malware domains", + "description": "Header for a ruleset section in 'Filter lists pane'" + }, + "3pGroupAnnoyances": { + "message": "Pethau diflas", + "description": "Header for a ruleset section in 'Filter lists pane'" + }, + "3pGroupMisc": { + "message": "Amrywiol", + "description": "Header for a ruleset section in 'Filter lists pane'" + }, + "3pGroupRegions": { + "message": "Rhanbarthau, ieithoedd", + "description": "Header for a ruleset section in 'Filter lists pane'" + }, + "aboutChangelog": { + "message": "Cofnod newidiadau", + "description": "" + }, + "aboutCode": { + "message": "Cod ffynhonnell (GPLv3)", + "description": "English: Source code (GPLv3)" + }, + "aboutContributors": { + "message": "Cyfranwyr", + "description": "English: Contributors" + }, + "aboutSourceCode": { + "message": "Cod ffynhonnell", + "description": "Link text to source code repo" + }, + "aboutTranslations": { + "message": "Cyfieithiadau", + "description": "Link text to translations repo" + }, + "aboutFilterLists": { + "message": "Rhestri hidlo", + "description": "Link text to uBO's own filter lists repo" + }, + "aboutDependencies": { + "message": "Gofynion allanol (cydnaws â GPLv3):", + "description": "Shown in the About pane" + }, + "firstRunSectionLabel": { + "message": "Croeso", + "description": "The header text for the welcome message section" + }, + "firstRunDescription": { + "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", + "description": "Descriptive text shown at first install time only " + }, + "defaultFilteringModeSectionLabel": { + "message": "Default filtering mode", + "description": "The header text for the default filtering mode section" + }, + "defaultFilteringModeDescription": { + "message": "The default filtering mode will be overridden by per-website filtering modes. You can adjust the filtering mode on any given website according to whichever mode works best on that website. Each mode has its advantages and disadvantages.", + "description": "This describes the default filtering mode setting" + }, + "filteringMode0Name": { + "message": "dim hidlo", + "description": "Name of blocking mode 0" + }, + "filteringMode1Name": { + "message": "sylfaenol", + "description": "Name of blocking mode 1" + }, + "filteringMode2Name": { + "message": "priodol", + "description": "Name of blocking mode 2" + }, + "filteringMode3Name": { + "message": "cyflawn", + "description": "Name of blocking mode 3" + }, + "basicFilteringModeDescription": { + "message": "Basic network filtering from selected filter lists.\n\nDoes not require permission to read and modify data on websites.", + "description": "This describes the 'basic' filtering mode" + }, + "optimalFilteringModeDescription": { + "message": "Advanced network filtering plus specific extended filtering from selected filter lists.\n\nRequires broad permission to read and modify data on all websites.", + "description": "This describes the 'optimal' filtering mode" + }, + "completeFilteringModeDescription": { + "message": "Advanced network filtering plus specific and generic extended filtering from selected filter lists.\n\nRequires broad permission to read and modify data on all websites.\n\nGeneric extended filtering may cause higher webpage resources usage.", + "description": "This describes the 'complete' filtering mode" + }, + "noFilteringModeDescription": { + "message": "List of hostnames for which no filtering will take place.", + "description": "A short description for the editable field which lists trusted sites" + }, + "behaviorSectionLabel": { + "message": "Ymddygiad", + "description": "The header text for the 'Behavior' section" + }, + "autoReloadLabel": { + "message": "Ail-lwytho tudalen ar ôl newid y modd hidlo", + "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" + } +} diff --git a/platform/mv3/extension/_locales/da/messages.json b/platform/mv3/extension/_locales/da/messages.json index 7f628ab..ae494fe 100644 --- a/platform/mv3/extension/_locales/da/messages.json +++ b/platform/mv3/extension/_locales/da/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Liste over værtsnavne, for hvilke ingen filtrering vil ske", + "message": "Liste over værtsnavne, for hvilke ingen filtrering vil ske.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatisk sidegenindlæsning ved skift af filtreringstilstand", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Vis antallet af blokerede forespørgsler på værktøjsbjælkeikonet", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/de/messages.json b/platform/mv3/extension/_locales/de/messages.json index 1e014df..13829f3 100644 --- a/platform/mv3/extension/_locales/de/messages.json +++ b/platform/mv3/extension/_locales/de/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Liste der Hostnamen, für die nicht gefiltert wird", + "message": "Liste der Hostnamen, für die nicht gefiltert wird.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Seite beim Ändern des Filtermodus automatisch neu laden", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Anzahl der blockierten Anfragen auf dem Symbol in der Symbolleiste anzeigen", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/el/messages.json b/platform/mv3/extension/_locales/el/messages.json index cc8c204..8e3bc5e 100644 --- a/platform/mv3/extension/_locales/el/messages.json +++ b/platform/mv3/extension/_locales/el/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Αυτόματη επαναφόρτωση σελίδας κατά την αλλαγή λειτουργίας φιλτραρίσματος", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Εμφάνιση του αριθμού των αποκλεισμένων αιτημάτων στο εικονίδιο της γραμμής εργαλείων", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/en/messages.json b/platform/mv3/extension/_locales/en/messages.json index 6725ba1..878f3cc 100644 --- a/platform/mv3/extension/_locales/en/messages.json +++ b/platform/mv3/extension/_locales/en/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/en_GB/messages.json b/platform/mv3/extension/_locales/en_GB/messages.json index b935137..884d7c1 100644 --- a/platform/mv3/extension/_locales/en_GB/messages.json +++ b/platform/mv3/extension/_locales/en_GB/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/eo/messages.json b/platform/mv3/extension/_locales/eo/messages.json index 9e86eea..ba5cfde 100644 --- a/platform/mv3/extension/_locales/eo/messages.json +++ b/platform/mv3/extension/_locales/eo/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/es/messages.json b/platform/mv3/extension/_locales/es/messages.json index 1bf7af5..53ff70b 100644 --- a/platform/mv3/extension/_locales/es/messages.json +++ b/platform/mv3/extension/_locales/es/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Lista de nombres de host para los cuales no tendrá lugar el filtrado", + "message": "Lista de nombres de dominio para los cuales no se realizará ningún filtrado.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Recargar automáticamente la página al cambiar el modo de filtrado", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Mostrar el número de peticiones bloqueadas en el icono de la barra de herramientas", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/et/messages.json b/platform/mv3/extension/_locales/et/messages.json index 92e5952..69f6aa2 100644 --- a/platform/mv3/extension/_locales/et/messages.json +++ b/platform/mv3/extension/_locales/et/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Leht laadib ise uuesti filtreerimisrežiimi muutmisel", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Kuva tööriistariba ikoonil blokeeritud elementide arv", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/eu/messages.json b/platform/mv3/extension/_locales/eu/messages.json index 386468f..aa48a0a 100644 --- a/platform/mv3/extension/_locales/eu/messages.json +++ b/platform/mv3/extension/_locales/eu/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Probatako eta baimenik behar ez duen eduki-blokeatzailea. Iragarkiak, jarraitzeko tresnak, eta gehiago instalatzean bertan [...]", + "message": "Probatako eta baimenik behar ez duen eduki-blokeatzailea. Iragarkiak, jarraitzeko tresnak, eta gehiago instalatzean bertan.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "Filtrorik ezarriko ez zaien zerbitzarien izenak", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Orria automatikoki kargatuko da iragazteko modua aldatuko denean", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/fa/messages.json b/platform/mv3/extension/_locales/fa/messages.json index b0ed662..900a492 100644 --- a/platform/mv3/extension/_locales/fa/messages.json +++ b/platform/mv3/extension/_locales/fa/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/fi/messages.json b/platform/mv3/extension/_locales/fi/messages.json index 44ac9b0..05d4211 100644 --- a/platform/mv3/extension/_locales/fi/messages.json +++ b/platform/mv3/extension/_locales/fi/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Lataa sivu suodatustilan vaihtuessa automaattisesti uudelleen", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Näytä estettyjen pyyntöjen määrä työkalupalkin kuvakkeessa", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/fil/messages.json b/platform/mv3/extension/_locales/fil/messages.json index 68025d2..fe5daa4 100644 --- a/platform/mv3/extension/_locales/fil/messages.json +++ b/platform/mv3/extension/_locales/fil/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Awtomatikong i-reload ang pahina kapag binago ang mode sa pagfi-filter", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/fr/messages.json b/platform/mv3/extension/_locales/fr/messages.json index 2f6a837..0152c8e 100644 --- a/platform/mv3/extension/_locales/fr/messages.json +++ b/platform/mv3/extension/_locales/fr/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Liste des noms de domaine pour lesquels aucun filtrage n'aura lieu", + "message": "Liste des noms de domaine qu'uBO Lite ne devra pas filtrer", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Recharger automatiquement la page lors du changement de mode de filtrage", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Afficher le nombre de requêtes bloquées sur l'icône", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/fy/messages.json b/platform/mv3/extension/_locales/fy/messages.json index 606fc0a..f583e4b 100644 --- a/platform/mv3/extension/_locales/fy/messages.json +++ b/platform/mv3/extension/_locales/fy/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Side automatysk fernije by wizigjen fan filtermodus", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "It tal blokkearre oanfragen op it arkbalkepiktogram toane", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/gl/messages.json b/platform/mv3/extension/_locales/gl/messages.json index 460bdb8..760c65c 100644 --- a/platform/mv3/extension/_locales/gl/messages.json +++ b/platform/mv3/extension/_locales/gl/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Recargar automáticamente a páxina a cambiar o modo de filtrado", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Mostrar na icona da barra o número de peticións bloqueadas", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/gu/messages.json b/platform/mv3/extension/_locales/gu/messages.json index 627857e..4bbb5e3 100644 --- a/platform/mv3/extension/_locales/gu/messages.json +++ b/platform/mv3/extension/_locales/gu/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/he/messages.json b/platform/mv3/extension/_locales/he/messages.json index 3782fdb..beb73f2 100644 --- a/platform/mv3/extension/_locales/he/messages.json +++ b/platform/mv3/extension/_locales/he/messages.json @@ -20,7 +20,7 @@ "description": "appears as tab name in dashboard" }, "aboutPageName": { - "message": "אודות", + "message": "על אודות", "description": "appears as tab name in dashboard" }, "aboutPrivacyPolicy": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "טעינת עמוד באופן אוטומטי עם שינוי מצב סינון", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "הצגת מספר הבקשות החסומות על הסמל", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/hi/messages.json b/platform/mv3/extension/_locales/hi/messages.json index 89ed004..244acb8 100644 --- a/platform/mv3/extension/_locales/hi/messages.json +++ b/platform/mv3/extension/_locales/hi/messages.json @@ -20,7 +20,7 @@ "description": "appears as tab name in dashboard" }, "aboutPageName": { - "message": "परिचय", + "message": "जानकारी", "description": "appears as tab name in dashboard" }, "aboutPrivacyPolicy": { @@ -72,11 +72,11 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "aboutChangelog": { - "message": "परिवर्तन लॉग", + "message": "परिवर्तन पत्र", "description": "" }, "aboutCode": { - "message": "सोर्स कोड {GPLv3}", + "message": "सोर्स कोड (GPLv3)", "description": "English: Source code (GPLv3)" }, "aboutContributors": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "फ़िल्टरिंग मोड बदलते समय स्वचालित रूप से पृष्ठ पुनः लोड करें", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "टूलबार आइकन पर अवरुद्ध अनुरोधों की संख्या दिखाएं", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/hr/messages.json b/platform/mv3/extension/_locales/hr/messages.json index 14c9401..2ae0291 100644 --- a/platform/mv3/extension/_locales/hr/messages.json +++ b/platform/mv3/extension/_locales/hr/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Popis naziva hostova za koje se neće izvršiti filtriranje", + "message": "Popis naziva hostova za koje se neće izvršiti filtriranje.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatski ponovno učitaj stranicu pri promjeni načina filtriranja", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Prikaži broj blokiranih zahtjeva na ikoni alatne trake", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/hu/messages.json b/platform/mv3/extension/_locales/hu/messages.json index 5fe25d2..3ec2b0e 100644 --- a/platform/mv3/extension/_locales/hu/messages.json +++ b/platform/mv3/extension/_locales/hu/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Az oldal automatikus újratöltése a szűrési mód megváltoztatásakor", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Blokkolt kérések számának megjelenítése az eszköztárikonon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/hy/messages.json b/platform/mv3/extension/_locales/hy/messages.json index 50b9b44..7defd2e 100644 --- a/platform/mv3/extension/_locales/hy/messages.json +++ b/platform/mv3/extension/_locales/hy/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Զտման ռեժիմը փոխելիս ինքնաշխատորեն վերաբեռնել էջը", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/id/messages.json b/platform/mv3/extension/_locales/id/messages.json index e3c6f69..a71f966 100644 --- a/platform/mv3/extension/_locales/id/messages.json +++ b/platform/mv3/extension/_locales/id/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Otomatis memuat ulang halaman web saat mengubah mode filter", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/it/messages.json b/platform/mv3/extension/_locales/it/messages.json index 04c500e..beea941 100644 --- a/platform/mv3/extension/_locales/it/messages.json +++ b/platform/mv3/extension/_locales/it/messages.json @@ -8,11 +8,11 @@ "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { - "message": "{{ruleCount}} regole, convertite da {{filterCount}} filtri di rete", + "message": "{{ruleCount}} Regole, convertite da {{filterCount}} filtri di rete", "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "dashboardName": { - "message": "uBO Lite — Cruscotto", + "message": "uBO Lite — Pannello di controllo", "description": "English: uBO Lite — Dashboard" }, "settingsPageName": { @@ -32,7 +32,7 @@ "description": "Label in the popup panel for the current filtering mode" }, "popupTipDashboard": { - "message": "Accedi al cruscotto", + "message": "Apri il pannello di controllo", "description": "English: Click to open the dashboard" }, "popupMoreButton": { @@ -44,7 +44,7 @@ "description": "Label to be used to hide popup panel sections" }, "3pGroupDefault": { - "message": "Predefinite", + "message": "Predefiniti", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAds": { @@ -60,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { - "message": "Scocciature", + "message": "Disturbi", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMisc": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Ricarica la pagina quando scegli un altro metodo di filtraggio", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Mostra il numero di richieste bloccate sull'icona nella barra degli strumenti", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/ja/messages.json b/platform/mv3/extension/_locales/ja/messages.json index fe679dc..ea15fdd 100644 --- a/platform/mv3/extension/_locales/ja/messages.json +++ b/platform/mv3/extension/_locales/ja/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "フィルタリングモード変更時にページを自動再読み込みする", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "ブロックしたリクエストの数をツールバーのアイコンに表示", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/ka/messages.json b/platform/mv3/extension/_locales/ka/messages.json index 298a736..c728583 100644 --- a/platform/mv3/extension/_locales/ka/messages.json +++ b/platform/mv3/extension/_locales/ka/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "გვერდის ავტომატური განახლება ფილტრაციის რეჟიმის შეცვლისას", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/kk/messages.json b/platform/mv3/extension/_locales/kk/messages.json index 627857e..4bbb5e3 100644 --- a/platform/mv3/extension/_locales/kk/messages.json +++ b/platform/mv3/extension/_locales/kk/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/kn/messages.json b/platform/mv3/extension/_locales/kn/messages.json index 627857e..30c578f 100644 --- a/platform/mv3/extension/_locales/kn/messages.json +++ b/platform/mv3/extension/_locales/kn/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "ಅನುಮತಿ-ಕಡಿಮೆ ವಿಷಯ ಬ್ಲಾಕರ್. ಅನುಸ್ಥಾಪನೆಯ ತಕ್ಷಣವೇ ಜಾಹೀರಾತುಗಳು, ಟ್ರ್ಯಾಕರ್‌ಗಳು, ಗಣಿಗಾರರು ಮತ್ತು ಹೆಚ್ಚಿನದನ್ನು ನಿರ್ಬಂಧಿಸುತ್ತದೆ.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -12,19 +12,19 @@ "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "dashboardName": { - "message": "uBO Lite — Dashboard", + "message": "\nಯುಬಿಒ ಲೈಟ್ - ಡ್ಯಾಶ್‌ಬೋರ್ಡ್\n", "description": "English: uBO Lite — Dashboard" }, "settingsPageName": { - "message": "Settings", + "message": "ಸಂಯೋಜನೆಗಳು", "description": "appears as tab name in dashboard" }, "aboutPageName": { - "message": "About", + "message": "ಬಗ್ಗೆ", "description": "appears as tab name in dashboard" }, "aboutPrivacyPolicy": { - "message": "Privacy policy", + "message": "ಗೌಪ್ಯತಾ ನೀತಿ\n", "description": "Link to privacy policy on GitHub (English)" }, "popupFilteringModeLabel": { @@ -32,27 +32,27 @@ "description": "Label in the popup panel for the current filtering mode" }, "popupTipDashboard": { - "message": "Open the dashboard", + "message": "ಡ್ಯಾಶ್‌ಬೋರ್ಡ್ ತೆರೆಯಿರಿ", "description": "English: Click to open the dashboard" }, "popupMoreButton": { - "message": "More", + "message": "ಇನ್ನಷ್ಟು", "description": "Label to be used to show popup panel sections" }, "popupLessButton": { - "message": "Less", + "message": "ಕಡಿಮೆ", "description": "Label to be used to hide popup panel sections" }, "3pGroupDefault": { - "message": "Default", + "message": "ಪೂರ್ವನಿಯೋಜಿತ", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAds": { - "message": "Ads", + "message": "ಜಾಹೀರಾತುಗಳು", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupPrivacy": { - "message": "Privacy", + "message": "ಗೌಪ್ಯತೆ", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMalware": { @@ -64,15 +64,15 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMisc": { - "message": "Miscellaneous", + "message": "ವಿವಿಧ", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupRegions": { - "message": "Regions, languages", + "message": "ಪ್ರದೇಶಗಳು, ಭಾಷೆಗಳು\n", "description": "Header for a ruleset section in 'Filter lists pane'" }, "aboutChangelog": { - "message": "Changelog", + "message": "ಬದಲಾವಣೆಗಳು", "description": "" }, "aboutCode": { @@ -84,15 +84,15 @@ "description": "English: Contributors" }, "aboutSourceCode": { - "message": "Source code", + "message": "ಮೂಲ ಕೊಡ್", "description": "Link text to source code repo" }, "aboutTranslations": { - "message": "Translations", + "message": "ಅನುವಾದ", "description": "Link text to translations repo" }, "aboutFilterLists": { - "message": "Filter lists", + "message": "ಫಿಲ್ಟರ್ ಪಟ್ಟಿಗಳು", "description": "Link text to uBO's own filter lists repo" }, "aboutDependencies": { @@ -100,7 +100,7 @@ "description": "Shown in the About pane" }, "firstRunSectionLabel": { - "message": "Welcome", + "message": "ಸ್ವಾಗತ", "description": "The header text for the welcome message section" }, "firstRunDescription": { @@ -120,7 +120,7 @@ "description": "Name of blocking mode 0" }, "filteringMode1Name": { - "message": "basic", + "message": "ಸಾಮಾನ್ಯ", "description": "Name of blocking mode 1" }, "filteringMode2Name": { @@ -128,7 +128,7 @@ "description": "Name of blocking mode 2" }, "filteringMode3Name": { - "message": "complete", + "message": "ಪೂರ್ಣ", "description": "Name of blocking mode 3" }, "basicFilteringModeDescription": { @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/ko/messages.json b/platform/mv3/extension/_locales/ko/messages.json index 5942fce..d066b63 100644 --- a/platform/mv3/extension/_locales/ko/messages.json +++ b/platform/mv3/extension/_locales/ko/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "필터링 모드를 변경할 때 페이지 자동 새로고침", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "차단된 요청 개수를 도구 모음 아이콘에 표시", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/lt/messages.json b/platform/mv3/extension/_locales/lt/messages.json index 0377c08..3f0bad8 100644 --- a/platform/mv3/extension/_locales/lt/messages.json +++ b/platform/mv3/extension/_locales/lt/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatiškai perkrauti sveitane keičiant filtro rėžimą", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/lv/messages.json b/platform/mv3/extension/_locales/lv/messages.json index bea58f2..a37ba6d 100644 --- a/platform/mv3/extension/_locales/lv/messages.json +++ b/platform/mv3/extension/_locales/lv/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Pārlādēt lapu pēc aizturēšanas veida nomaiņas.", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Rādīt aizturēto pieprasījumu skaitu rīkjoslas ikonā", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/mk/messages.json b/platform/mv3/extension/_locales/mk/messages.json index 0ef10c7..cb7631b 100644 --- a/platform/mv3/extension/_locales/mk/messages.json +++ b/platform/mv3/extension/_locales/mk/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/ml/messages.json b/platform/mv3/extension/_locales/ml/messages.json index d272672..2bffd1a 100644 --- a/platform/mv3/extension/_locales/ml/messages.json +++ b/platform/mv3/extension/_locales/ml/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "ഫിൽട്ടറിംഗ് മോഡ് മാറ്റുമ്പോൾ പേജ് സ്വയമേവ റീലോഡ് ചെയ്യുക", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/mr/messages.json b/platform/mv3/extension/_locales/mr/messages.json index 627857e..4bbb5e3 100644 --- a/platform/mv3/extension/_locales/mr/messages.json +++ b/platform/mv3/extension/_locales/mr/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/ms/messages.json b/platform/mv3/extension/_locales/ms/messages.json index 2128e9b..817a81f 100644 --- a/platform/mv3/extension/_locales/ms/messages.json +++ b/platform/mv3/extension/_locales/ms/messages.json @@ -4,15 +4,15 @@ "description": "extension name." }, "extShortDesc": { - "message": "A permission-less content blocker. Blocks ads, trackers, miners, and more immediately upon installation.", + "message": "Penyekat kandungan tanpa kebenaran. Menyekat iklan, penjejak, pelombong dan banyak lagi sebaik sahaja pemasangan.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { - "message": "{{ruleCount}} rules, converted from {{filterCount}} network filters", + "message": "Peraturan {{ruleCount}}, ditukar daripada penapis rangkaian {{filterCount}}.", "description": "Appears aside each filter list in the _3rd-party filters_ pane" }, "dashboardName": { - "message": "uBO Lite — Dashboard", + "message": "uBO Lite — Papan pemuka", "description": "English: uBO Lite — Dashboard" }, "settingsPageName": { @@ -28,11 +28,11 @@ "description": "Link to privacy policy on GitHub (English)" }, "popupFilteringModeLabel": { - "message": "filtering mode", + "message": "mod penapisan", "description": "Label in the popup panel for the current filtering mode" }, "popupTipDashboard": { - "message": "Open the dashboard", + "message": "Buka papan pemuka", "description": "English: Click to open the dashboard" }, "popupMoreButton": { @@ -60,7 +60,7 @@ "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupAnnoyances": { - "message": "Annoyances", + "message": "Kegusaran", "description": "Header for a ruleset section in 'Filter lists pane'" }, "3pGroupMisc": { @@ -104,15 +104,15 @@ "description": "The header text for the welcome message section" }, "firstRunDescription": { - "message": "You have just installed uBO Lite. Here you can choose the default filtering mode to use on all websites.\n\nBy default, Basic mode is selected because it does not require the permission to read and modify data. If you trust uBO Lite, you can give it broad permission to read and modify data on all websites in order to enable more advanced filtering capabilities for all websites by default.", + "message": "Anda baru sahaja memasang uBO Lite. Di sini anda boleh memilih mod penapisan lalai untuk digunakan pada semua tapak web.\n\nSecara lalai, mod Asas dipilih kerana ia tidak memerlukan kebenaran untuk membaca dan mengubah suai data. Jika anda mempercayai uBO Lite, anda boleh memberikannya kebenaran untuk membaca dan mengubah suai data pada semua tapak web untuk mendayakan keupayaan penapisan yang lebih maju untuk semua tapak web secara lalai.", "description": "Descriptive text shown at first install time only " }, "defaultFilteringModeSectionLabel": { - "message": "Default filtering mode", + "message": "Mod penapisan lalai", "description": "The header text for the default filtering mode section" }, "defaultFilteringModeDescription": { - "message": "The default filtering mode will be overridden by per-website filtering modes. You can adjust the filtering mode on any given website according to whichever mode works best on that website. Each mode has its advantages and disadvantages.", + "message": "Mod penapisan lalai akan ditindih oleh mod penapisan setiap tapak web. Anda boleh melaraskan mod penapisan pada mana-mana tapak web tertentu mengikut mana-mana mod yang paling berkesan pada tapak web tersebut. Setiap mod mempunyai kelebihan dan kekurangannya.", "description": "This describes the default filtering mode setting" }, "filteringMode0Name": { @@ -124,7 +124,7 @@ "description": "Name of blocking mode 1" }, "filteringMode2Name": { - "message": "optima", + "message": "optimum", "description": "Name of blocking mode 2" }, "filteringMode3Name": { @@ -132,19 +132,19 @@ "description": "Name of blocking mode 3" }, "basicFilteringModeDescription": { - "message": "Basic network filtering from selected filter lists.\n\nDoes not require permission to read and modify data on websites.", + "message": "Penapisan rangkaian asas daripada senarai penapis yang dipilih.\n\nTidak memerlukan kebenaran untuk membaca dan mengubah suai data pada tapak web.", "description": "This describes the 'basic' filtering mode" }, "optimalFilteringModeDescription": { - "message": "Advanced network filtering plus specific extended filtering from selected filter lists.\n\nRequires broad permission to read and modify data on all websites.", + "message": "Penapisan rangkaian lanjutan ditambah penapisan lanjutan khusus daripada senarai penapis yang dipilih.\n\nMemerlukan kebenaran untuk membaca dan mengubah suai data pada semua tapak web.", "description": "This describes the 'optimal' filtering mode" }, "completeFilteringModeDescription": { - "message": "Advanced network filtering plus specific and generic extended filtering from selected filter lists.\n\nRequires broad permission to read and modify data on all websites.\n\nGeneric extended filtering may cause higher webpage resources usage.", + "message": "Penapisan rangkaian lanjutan serta penapisan lanjutan khusus dan generik daripada senarai penapis yang dipilih.\n\nMemerlukan kebenaran untuk membaca dan mengubah suai data pada semua tapak web.\n\nPenapisan lanjutan generik boleh menyebabkan penggunaan sumber halaman web yang lebih tinggi.", "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "Senarai nama hos yang tiada penapisan akan berlaku", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -152,7 +152,11 @@ "description": "The header text for the 'Behavior' section" }, "autoReloadLabel": { - "message": "Automatically reload page when changing filtering mode", + "message": "Muat semula halaman secara automatik apabila menukar mod penapisan", + "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/nb/messages.json b/platform/mv3/extension/_locales/nb/messages.json index 5c47f65..4b0accf 100644 --- a/platform/mv3/extension/_locales/nb/messages.json +++ b/platform/mv3/extension/_locales/nb/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatisk last side på nytt ved endring av filtreringsmodus", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Vis antall blokkerte forespørsler på vertøyslinje-ikonet", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/nl/messages.json b/platform/mv3/extension/_locales/nl/messages.json index b83eeae..d73b801 100644 --- a/platform/mv3/extension/_locales/nl/messages.json +++ b/platform/mv3/extension/_locales/nl/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Pagina automatisch vernieuwen bij wijzigen van filtermodus", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Het aantal geblokkeerde aanvragen op het werkbalkpictogram tonen", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/oc/messages.json b/platform/mv3/extension/_locales/oc/messages.json index 627857e..4bbb5e3 100644 --- a/platform/mv3/extension/_locales/oc/messages.json +++ b/platform/mv3/extension/_locales/oc/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/pa/messages.json b/platform/mv3/extension/_locales/pa/messages.json index 753c355..868cc48 100644 --- a/platform/mv3/extension/_locales/pa/messages.json +++ b/platform/mv3/extension/_locales/pa/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "ਫਿਲਫਰ ਕਰਨ ਦਾ ਢੰਗ ਬਦਲਣ ਦੇ ਬਾਅਦ ਸਫ਼ੇ ਨੂੰ ਆਪਣੇ-ਆਪ ਲੋਡ ਕਰੋ", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/pl/messages.json b/platform/mv3/extension/_locales/pl/messages.json index 07c7543..1c7b89f 100644 --- a/platform/mv3/extension/_locales/pl/messages.json +++ b/platform/mv3/extension/_locales/pl/messages.json @@ -4,7 +4,7 @@ "description": "extension name." }, "extShortDesc": { - "message": "Eksperymentalny, niewymagający uprawnień bloker treści. Natychmiast po instalacji blokuje reklamy, moduły śledzące, koparki i nie tylko.", + "message": "Niewymagający uprawnień bloker treści. Natychmiast po instalacji blokuje reklamy, moduły śledzące, koparki i nie tylko.", "description": "this will be in the Chrome web store: must be 132 characters or less" }, "perRulesetStats": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatycznie wczytaj ponownie stronę po zmianie trybu filtrowania", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Wyświetlaj liczbę zablokowanych żądań na ikonie paska narzędzi", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/pt_BR/messages.json b/platform/mv3/extension/_locales/pt_BR/messages.json index cb4e978..e6265ef 100644 --- a/platform/mv3/extension/_locales/pt_BR/messages.json +++ b/platform/mv3/extension/_locales/pt_BR/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Recarregar a página automaticamente quando mudar o modo de filtragem", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Mostrar o número de solicitações bloqueadas no ícone da barra de ferramentas", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/pt_PT/messages.json b/platform/mv3/extension/_locales/pt_PT/messages.json index 4bd510a..511db27 100644 --- a/platform/mv3/extension/_locales/pt_PT/messages.json +++ b/platform/mv3/extension/_locales/pt_PT/messages.json @@ -140,11 +140,11 @@ "description": "This describes the 'optimal' filtering mode" }, "completeFilteringModeDescription": { - "message": "Filtragem de rede avançada mais filtragem alargada específica e genérica a partir de listas de filtros selecionadas.\n\nRequer ampla permissão para ler e modificar dados em todos os websites.\n\nA filtragem alargada genérica pode causar uma maior utilização de recursos das páginas web.", + "message": "Filtragem de rede avançada acrescida de filtragem alargada específica e genérica a partir de listas de filtros selecionadas.\n\nRequer permissão ampla para ler e modificar dados em todos os websites.\n\nA filtragem alargada genérica pode causar uma maior utilização de recursos das páginas web.", "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Lista de nomes de anfitriões para os quais não será efetuada qualquer filtragem", + "message": "Lista de nomes de anfitriões para os quais não será efetuada qualquer filtragem.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Recarrega automaticamente a página ao mudar o modo de filtragem", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Mostra o número de pedidos bloqueados no ícone da barra de ferramentas", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/ro/messages.json b/platform/mv3/extension/_locales/ro/messages.json index fb01a05..70f9bf6 100644 --- a/platform/mv3/extension/_locales/ro/messages.json +++ b/platform/mv3/extension/_locales/ro/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Reîncărcare automată a paginii la schimbarea modului de filtrare", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/ru/messages.json b/platform/mv3/extension/_locales/ru/messages.json index 0104b7c..f13511e 100644 --- a/platform/mv3/extension/_locales/ru/messages.json +++ b/platform/mv3/extension/_locales/ru/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Список имён хостов, для которых не будет производиться фильтрация", + "message": "Список имён хостов, для которых не будет производиться фильтрация.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Автоматически перезагружать страницу при изменении режима фильтрации", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Показывать количество заблокированных запросов на иконке в панели инструментов", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/si/messages.json b/platform/mv3/extension/_locales/si/messages.json index 627857e..4bbb5e3 100644 --- a/platform/mv3/extension/_locales/si/messages.json +++ b/platform/mv3/extension/_locales/si/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/sk/messages.json b/platform/mv3/extension/_locales/sk/messages.json index 997c759..91ebfc9 100644 --- a/platform/mv3/extension/_locales/sk/messages.json +++ b/platform/mv3/extension/_locales/sk/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "Zoznam názvov hostiteľov s vylúčeným filtrovaním", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automaticky znova načítať stránku pri zmene režimu filtrovania", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Zobraziť počet zablokovaných požiadaviek na ikone rozšírenia", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/sl/messages.json b/platform/mv3/extension/_locales/sl/messages.json index 627857e..4bbb5e3 100644 --- a/platform/mv3/extension/_locales/sl/messages.json +++ b/platform/mv3/extension/_locales/sl/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/so/messages.json b/platform/mv3/extension/_locales/so/messages.json index 627857e..4bbb5e3 100644 --- a/platform/mv3/extension/_locales/so/messages.json +++ b/platform/mv3/extension/_locales/so/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/sq/messages.json b/platform/mv3/extension/_locales/sq/messages.json index d390d8d..7b8c074 100644 --- a/platform/mv3/extension/_locales/sq/messages.json +++ b/platform/mv3/extension/_locales/sq/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Emrat e hosteve që nuk do të kalojnë në filtër", + "message": "Emrat e hosteve, që nuk do të kalojnë në filtër.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Freskoj automatikisht faqen kur ndryshoj mënyrën e filtrimit", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Shfaq numrin e kërkesave të bllokuara në ikonën e instrumenteve", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/sr/messages.json b/platform/mv3/extension/_locales/sr/messages.json index 0900785..5680a04 100644 --- a/platform/mv3/extension/_locales/sr/messages.json +++ b/platform/mv3/extension/_locales/sr/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Аутоматски поново учитај страницу при промени режима филтрирања", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Прикажи број блокираних захтева на иконици на траци алата", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/sv/messages.json b/platform/mv3/extension/_locales/sv/messages.json index fddcca5..5dcbfc9 100644 --- a/platform/mv3/extension/_locales/sv/messages.json +++ b/platform/mv3/extension/_locales/sv/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "Lista över värdnamn för vilka ingen filtrering kommer att äga rum", + "message": "Lista över värdnamn som inte kommer att filtreras", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Ladda automatiskt om sidan när du byter filtreringsläge", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Visa antalet blockerade förfrågningar på verktygsfältsikonen", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/sw/messages.json b/platform/mv3/extension/_locales/sw/messages.json index 627857e..4bbb5e3 100644 --- a/platform/mv3/extension/_locales/sw/messages.json +++ b/platform/mv3/extension/_locales/sw/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/ta/messages.json b/platform/mv3/extension/_locales/ta/messages.json index 627857e..4bbb5e3 100644 --- a/platform/mv3/extension/_locales/ta/messages.json +++ b/platform/mv3/extension/_locales/ta/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/te/messages.json b/platform/mv3/extension/_locales/te/messages.json index e263523..00008c2 100644 --- a/platform/mv3/extension/_locales/te/messages.json +++ b/platform/mv3/extension/_locales/te/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "ఫిల్టరింగ్ మోడ్‌ను మార్చేటప్పుడు పేజీని స్వయంచాలకంగా రీలోడ్ చేయండి", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/th/messages.json b/platform/mv3/extension/_locales/th/messages.json index 75f992a..8d523ba 100644 --- a/platform/mv3/extension/_locales/th/messages.json +++ b/platform/mv3/extension/_locales/th/messages.json @@ -88,7 +88,7 @@ "description": "Link text to source code repo" }, "aboutTranslations": { - "message": "การแปลภาษา", + "message": "แปล", "description": "Link text to translations repo" }, "aboutFilterLists": { @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/tr/messages.json b/platform/mv3/extension/_locales/tr/messages.json index b40f8a0..b4e4101 100644 --- a/platform/mv3/extension/_locales/tr/messages.json +++ b/platform/mv3/extension/_locales/tr/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Filtreleme modu değiştirildiğinde sayfayı yenile", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Engellenen isteklerin sayısını araç çubuğu simgesinde göster", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/uk/messages.json b/platform/mv3/extension/_locales/uk/messages.json index b48a9bb..5bf1a04 100644 --- a/platform/mv3/extension/_locales/uk/messages.json +++ b/platform/mv3/extension/_locales/uk/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Автоматично оновити сторінку при зміні режиму фільтрування", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Показувати кількість заблокованих запитів на піктограмі на панелі інструментів", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/ur/messages.json b/platform/mv3/extension/_locales/ur/messages.json index e66c4a9..2705d51 100644 --- a/platform/mv3/extension/_locales/ur/messages.json +++ b/platform/mv3/extension/_locales/ur/messages.json @@ -144,7 +144,7 @@ "description": "This describes the 'complete' filtering mode" }, "noFilteringModeDescription": { - "message": "List of hostnames for which no filtering will take place", + "message": "List of hostnames for which no filtering will take place.", "description": "A short description for the editable field which lists trusted sites" }, "behaviorSectionLabel": { @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Automatically reload page when changing filtering mode", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/vi/messages.json b/platform/mv3/extension/_locales/vi/messages.json index 6ecd8cb..2c6d1f0 100644 --- a/platform/mv3/extension/_locales/vi/messages.json +++ b/platform/mv3/extension/_locales/vi/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "Tự động tải lại trang khi thay đổi chế độ bộ lọc", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Hiện số lượng yêu cầu bị chặn trên biểu tượng thanh công cụ", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/zh_CN/messages.json b/platform/mv3/extension/_locales/zh_CN/messages.json index c11fdf7..793f3c8 100644 --- a/platform/mv3/extension/_locales/zh_CN/messages.json +++ b/platform/mv3/extension/_locales/zh_CN/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "更改过滤模式后自动刷新网页", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "Show the number of blocked requests on the toolbar icon", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/_locales/zh_TW/messages.json b/platform/mv3/extension/_locales/zh_TW/messages.json index 7825bd5..99ebc62 100644 --- a/platform/mv3/extension/_locales/zh_TW/messages.json +++ b/platform/mv3/extension/_locales/zh_TW/messages.json @@ -154,5 +154,9 @@ "autoReloadLabel": { "message": "變更過濾模式時自動重新載入頁面", "description": "Label for a checkbox in the options page" + }, + "showBlockedCountLabel": { + "message": "在工具列圖示上顯示被阻擋的連線請求的數量", + "description": "Label for a checkbox in the options page" } } diff --git a/platform/mv3/extension/css/settings.css b/platform/mv3/extension/css/settings.css index f03e276..2e727fc 100644 --- a/platform/mv3/extension/css/settings.css +++ b/platform/mv3/extension/css/settings.css @@ -22,6 +22,14 @@ p { white-space: pre-line; } +section > div { + padding: 0 var(--default-gap-xxsmall); + } + +#showBlockedCount:has(input[type="checkbox"][disabled]) { + opacity: 0.5; + } + #defaultFilteringMode { display: grid; gap: 1em; diff --git a/platform/mv3/extension/dashboard.html b/platform/mv3/extension/dashboard.html index 698e1fb..d2dc918 100644 --- a/platform/mv3/extension/dashboard.html +++ b/platform/mv3/extension/dashboard.html @@ -25,6 +25,13 @@
+
+

+

+

+

+

+

@@ -89,12 +96,6 @@

-
-

-

-

-
-

diff --git a/platform/mv3/extension/js/background.js b/platform/mv3/extension/js/background.js index 5ceacc4..e65775e 100644 --- a/platform/mv3/extension/js/background.js +++ b/platform/mv3/extension/js/background.js @@ -19,47 +19,43 @@ Home: https://github.com/gorhill/uBlock */ -/* jshint esversion:11 */ - -'use strict'; - /******************************************************************************/ import { + adminRead, browser, dnr, - runtime, localRead, localWrite, + runtime, sessionRead, sessionWrite, - adminRead, } from './ext.js'; import { - getRulesetDetails, + broadcastMessage, + ubolLog, +} from './utils.js'; + +import { defaultRulesetsFromLanguage, enableRulesets, getEnabledRulesetsDetails, + getRulesetDetails, updateDynamicRules, } from './ruleset-manager.js'; import { - registerInjectables, -} from './scripting-manager.js'; - -import { - getFilteringMode, - setFilteringMode, getDefaultFilteringMode, - setDefaultFilteringMode, + getFilteringMode, getTrustedSites, + setDefaultFilteringMode, + setFilteringMode, setTrustedSites, syncWithBrowserPermissions, } from './mode-manager.js'; import { - broadcastMessage, - ubolLog, -} from './utils.js'; + registerInjectables, +} from './scripting-manager.js'; /******************************************************************************/ @@ -67,10 +63,13 @@ const rulesetConfig = { version: '', enabledRulesets: [ 'default' ], autoReload: true, + showBlockedCount: true, }; const UBOL_ORIGIN = runtime.getURL('').replace(/\/$/, ''); +const canShowBlockedCount = typeof dnr.setExtensionActionOptions === 'function'; + let firstRun = false; let wakeupRun = false; @@ -85,7 +84,12 @@ async function loadRulesetConfig() { if ( data ) { rulesetConfig.version = data.version; rulesetConfig.enabledRulesets = data.enabledRulesets; - rulesetConfig.autoReload = data.autoReload && true || false; + rulesetConfig.autoReload = typeof data.autoReload === 'boolean' + ? data.autoReload + : true; + rulesetConfig.showBlockedCount = typeof data.showBlockedCount === 'boolean' + ? data.showBlockedCount + : true; wakeupRun = true; return; } @@ -93,7 +97,12 @@ async function loadRulesetConfig() { if ( data ) { rulesetConfig.version = data.version; rulesetConfig.enabledRulesets = data.enabledRulesets; - rulesetConfig.autoReload = data.autoReload && true || false; + rulesetConfig.autoReload = typeof data.autoReload === 'boolean' + ? data.autoReload + : true; + rulesetConfig.showBlockedCount = typeof data.showBlockedCount === 'boolean' + ? data.showBlockedCount + : true; sessionWrite('rulesetConfig', rulesetConfig); return; } @@ -201,6 +210,8 @@ function onMessage(request, sender, callback) { maxNumberOfEnabledRulesets: dnr.MAX_NUMBER_OF_ENABLED_STATIC_RULESETS, rulesetDetails: Array.from(rulesetDetails.values()), autoReload: rulesetConfig.autoReload, + showBlockedCount: rulesetConfig.showBlockedCount, + canShowBlockedCount, firstRun, }); firstRun = false; @@ -216,6 +227,19 @@ function onMessage(request, sender, callback) { }); return true; + case 'setShowBlockedCount': + rulesetConfig.showBlockedCount = request.state && true || false; + if ( canShowBlockedCount ) { + dnr.setExtensionActionOptions({ + displayActionCountAsBadgeText: rulesetConfig.showBlockedCount, + }); + } + saveRulesetConfig().then(( ) => { + callback(); + broadcastMessage({ showBlockedCount: rulesetConfig.showBlockedCount }); + }); + return true; + case 'popupPanelData': { Promise.all([ getFilteringMode(request.hostname), @@ -329,8 +353,10 @@ async function start() { // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/declarativeNetRequest // Firefox API does not support `dnr.setExtensionActionOptions` - if ( wakeupRun === false && dnr.setExtensionActionOptions ) { - dnr.setExtensionActionOptions({ displayActionCountAsBadgeText: true }); + if ( wakeupRun === false && canShowBlockedCount ) { + dnr.setExtensionActionOptions({ + displayActionCountAsBadgeText: rulesetConfig.showBlockedCount, + }); } runtime.onMessage.addListener(onMessage); diff --git a/platform/mv3/extension/js/mode-manager.js b/platform/mv3/extension/js/mode-manager.js index bc76199..e75dbee 100644 --- a/platform/mv3/extension/js/mode-manager.js +++ b/platform/mv3/extension/js/mode-manager.js @@ -288,34 +288,53 @@ async function writeFilteringModeDetails(afterDetails) { async function filteringModesToDNR(modes) { const dynamicRuleMap = await getDynamicRules(); - const presentRule = dynamicRuleMap.get(TRUSTED_DIRECTIVE_BASE_RULE_ID); + const presentRule = dynamicRuleMap.get(TRUSTED_DIRECTIVE_BASE_RULE_ID+0); const presentNone = new Set( presentRule && presentRule.condition.requestDomains ); if ( eqSets(presentNone, modes.none) ) { return; } const removeRuleIds = []; if ( presentRule !== undefined ) { - removeRuleIds.push(TRUSTED_DIRECTIVE_BASE_RULE_ID); - dynamicRuleMap.delete(TRUSTED_DIRECTIVE_BASE_RULE_ID); + removeRuleIds.push(TRUSTED_DIRECTIVE_BASE_RULE_ID+0); + removeRuleIds.push(TRUSTED_DIRECTIVE_BASE_RULE_ID+1); + dynamicRuleMap.delete(TRUSTED_DIRECTIVE_BASE_RULE_ID+0); + dynamicRuleMap.delete(TRUSTED_DIRECTIVE_BASE_RULE_ID+1); } const addRules = []; - if ( modes.none.size !== 0 ) { - const rule = { - id: TRUSTED_DIRECTIVE_BASE_RULE_ID, + const noneHostnames = [ ...modes.none ]; + const notNoneHostnames = [ ...modes.basic, ...modes.optimal, ...modes.complete ]; + if ( noneHostnames.length !== 0 ) { + const rule0 = { + id: TRUSTED_DIRECTIVE_BASE_RULE_ID+0, action: { type: 'allowAllRequests' }, condition: { resourceTypes: [ 'main_frame' ], }, priority: 100, }; - if ( - modes.none.size !== 1 || - modes.none.has('all-urls') === false - ) { - rule.condition.requestDomains = Array.from(modes.none); + if ( modes.none.has('all-urls') === false ) { + rule0.condition.requestDomains = noneHostnames.slice(); + } else if ( notNoneHostnames.length !== 0 ) { + rule0.condition.excludedRequestDomains = notNoneHostnames.slice(); } - addRules.push(rule); - dynamicRuleMap.set(TRUSTED_DIRECTIVE_BASE_RULE_ID, rule); + addRules.push(rule0); + dynamicRuleMap.set(TRUSTED_DIRECTIVE_BASE_RULE_ID+0, rule0); + // https://github.com/uBlockOrigin/uBOL-home/issues/114 + const rule1 = { + id: TRUSTED_DIRECTIVE_BASE_RULE_ID+1, + action: { type: 'allow' }, + condition: { + resourceTypes: [ 'script' ], + }, + priority: 100, + }; + if ( modes.none.has('all-urls') === false ) { + rule1.condition.initiatorDomains = noneHostnames.slice(); + } else if ( notNoneHostnames.length !== 0 ) { + rule1.condition.excludedInitiatorDomains = notNoneHostnames.slice(); + } + addRules.push(rule1); + dynamicRuleMap.set(TRUSTED_DIRECTIVE_BASE_RULE_ID+1, rule1); } const updateOptions = {}; if ( addRules.length ) { diff --git a/platform/mv3/extension/js/scripting/css-procedural.js b/platform/mv3/extension/js/scripting/css-procedural.js index 818e697..7f50f80 100644 --- a/platform/mv3/extension/js/scripting/css-procedural.js +++ b/platform/mv3/extension/js/scripting/css-procedural.js @@ -341,6 +341,38 @@ class PSelectorOthersTask extends PSelectorTask { /******************************************************************************/ +class PSelectorShadowTask extends PSelectorTask { + constructor(task) { + super(); + this.selector = task[1]; + } + transpose(node, output) { + const root = this.openOrClosedShadowRoot(node); + if ( root === null ) { return; } + const nodes = root.querySelectorAll(this.selector); + output.push(...nodes); + } + get openOrClosedShadowRoot() { + if ( PSelectorShadowTask.openOrClosedShadowRoot !== undefined ) { + return PSelectorShadowTask.openOrClosedShadowRoot; + } + if ( typeof chrome === 'object' && chrome !== null ) { + if ( chrome.dom instanceof Object ) { + if ( typeof chrome.dom.openOrClosedShadowRoot === 'function' ) { + PSelectorShadowTask.openOrClosedShadowRoot = + chrome.dom.openOrClosedShadowRoot; + return PSelectorShadowTask.openOrClosedShadowRoot; + } + } + } + PSelectorShadowTask.openOrClosedShadowRoot = node => + node.openOrClosedShadowRoot || null; + return PSelectorShadowTask.openOrClosedShadowRoot; + } +} + +/******************************************************************************/ + // https://github.com/AdguardTeam/ExtendedCss/issues/31#issuecomment-302391277 // Prepend `:scope ` if needed. class PSelectorSpathTask extends PSelectorTask { @@ -471,7 +503,6 @@ class PSelectorXpathTask extends PSelectorTask { class PSelector { constructor(o) { - this.raw = o.raw; this.selector = o.selector; this.tasks = []; const tasks = []; @@ -542,6 +573,7 @@ PSelector.prototype.operatorToTaskMap = new Map([ [ 'min-text-length', PSelectorMinTextLengthTask ], [ 'not', PSelectorIfNotTask ], [ 'others', PSelectorOthersTask ], + [ 'shadow', PSelectorShadowTask ], [ 'spath', PSelectorSpathTask ], [ 'upward', PSelectorUpwardTask ], [ 'watch-attr', PSelectorWatchAttrs ], @@ -566,6 +598,13 @@ class PSelectorRoot extends PSelector { } return []; } + exec(input) { + try { + return super.exec(input); + } catch (ex) { + } + return []; + } } /******************************************************************************/ diff --git a/platform/mv3/extension/js/settings.js b/platform/mv3/extension/js/settings.js index 1a95ac0..6f50055 100644 --- a/platform/mv3/extension/js/settings.js +++ b/platform/mv3/extension/js/settings.js @@ -19,11 +19,9 @@ Home: https://github.com/gorhill/uBlock */ -'use strict'; - -import { browser, sendMessage, localRead, localWrite } from './ext.js'; -import { i18n$, i18n } from './i18n.js'; +import { browser, localRead, localWrite, sendMessage } from './ext.js'; import { dom, qs$, qsa$ } from './dom.js'; +import { i18n, i18n$ } from './i18n.js'; import punycode from './punycode.js'; /******************************************************************************/ @@ -211,7 +209,17 @@ function renderWidgets() { renderDefaultMode(); renderTrustedSites(); - qs$('#autoReload input[type="checkbox"').checked = cachedRulesetData.autoReload; + qs$('#autoReload input[type="checkbox"]').checked = cachedRulesetData.autoReload; + + { + const input = qs$('#showBlockedCount input[type="checkbox"]'); + if ( cachedRulesetData.canShowBlockedCount ) { + input.checked = cachedRulesetData.showBlockedCount; + } else { + input.checked = false; + dom.attr(input, 'disabled', ''); + } + } // Compute total counts let rulesetCount = 0; @@ -290,13 +298,20 @@ dom.on( /******************************************************************************/ -dom.on('#autoReload input[type="checkbox"', 'change', ev => { +dom.on('#autoReload input[type="checkbox"]', 'change', ev => { sendMessage({ what: 'setAutoReload', state: ev.target.checked, }); }); +dom.on('#showBlockedCount input[type="checkbox"]', 'change', ev => { + sendMessage({ + what: 'setShowBlockedCount', + state: ev.target.checked, + }); +}); + /******************************************************************************/ function renderTrustedSites() { @@ -455,6 +470,13 @@ bc.onmessage = ev => { } } + if ( message.showBlockedCount !== undefined ) { + if ( message.showBlockedCount !== local.showBlockedCount ) { + local.showBlockedCount = message.showBlockedCount; + render = true; + } + } + if ( message.enabledRulesets !== undefined ) { if ( hashFromIterable(message.enabledRulesets) !== hashFromIterable(local.enabledRulesets) ) { local.enabledRulesets = message.enabledRulesets; diff --git a/platform/mv3/extension/js/utils.js b/platform/mv3/extension/js/utils.js index b1a463a..cadeaea 100644 --- a/platform/mv3/extension/js/utils.js +++ b/platform/mv3/extension/js/utils.js @@ -131,11 +131,22 @@ export const broadcastMessage = message => { /******************************************************************************/ const ubolLog = (...args) => { - // Do not pollute dev console in stable release. - if ( browser.runtime.id === 'ddkjiahejlhfcafbddmgiahcphecmpfh' ) { return; } + // Do not pollute dev console in stable releases. + if ( shouldLog !== true ) { return; } console.info('[uBOL]', ...args); }; +const shouldLog = (( ) => { + const { id } = browser.runtime; + // https://addons.mozilla.org/en-US/firefox/addon/ublock-origin-lite/ + if ( id === 'uBOLite@raymondhill.net' ) { return false; } + // https://chromewebstore.google.com/detail/ddkjiahejlhfcafbddmgiahcphecmpfh + if ( id === 'ddkjiahejlhfcafbddmgiahcphecmpfh' ) { return false; } + // https://microsoftedge.microsoft.com/addons/detail/cimighlppcgcoapaliogpjjdehbnofhn + if ( id === 'cimighlppcgcoapaliogpjjdehbnofhn' ) { return false; } + return true; +})(); + /******************************************************************************/ export { diff --git a/platform/mv3/make-rulesets.js b/platform/mv3/make-rulesets.js index 6b608bf..4f79d52 100644 --- a/platform/mv3/make-rulesets.js +++ b/platform/mv3/make-rulesets.js @@ -110,7 +110,7 @@ const urlToFileName = url => { ; }; -const fetchList = (url, cacheDir) => { +const fetchText = (url, cacheDir) => { return new Promise((resolve, reject) => { const fname = urlToFileName(url); fs.readFile(`${cacheDir}/${fname}`, { encoding: 'utf8' }).then(content => { @@ -168,7 +168,7 @@ const requiredRedirectResources = new Set(); /******************************************************************************/ -async function fetchAsset(assetDetails) { +async function fetchList(assetDetails) { // Remember fetched URLs const fetchedURLs = new Set(); @@ -190,7 +190,7 @@ async function fetchAsset(assetDetails) { newParts.push(`!#trusted on ${assetDetails.secret}`); } newParts.push( - fetchList(part.url, cacheDir).then(details => { + fetchText(part.url, cacheDir).then(details => { const { url } = details; const content = details.content.trim(); if ( typeof content === 'string' && content !== '' ) { @@ -227,10 +227,13 @@ const isRegex = rule => rule.condition !== undefined && rule.condition.regexFilter !== undefined; -const isRedirect = rule => - rule.action !== undefined && - rule.action.type === 'redirect' && - rule.action.redirect.extensionPath !== undefined; +const isRedirect = rule => { + if ( rule.action === undefined ) { return false; } + if ( rule.action.type !== 'redirect' ) { return false; } + if ( rule.action.redirect?.extensionPath !== undefined ) { return true; } + if ( rule.action.redirect?.transform?.path !== undefined ) { return true; } + return false; +}; const isModifyHeaders = rule => rule.action !== undefined && @@ -367,6 +370,14 @@ async function processNetworkFilters(assetDetails, network) { } } + // Add native DNR ruleset if present + if ( assetDetails.dnrURL ) { + const result = await fetchText(assetDetails.dnrURL, cacheDir); + for ( const rule of JSON.parse(result.content) ) { + rules.push(rule); + } + } + const plainGood = rules.filter(rule => isGood(rule) && isRegex(rule) === false); log(`\tPlain good: ${plainGood.length}`); log(plainGood @@ -384,6 +395,7 @@ async function processNetworkFilters(assetDetails, network) { isRedirect(rule) ); redirects.forEach(rule => { + if ( rule.action.redirect.extensionPath === undefined ) { return; } requiredRedirectResources.add( rule.action.redirect.extensionPath.replace(/^\/+/, '') ); @@ -979,11 +991,15 @@ async function rulesetFromURLs(assetDetails) { log(`Listset for '${assetDetails.id}':`); if ( assetDetails.text === undefined ) { - const text = await fetchAsset(assetDetails); + const text = await fetchList(assetDetails); if ( text === '' ) { return; } assetDetails.text = text; } + if ( Array.isArray(assetDetails.filters) ) { + assetDetails.text += '\n' + assetDetails.filters.join('\n'); + } + const extensionPaths = []; for ( const [ fname, details ] of redirectResourcesMap ) { const path = `/web_accessible_resources/${fname}`; @@ -1140,10 +1156,10 @@ async function main() { // Assemble all default lists as the default ruleset const contentURLs = [ 'https://ublockorigin.github.io/uAssets/filters/filters.min.txt', - 'https://ublockorigin.github.io/uAssets/filters/badware.txt', + 'https://ublockorigin.github.io/uAssets/filters/badware.min.txt', 'https://ublockorigin.github.io/uAssets/filters/privacy.min.txt', 'https://ublockorigin.github.io/uAssets/filters/unbreak.min.txt', - 'https://ublockorigin.github.io/uAssets/filters/quick-fixes.txt', + 'https://ublockorigin.github.io/uAssets/filters/quick-fixes.min.txt', 'https://ublockorigin.github.io/uAssets/filters/ubol-filters.txt', 'https://ublockorigin.github.io/uAssets/thirdparties/easylist.txt', 'https://ublockorigin.github.io/uAssets/thirdparties/easyprivacy.txt', @@ -1155,7 +1171,10 @@ async function main() { enabled: true, secret, urls: contentURLs, + dnrURL: 'https://ublockorigin.github.io/uAssets/dnr/default.json', homeURL: 'https://github.com/uBlockOrigin/uAssets', + filters: [ + ], }); // Regional rulesets @@ -1206,7 +1225,6 @@ async function main() { for ( const id of handpicked ) { const asset = assets[id]; if ( asset.content !== 'filters' ) { continue; } - const contentURL = Array.isArray(asset.contentURL) ? asset.contentURL[0] : asset.contentURL; @@ -1234,45 +1252,45 @@ async function main() { }); await rulesetFromURLs({ id: 'annoyances-overlays', - name: 'AdGuard/uBO – Overlays', + name: 'EasyList/uBO – Overlay Notices', group: 'annoyances', enabled: false, secret, urls: [ - 'https://filters.adtidy.org/extension/ublock/filters/19.txt', + 'https://ublockorigin.github.io/uAssets/thirdparties/easylist-newsletters.txt', 'https://ublockorigin.github.io/uAssets/filters/annoyances-others.txt', ], - homeURL: 'https://github.com/AdguardTeam/AdguardFilters#adguard-filters', + homeURL: 'https://github.com/easylist/easylist#fanboy-lists', }); await rulesetFromURLs({ id: 'annoyances-social', - name: 'AdGuard – Social Media', + name: 'EasyList – Social Widgets', group: 'annoyances', enabled: false, urls: [ - 'https://filters.adtidy.org/extension/ublock/filters/4.txt', + 'https://ublockorigin.github.io/uAssets/thirdparties/easylist-social.txt', ], - homeURL: 'https://github.com/AdguardTeam/AdguardFilters#adguard-filters', + homeURL: 'https://github.com/easylist/easylist#fanboy-lists', }); await rulesetFromURLs({ id: 'annoyances-widgets', - name: 'AdGuard – Widgets', + name: 'EasyList – Chat Widgets', group: 'annoyances', enabled: false, urls: [ - 'https://filters.adtidy.org/extension/ublock/filters/22.txt', + 'https://ublockorigin.github.io/uAssets/thirdparties/easylist-chat.txt', ], - homeURL: 'https://github.com/AdguardTeam/AdguardFilters#adguard-filters', + homeURL: 'https://github.com/easylist/easylist#fanboy-lists', }); await rulesetFromURLs({ id: 'annoyances-others', - name: 'AdGuard – Other Annoyances', + name: 'EasyList – Other Annoyances', group: 'annoyances', enabled: false, urls: [ - 'https://filters.adtidy.org/extension/ublock/filters/21.txt', + 'https://ublockorigin.github.io/uAssets/thirdparties/easylist-annoyances.txt' ], - homeURL: 'https://github.com/AdguardTeam/AdguardFilters#adguard-filters', + homeURL: 'https://github.com/easylist/easylist#fanboy-lists', }); // Handpicked rulesets from abroad diff --git a/platform/mv3/salvage-ruleids.mjs b/platform/mv3/salvage-ruleids.mjs new file mode 100644 index 0000000..f11d986 --- /dev/null +++ b/platform/mv3/salvage-ruleids.mjs @@ -0,0 +1,117 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2024-present Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see {http://www.gnu.org/licenses/}. + + Home: https://github.com/gorhill/uBlock +*/ + +'use strict'; + +/******************************************************************************/ + +import fs from 'fs/promises'; +import process from 'process'; + +/******************************************************************************/ + +const commandLineArgs = (( ) => { + const args = new Map(); + let name, value; + for ( const arg of process.argv.slice(2) ) { + const pos = arg.indexOf('='); + if ( pos === -1 ) { + name = arg; + value = ''; + } else { + name = arg.slice(0, pos); + value = arg.slice(pos+1); + } + args.set(name, value); + } + return args; +})(); + +const beforeDir = commandLineArgs.get('before') || ''; +const afterDir = commandLineArgs.get('after') || ''; + +if ( beforeDir === '' || afterDir === '' ) { + process.exit(0); +} + +/******************************************************************************/ + +async function main() { + const folders = [ + 'main', + 'modify-headers', + 'redirect', + 'regex', + 'removeparam', + ]; + const writePromises = []; + for ( const folder of folders ) { + const afterFiles = await fs.readdir(`${afterDir}/rulesets/${folder}`); + for ( const file of afterFiles ) { + let raw = await fs.readFile(`${beforeDir}/rulesets/${folder}/${file}`, 'utf-8').catch(( ) => ''); + let beforeRules; + try { beforeRules = JSON.parse(raw); } catch(_) { } + if ( Array.isArray(beforeRules) === false ) { continue; } + raw = await fs.readFile(`${afterDir}/rulesets/${folder}/${file}`, 'utf-8').catch(( ) => ''); + let afterRules; + try { afterRules = JSON.parse(raw); } catch(_) { } + if ( Array.isArray(afterRules) === false ) { continue; } + const beforeMap = new Map(beforeRules.map(a => { + const id = a.id; + a.id = 0; + return [ JSON.stringify(a), id ]; + })); + const reusedIds = new Set(); + for ( const afterRule of afterRules ) { + afterRule.id = 0; + const key = JSON.stringify(afterRule); + const beforeId = beforeMap.get(key); + if ( beforeId === undefined ) { continue; } + if ( reusedIds.has(beforeId) ) { continue; } + afterRule.id = beforeId; + reusedIds.add(beforeId); + } + // Assign new ids to unmatched rules + let ruleIdGenerator = 1; + for ( const afterRule of afterRules ) { + if ( afterRule.id !== 0 ) { continue; } + while ( reusedIds.has(ruleIdGenerator) ) { ruleIdGenerator += 1; } + afterRule.id = ruleIdGenerator++; + } + afterRules.sort((a, b) => a.id - b.id); + const indent = afterRules.length > 10 ? undefined : 1; + const lines = []; + for ( const afterRule of afterRules ) { + lines.push(JSON.stringify(afterRule, null, indent)); + } + const path = `${afterDir}/rulesets/${folder}/${file}`; + console.log(` Salvaged ${reusedIds.size} ids in ${folder}/${file}`); + writePromises.push( + fs.writeFile(path, `[\n${lines.join(',\n')}\n]\n`) + ); + } + } + await Promise.all(writePromises); +} + +main(); + +/******************************************************************************/ diff --git a/platform/mv3/scriptlets/scriptlet.template.js b/platform/mv3/scriptlets/scriptlet.template.js index b2c4ada..f5a4748 100644 --- a/platform/mv3/scriptlets/scriptlet.template.js +++ b/platform/mv3/scriptlets/scriptlet.template.js @@ -40,7 +40,7 @@ // Start of code to inject const uBOL_$scriptletName$ = function() { -const scriptletGlobals = new Map(); // jshint ignore: line +const scriptletGlobals = {}; // jshint ignore: line const argsList = self.$argsList$; diff --git a/platform/opera/manifest.json b/platform/opera/manifest.json index abc0bda..afaaad3 100644 --- a/platform/opera/manifest.json +++ b/platform/opera/manifest.json @@ -30,6 +30,9 @@ }, "toggle-cosmetic-filtering": { "description": "__MSG_toggleCosmeticFiltering__" + }, + "toggle-javascript": { + "description": "__MSG_toggleJavascript__" } }, "content_scripts": [ @@ -90,6 +93,7 @@ "name": "uBlock Origin", "options_page": "dashboard.html", "permissions": [ + "alarms", "contextMenus", "privacy", "storage", diff --git a/src/1p-filters.html b/src/1p-filters.html index bafa992..bc08479 100644 --- a/src/1p-filters.html +++ b/src/1p-filters.html @@ -22,15 +22,16 @@
- -

question-circle

-   +  

+

+
+