From f5ff04201c8dd3c5bb1954096a52d36eea7814c1 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Fri, 31 Mar 2023 13:23:46 -0700 Subject: [PATCH 1/5] update code to support new uBlock Origin scriptlets format --- lib/adBlockRustUtils.js | 52 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/lib/adBlockRustUtils.js b/lib/adBlockRustUtils.js index 561a83b5..153aec66 100644 --- a/lib/adBlockRustUtils.js +++ b/lib/adBlockRustUtils.js @@ -47,14 +47,62 @@ const lazyInit = (fn) => { } } +// Wraps new template scriptlets with the older "numbered template arg" format and any required dependency code +const wrapScriptletArgFormat = (fnString, dependencyPrelude) => `{ + const args = ['{{1}}', '{{2}}', '{{3}}', '{{4}}', '{{5}}', '{{6}}', '{{7}}', '{{8}}', '{{9}}']; + let last_arg_index = 0; + for (const arg_index in args) { + if (args[arg_index] === '{{' + (Number(arg_index) + 1) + '}}') { + break; + } + last_arg_index += 1; + } + ${dependencyPrelude} + (${fnString})(...args.slice(0, last_arg_index)) +}` + const generateResources = lazyInit(async () => { + const { builtinScriptlets } = await import(path.join('..', uBlockScriptlets).toString()) + + const dependencyFns = builtinScriptlets.filter(s => s.name.endsWith('.fn')) + // Assumption: dependency functions don't have any dependencies themselves + if (!dependencyFns.every(f => f.dependencies === undefined)) { + throw new Error('Recursive dependencies detected') + } + const dependencyMap = dependencyFns.reduce((map, entry) => { + map[entry.name] = entry + return map + }, {}) + + const transformedUboBuiltins = builtinScriptlets.filter(s => !s.name.endsWith('.fn')).map(s => { + // Bundle dependencies wherever needed. This causes some small duplication but makes each scriptlet fully self-contained. + let dependencyPrelude = '' + if (s.dependencies !== undefined) { + for (const dep of s.dependencies) { + const thisDepCode = dependencyMap[dep].fn.toString() + if (thisDepCode === undefined) { + throw new Error(`Couldn't find dependency ${dep}`) + } + dependencyPrelude += thisDepCode + '\n' + } + } + const content = Buffer.from(wrapScriptletArgFormat(s.fn.toString(), dependencyPrelude)).toString('base64') + return { + name: s.name, + aliases: s.aliases ?? [], + kind: { mime: 'application/javascript' }, + content + } + }) + const resourceData = uBlockResources( uBlockWebAccessibleResources, - uBlockRedirectEngine, - uBlockScriptlets + uBlockRedirectEngine ) + const braveResources = await requestJSON(braveResourcesUrl) resourceData.push(...braveResources) + resourceData.push(...transformedUboBuiltins) return JSON.stringify(resourceData) }) From e9b79d5a78e7d666b0fdbcc3e625b420c42b9434 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Fri, 31 Mar 2023 18:18:36 -0700 Subject: [PATCH 2/5] bump uBO submodule version --- submodules/uBlock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/uBlock b/submodules/uBlock index 0d9e8d58..2b4ef63c 160000 --- a/submodules/uBlock +++ b/submodules/uBlock @@ -1 +1 @@ -Subproject commit 0d9e8d58f1eada6ebc3a67449f4e2fb039f02a7f +Subproject commit 2b4ef63caeb2ec0ee58d8e6f270270c966c89d18 From 953fd3f29a90f9246ab7ae0333a3e908a2a8cf90 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Tue, 30 May 2023 16:08:42 -0700 Subject: [PATCH 3/5] support recursive deps and filter out deps with trust or world requirements --- lib/adBlockRustUtils.js | 25 ++++++++++++++----------- submodules/uBlock | 2 +- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/adBlockRustUtils.js b/lib/adBlockRustUtils.js index 153aec66..5f96bef6 100644 --- a/lib/adBlockRustUtils.js +++ b/lib/adBlockRustUtils.js @@ -65,27 +65,30 @@ const generateResources = lazyInit(async () => { const { builtinScriptlets } = await import(path.join('..', uBlockScriptlets).toString()) const dependencyFns = builtinScriptlets.filter(s => s.name.endsWith('.fn')) - // Assumption: dependency functions don't have any dependencies themselves - if (!dependencyFns.every(f => f.dependencies === undefined)) { - throw new Error('Recursive dependencies detected') - } const dependencyMap = dependencyFns.reduce((map, entry) => { map[entry.name] = entry return map }, {}) - const transformedUboBuiltins = builtinScriptlets.filter(s => !s.name.endsWith('.fn')).map(s => { + // ignore "trusted" scriptlets and scriptlets with execution world requirements for now + const transformedUboBuiltins = builtinScriptlets.filter(s => !s.name.endsWith('.fn') && !s.requiresTrust && s.world === undefined).map(s => { // Bundle dependencies wherever needed. This causes some small duplication but makes each scriptlet fully self-contained. let dependencyPrelude = '' - if (s.dependencies !== undefined) { - for (const dep of s.dependencies) { - const thisDepCode = dependencyMap[dep].fn.toString() - if (thisDepCode === undefined) { - throw new Error(`Couldn't find dependency ${dep}`) + const requiredDependencies = s.dependencies ?? [] + for (const dep of requiredDependencies) { + for (const recursiveDep of dependencyMap[dep].dependencies ?? []) { + if (!requiredDependencies.includes(recursiveDep)) { + requiredDependencies.push(recursiveDep) } - dependencyPrelude += thisDepCode + '\n' } } + for (const dep of requiredDependencies.reverse()) { + const thisDepCode = dependencyMap[dep].fn.toString() + if (thisDepCode === undefined) { + throw new Error(`Couldn't find dependency ${dep}`) + } + dependencyPrelude += thisDepCode + '\n' + } const content = Buffer.from(wrapScriptletArgFormat(s.fn.toString(), dependencyPrelude)).toString('base64') return { name: s.name, diff --git a/submodules/uBlock b/submodules/uBlock index 2b4ef63c..510f0872 160000 --- a/submodules/uBlock +++ b/submodules/uBlock @@ -1 +1 @@ -Subproject commit 2b4ef63caeb2ec0ee58d8e6f270270c966c89d18 +Subproject commit 510f08720d77c5ae4b0f7d8b1ca02552cc372dfd From 8edd6d2a64e091d1439240c03dd0000d3e5249a0 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Thu, 29 Jun 2023 14:50:00 -0700 Subject: [PATCH 4/5] further update uBO --- submodules/uBlock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/uBlock b/submodules/uBlock index 510f0872..5d119378 160000 --- a/submodules/uBlock +++ b/submodules/uBlock @@ -1 +1 @@ -Subproject commit 510f08720d77c5ae4b0f7d8b1ca02552cc372dfd +Subproject commit 5d1193783543abfc5196937a48f9307644a3a2d2 From 19ec61b90243032f9a8371d17c0f6a33cf5cc6f6 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Thu, 29 Jun 2023 17:42:49 -0700 Subject: [PATCH 5/5] ignore world argument, and fully sync uBO resources `world` is used specifically for Mv3, which is not a concern for Brave. --- lib/adBlockRustUtils.js | 4 ++-- submodules/uBlock | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/adBlockRustUtils.js b/lib/adBlockRustUtils.js index 5f96bef6..3fe9eb12 100644 --- a/lib/adBlockRustUtils.js +++ b/lib/adBlockRustUtils.js @@ -70,8 +70,8 @@ const generateResources = lazyInit(async () => { return map }, {}) - // ignore "trusted" scriptlets and scriptlets with execution world requirements for now - const transformedUboBuiltins = builtinScriptlets.filter(s => !s.name.endsWith('.fn') && !s.requiresTrust && s.world === undefined).map(s => { + // ignore "trusted" scriptlets for now + const transformedUboBuiltins = builtinScriptlets.filter(s => !s.name.endsWith('.fn') && !s.requiresTrust).map(s => { // Bundle dependencies wherever needed. This causes some small duplication but makes each scriptlet fully self-contained. let dependencyPrelude = '' const requiredDependencies = s.dependencies ?? [] diff --git a/submodules/uBlock b/submodules/uBlock index 5d119378..99752749 160000 --- a/submodules/uBlock +++ b/submodules/uBlock @@ -1 +1 @@ -Subproject commit 5d1193783543abfc5196937a48f9307644a3a2d2 +Subproject commit 99752749880493f6890e47dd0b992c71698cbc2f