From 0c56103a40124eb8b7ac8d6b8d0b7c04b4a4e05d Mon Sep 17 00:00:00 2001 From: ryanbr Date: Thu, 20 Aug 2026 17:05:47 +1200 Subject: [PATCH] Add `env_brave` preparser token Brave can't be told apart from Chrome through the user agent string, so detection uses `navigator.brave` with `navigator.userAgentData.brands` as fallback. Both are synchronous, unlike `navigator.brave.isBrave()` -- the flavor must be settled before filter lists are compiled and cached. Brave still offers uBO in MV2, and a considerable number of Brave users run Brave Shields and uBO at the same time. Filters which are safe on their own can conflict when both blockers apply them, and list maintainers currently have no way to express that: https://github.com/uBlockOrigin/uAssets/pull/34162 --- platform/common/vapi-common.js | 12 ++++++++++++ src/js/static-filtering-parser.js | 2 ++ 2 files changed, 14 insertions(+) diff --git a/platform/common/vapi-common.js b/platform/common/vapi-common.js index 65e0c93c5c048..eafb02c425198 100644 --- a/platform/common/vapi-common.js +++ b/platform/common/vapi-common.js @@ -197,6 +197,18 @@ vAPI.webextFlavor = { .add('user_stylesheet'); } flavor.major = match && parseInt(match[1], 10) || 120; + // Brave can't be told apart through the user agent string, which is + // identical to Chrome's. Both tests below are synchronous, whereas + // navigator.brave.isBrave() is promise-based -- the flavor must be + // settled before filter lists are compiled and cached. Either test + // alone would do, the second one is a fallback for the first. + // https://github.com/brave/brave-browser/wiki/Detecting-Brave-(for-Websites) + if ( + navigator.brave instanceof Object || + navigator.userAgentData?.brands?.some(a => a.brand === 'Brave') + ) { + soup.add('brave'); + } } // Don't starve potential listeners diff --git a/src/js/static-filtering-parser.js b/src/js/static-filtering-parser.js index 5429d423d5f8d..d2a1af2f96363 100644 --- a/src/js/static-filtering-parser.js +++ b/src/js/static-filtering-parser.js @@ -604,6 +604,7 @@ export const preparserIfTokens = new Set([ 'ext_ublock', 'ext_ubol', 'ext_devbuild', + 'env_brave', 'env_chromium', 'env_edge', 'env_firefox', @@ -4230,6 +4231,7 @@ export const utils = (( ) => { [ 'ext_ublock', 'ublock' ], [ 'ext_ubol', 'ubol' ], [ 'ext_devbuild', 'devbuild' ], + [ 'env_brave', 'brave' ], [ 'env_chromium', 'chromium' ], [ 'env_edge', 'edge' ], [ 'env_firefox', 'firefox' ],