[mv3] Use workaround to inject scriptlets in Firefox

Additionally:

Use `export UBO_VERSION=local` at the console to build MV3 extension using
current version of uBO code base. By default, the version is taken from
`./platform/mv3/ubo-version' and usually set to last stable release.
This commit is contained in:
Raymond Hill 2023-08-11 13:22:25 -04:00
parent 5ec0550581
commit bb41d9594f
No known key found for this signature in database
GPG key ID: 25E1490B761470C2
7 changed files with 89 additions and 21 deletions

View file

@ -417,10 +417,6 @@ function registerSpecific(context) {
/******************************************************************************/
function registerScriptlet(context, scriptletDetails) {
// https://bugzilla.mozilla.org/show_bug.cgi?id=1736575
// `MAIN` world not yet supported in Firefox
if ( isGecko ) { return; }
const { before, filteringModeDetails, rulesetsDetails } = context;
const hasBroadHostPermission =
@ -476,9 +472,14 @@ function registerScriptlet(context, scriptletDetails) {
matches,
excludeMatches,
runAt: 'document_start',
world: 'MAIN',
};
// https://bugzilla.mozilla.org/show_bug.cgi?id=1736575
// `MAIN` world not yet supported in Firefox
if ( isGecko === false ) {
directive.world = 'MAIN';
}
// register
if ( registered === undefined ) {
context.toAdd.push(directive);

View file

@ -485,8 +485,13 @@ class PSelector {
prime(input) {
const root = input || document;
if ( this.selector === '' ) { return [ root ]; }
if ( input !== document && /^ [>+~]/.test(this.selector) ) {
return Array.from(PSelectorSpathTask.qsa(input, this.selector));
if ( input !== document ) {
const c0 = this.selector.charCodeAt(0);
if ( c0 === 0x2B /* + */ || c0 === 0x7E /* ~ */ ) {
return Array.from(PSelectorSpathTask.qsa(input, this.selector));
} else if ( c0 === 0x3E /* > */ ) {
return Array.from(input.querySelectorAll(`:scope ${this.selector}`));
}
}
return Array.from(root.querySelectorAll(this.selector));
}

View file

@ -53,19 +53,23 @@ const commandLineArgs = (( ) => {
return args;
})();
const platform = commandLineArgs.get('platform') || 'chromium';
const outputDir = commandLineArgs.get('output') || '.';
const cacheDir = `${outputDir}/../mv3-data`;
const rulesetDir = `${outputDir}/rulesets`;
const scriptletDir = `${rulesetDir}/scripting`;
const env = [
'chromium',
platform,
'mv3',
'native_css_has',
'ublock',
'ubol',
'user_stylesheet',
];
if ( platform !== 'firefox' ) {
env.push('native_css_has');
}
/******************************************************************************/
const jsonSetMapReplacer = (k, v) => {
@ -1222,7 +1226,7 @@ async function main() {
resources: Array.from(requiredRedirectResources).map(path => `/${path}`),
matches: [ '<all_urls>' ],
};
if ( commandLineArgs.get('platform') === 'chromium' ) {
if ( platform === 'chromium' ) {
web_accessible_resources.use_dynamic_url = true;
}
manifest.web_accessible_resources = [ web_accessible_resources ];

View file

@ -167,7 +167,7 @@ export async function commit(rulesetId, path, writeFn) {
content = safeReplace(content, /\$scriptletName\$/, details.name, 0);
content = safeReplace(content,
'self.$argsList$',
JSON.stringify(Array.from(details.args.keys()))
JSON.stringify(Array.from(details.args.keys()).map(a => JSON.parse(a)))
);
content = safeReplace(content,
'self.$hostnamesMap$',

View file

@ -21,6 +21,7 @@
*/
/* jshint esversion:11 */
/* global cloneInto */
'use strict';
@ -31,10 +32,14 @@
// Important!
// Isolate from global scope
(function uBOL_$scriptletName$() {
// Start of local scope
(( ) => {
/******************************************************************************/
// Start of injected code
const uBOL_$scriptletName$ = function() {
const scriptletGlobals = new Map(); // jshint ignore: line
const argsList = self.$argsList$;
@ -109,13 +114,58 @@ if ( entitiesMap.size !== 0 ) {
// Apply scriplets
for ( const i of todoIndices ) {
try { $scriptletName$(...JSON.parse(argsList[i])); }
try { $scriptletName$(...argsList[i]); }
catch(ex) {}
}
argsList.length = 0;
/******************************************************************************/
};
// End of injected code
/******************************************************************************/
// Inject code
// https://bugzilla.mozilla.org/show_bug.cgi?id=1736575
// `MAIN` world not yet supported in Firefox, so we inject the code into
// 'MAIN' ourself when enviroment in Firefox.
// Not Firefox
if ( typeof wrappedJSObject !== 'object' ) {
return uBOL_$scriptletName$();
}
// Firefox
{
const page = self.wrappedJSObject;
let script, url;
try {
page.uBOL_$scriptletName$ = cloneInto([
[ '(', uBOL_$scriptletName$.toString(), ')();' ],
{ type: 'text/javascript; charset=utf-8' },
], self);
const blob = new page.Blob(...page.uBOL_$scriptletName$);
url = page.URL.createObjectURL(blob);
const doc = page.document;
script = doc.createElement('script');
script.async = false;
script.src = url;
(doc.head || doc.documentElement || doc).append(script);
} catch (ex) {
console.error(ex);
}
if ( url ) {
if ( script ) { script.remove(); }
page.URL.revokeObjectURL(url);
}
delete page.uBOL_$scriptletName$;
}
/******************************************************************************/
// End of local scope
})();
/******************************************************************************/

View file

@ -378,8 +378,13 @@ class PSelector {
prime(input) {
const root = input || document;
if ( this.selector === '' ) { return [ root ]; }
if ( input !== document && /^ ?[>+~]/.test(this.selector) ) {
return Array.from(PSelectorSpathTask.qsa(input, this.selector));
if ( input !== document ) {
const c0 = this.selector.charCodeAt(0);
if ( c0 === 0x2B /* + */ || c0 === 0x7E /* ~ */ ) {
return Array.from(PSelectorSpathTask.qsa(input, this.selector));
} else if ( c0 === 0x3E /* > */ ) {
return Array.from(input.querySelectorAll(`:scope ${this.selector}`));
}
}
return Array.from(root.querySelectorAll(this.selector));
}

View file

@ -35,7 +35,6 @@ if [ "$QUICK" != "yes" ]; then
rm -rf $DES
fi
mkdir -p $DES
cd $DES
DES=$(pwd)
@ -45,11 +44,15 @@ mkdir -p $DES/css/fonts
mkdir -p $DES/js
mkdir -p $DES/img
UBO_DIR=$(mktemp -d)
UBO_REPO="https://github.com/gorhill/uBlock.git"
UBO_VERSION=$(cat platform/mv3/ubo-version)
echo "*** uBOLite.mv3: Fetching uBO $UBO_VERSION from $UBO_REPO into $UBO_DIR"
git clone -q --depth 1 --branch "$UBO_VERSION" "$UBO_REPO" "$UBO_DIR"
if [ "$UBO_VERSION" != "local" ]; then
UBO_VERSION=$(cat platform/mv3/ubo-version)
UBO_REPO="https://github.com/gorhill/uBlock.git"
UBO_DIR=$(mktemp -d)
echo "*** uBOLite.mv3: Fetching uBO $UBO_VERSION from $UBO_REPO into $UBO_DIR"
git clone -q --depth 1 --branch "$UBO_VERSION" "$UBO_REPO" "$UBO_DIR"
else
UBO_DIR=.
fi
echo "*** uBOLite.mv3: Copying common files"
cp -R $UBO_DIR/src/css/fonts/* $DES/css/fonts/