Add ability for scriptlets to share local data

Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/1741

As a result of the new capability, usage of RegExp API in `aost`
scriptlet has been shielded from the webpage tampering with the
API.
This commit is contained in:
Raymond Hill 2023-03-26 12:31:36 -04:00
parent c7c748862e
commit 5c9c87e485
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
2 changed files with 37 additions and 14 deletions

View File

@ -22,6 +22,9 @@
web page context.
*/
// Externally added to the private namespace in which scriptlets execute.
/* global sriptletGlobals */
'use strict';
export const builtinScriptlets = [];
@ -34,6 +37,25 @@ export const builtinScriptlets = [];
*******************************************************************************/
builtinScriptlets.push({
name: 'safe-self.fn',
fn: safeSelf,
});
function safeSelf() {
if ( sriptletGlobals.has('safeSelf') ) {
return sriptletGlobals.get('safeSelf');
}
const safe = {
'RegExp': self.RegExp,
'RegExp_test': self.RegExp.prototype.test,
'RegExp_exec': self.RegExp.prototype.exec,
};
sriptletGlobals.set('safeSelf', safe);
return safe;
}
/******************************************************************************/
builtinScriptlets.push({
name: 'pattern-to-regex.fn',
fn: patternToRegex,
@ -257,6 +279,7 @@ builtinScriptlets.push({
aliases: [ 'aost.js' ],
fn: abortOnStackTrace,
dependencies: [
'safe-self.fn',
'pattern-to-regex.fn',
'get-exception-token.fn',
],
@ -268,6 +291,7 @@ function abortOnStackTrace(
logLevel = ''
) {
if ( typeof chain !== 'string' ) { return; }
const safe = safeSelf();
const reNeedle = patternToRegex(needle);
const exceptionToken = getExceptionToken();
const log = console.log.bind(console);
@ -279,11 +303,12 @@ function abortOnStackTrace(
docURL = docURL.slice(0, pos);
}
// Normalize stack trace
const reLine = /(.*?@)?(\S+)(:\d+):\d+\)?$/;
const lines = [];
for ( let line of err.stack.split(/[\n\r]+/) ) {
if ( line.includes(exceptionToken) ) { continue; }
line = line.trim();
let match = /(.*?@)?(\S+)(:\d+):\d+\)?$/.exec(line);
let match = safe.RegExp_exec.call(reLine, line);
if ( match === null ) { continue; }
let url = match[2];
if ( url.startsWith('(') ) { url = url.slice(1); }
@ -301,7 +326,7 @@ function abortOnStackTrace(
}
lines[0] = `stackDepth:${lines.length-1}`;
const stack = lines.join('\t');
const r = reNeedle.test(stack);
const r = safe.RegExp_test.call(reNeedle, stack);
if (
logLevel === '1' ||
logLevel === '2' && r ||

View File

@ -379,22 +379,20 @@ scriptletFilteringEngine.retrieve = function(request, options = {}) {
if ( cacheDetails.code === '' ) { return; }
const out = [ cacheDetails.code ];
if ( µb.hiddenSettings.debugScriptlets ) {
out.unshift('debugger;');
}
out.unshift(
const out = [
'(function() {',
'// >>>> start of private namespace',
''
);
out.push(
'',
µb.hiddenSettings.debugScriptlets ? 'debugger;' : ';',
'',
// For use by scriptlets to share local data among themselves
'const sriptletGlobals = new Map();',
'',
cacheDetails.code,
'',
'// <<<< end of private namespace',
'})();'
);
'})();',
];
return out.join('\n');
};