mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-10 01:02:08 +01:00
Add scriptlet dependencies to reduce code duplication
This commit is contained in:
parent
439951824a
commit
236fb3ad59
3 changed files with 546 additions and 605 deletions
|
@ -26,11 +26,64 @@
|
||||||
|
|
||||||
export const builtinScriptlets = [];
|
export const builtinScriptlets = [];
|
||||||
|
|
||||||
/// abort-current-script.js
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Helper functions
|
||||||
|
|
||||||
|
These are meant to be used as dependencies to injectable scriptlets.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
builtinScriptlets.push({
|
||||||
|
name: 'pattern-to-regex.fn',
|
||||||
|
fn: patternToRegex,
|
||||||
|
});
|
||||||
|
function patternToRegex(pattern) {
|
||||||
|
if ( pattern === '' ) {
|
||||||
|
return /^/;
|
||||||
|
}
|
||||||
|
if ( pattern.startsWith('/') && pattern.endsWith('/') ) {
|
||||||
|
return new RegExp(pattern.slice(1, -1));
|
||||||
|
}
|
||||||
|
return new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
builtinScriptlets.push({
|
||||||
|
name: 'get-exception-token.fn',
|
||||||
|
fn: getExceptionToken,
|
||||||
|
});
|
||||||
|
function getExceptionToken() {
|
||||||
|
const token =
|
||||||
|
String.fromCharCode(Date.now() % 26 + 97) +
|
||||||
|
Math.floor(Math.random() * 982451653 + 982451653).toString(36);
|
||||||
|
const oe = self.onerror;
|
||||||
|
self.onerror = function(msg, ...args) {
|
||||||
|
if ( typeof msg === 'string' && msg.includes(token) ) { return true; }
|
||||||
|
if ( oe instanceof Function ) {
|
||||||
|
return oe.call(this, msg, ...args);
|
||||||
|
}
|
||||||
|
}.bind();
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
|
||||||
|
Injectable scriptlets
|
||||||
|
|
||||||
|
These are meant to be used in the MAIN (webpage) execution world.
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'abort-current-script.js',
|
name: 'abort-current-script.js',
|
||||||
aliases: [ 'acs.js', 'abort-current-inline-script.js', 'acis.js' ],
|
aliases: [ 'acs.js', 'abort-current-inline-script.js', 'acis.js' ],
|
||||||
fn: abortCurrentScript,
|
fn: abortCurrentScript,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
'get-exception-token.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
// Issues to mind before changing anything:
|
// Issues to mind before changing anything:
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/2154
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/2154
|
||||||
|
@ -41,21 +94,8 @@ function abortCurrentScript(
|
||||||
) {
|
) {
|
||||||
if ( typeof target !== 'string' ) { return; }
|
if ( typeof target !== 'string' ) { return; }
|
||||||
if ( target === '' ) { return; }
|
if ( target === '' ) { return; }
|
||||||
const reRegexEscape = /[.*+?^${}()|[\]\\]/g;
|
const reNeedle = patternToRegex(needle);
|
||||||
const reNeedle = (( ) => {
|
const reContext = patternToRegex(context);
|
||||||
if ( needle === '' ) { return /^/; }
|
|
||||||
if ( /^\/.+\/$/.test(needle) ) {
|
|
||||||
return new RegExp(needle.slice(1,-1));
|
|
||||||
}
|
|
||||||
return new RegExp(needle.replace(reRegexEscape, '\\$&'));
|
|
||||||
})();
|
|
||||||
const reContext = (( ) => {
|
|
||||||
if ( context === '' ) { return; }
|
|
||||||
if ( /^\/.+\/$/.test(context) ) {
|
|
||||||
return new RegExp(context.slice(1,-1));
|
|
||||||
}
|
|
||||||
return new RegExp(context.replace(reRegexEscape, '\\$&'));
|
|
||||||
})();
|
|
||||||
const thisScript = document.currentScript;
|
const thisScript = document.currentScript;
|
||||||
const chain = target.split('.');
|
const chain = target.split('.');
|
||||||
let owner = window;
|
let owner = window;
|
||||||
|
@ -75,8 +115,7 @@ function abortCurrentScript(
|
||||||
value = owner[prop];
|
value = owner[prop];
|
||||||
desc = undefined;
|
desc = undefined;
|
||||||
}
|
}
|
||||||
const magic = String.fromCharCode(Date.now() % 26 + 97) +
|
const exceptionToken = getExceptionToken();
|
||||||
Math.floor(Math.random() * 982451653 + 982451653).toString(36);
|
|
||||||
const scriptTexts = new WeakMap();
|
const scriptTexts = new WeakMap();
|
||||||
const getScriptText = elem => {
|
const getScriptText = elem => {
|
||||||
let text = elem.textContent;
|
let text = elem.textContent;
|
||||||
|
@ -103,11 +142,9 @@ function abortCurrentScript(
|
||||||
const e = document.currentScript;
|
const e = document.currentScript;
|
||||||
if ( e instanceof HTMLScriptElement === false ) { return; }
|
if ( e instanceof HTMLScriptElement === false ) { return; }
|
||||||
if ( e === thisScript ) { return; }
|
if ( e === thisScript ) { return; }
|
||||||
if ( reContext !== undefined && reContext.test(e.src) === false ) {
|
if ( reContext.test(e.src) === false ) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ( reNeedle.test(getScriptText(e)) === false ) { return; }
|
if ( reNeedle.test(getScriptText(e)) === false ) { return; }
|
||||||
throw new ReferenceError(magic);
|
throw new ReferenceError(exceptionToken);
|
||||||
};
|
};
|
||||||
Object.defineProperty(owner, prop, {
|
Object.defineProperty(owner, prop, {
|
||||||
get: function() {
|
get: function() {
|
||||||
|
@ -125,33 +162,26 @@ function abortCurrentScript(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const oe = window.onerror;
|
|
||||||
window.onerror = function(msg) {
|
|
||||||
if ( typeof msg === 'string' && msg.includes(magic) ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ( oe instanceof Function ) {
|
|
||||||
return oe.apply(this, arguments);
|
|
||||||
}
|
|
||||||
}.bind();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// abort-on-property-read.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'abort-on-property-read.js',
|
name: 'abort-on-property-read.js',
|
||||||
aliases: [ 'aopr.js' ],
|
aliases: [ 'aopr.js' ],
|
||||||
fn: abortOnPropertyRead,
|
fn: abortOnPropertyRead,
|
||||||
|
dependencies: [
|
||||||
|
'get-exception-token.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
function abortOnPropertyRead(
|
function abortOnPropertyRead(
|
||||||
chain = ''
|
chain = ''
|
||||||
) {
|
) {
|
||||||
if ( typeof chain !== 'string' ) { return; }
|
if ( typeof chain !== 'string' ) { return; }
|
||||||
if ( chain === '' ) { return; }
|
if ( chain === '' ) { return; }
|
||||||
const magic = String.fromCharCode(Date.now() % 26 + 97) +
|
const exceptionToken = getExceptionToken();
|
||||||
Math.floor(Math.random() * 982451653 + 982451653).toString(36);
|
|
||||||
const abort = function() {
|
const abort = function() {
|
||||||
throw new ReferenceError(magic);
|
throw new ReferenceError(exceptionToken);
|
||||||
};
|
};
|
||||||
const makeProxy = function(owner, chain) {
|
const makeProxy = function(owner, chain) {
|
||||||
const pos = chain.indexOf('.');
|
const pos = chain.indexOf('.');
|
||||||
|
@ -186,31 +216,24 @@ function abortOnPropertyRead(
|
||||||
};
|
};
|
||||||
const owner = window;
|
const owner = window;
|
||||||
makeProxy(owner, chain);
|
makeProxy(owner, chain);
|
||||||
const oe = window.onerror;
|
|
||||||
window.onerror = function(msg, src, line, col, error) {
|
|
||||||
if ( typeof msg === 'string' && msg.indexOf(magic) !== -1 ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ( oe instanceof Function ) {
|
|
||||||
return oe(msg, src, line, col, error);
|
|
||||||
}
|
|
||||||
}.bind();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// abort-on-property-write.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'abort-on-property-write.js',
|
name: 'abort-on-property-write.js',
|
||||||
aliases: [ 'aopw.js' ],
|
aliases: [ 'aopw.js' ],
|
||||||
fn: abortOnPropertyWrite,
|
fn: abortOnPropertyWrite,
|
||||||
|
dependencies: [
|
||||||
|
'get-exception-token.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
function abortOnPropertyWrite(
|
function abortOnPropertyWrite(
|
||||||
prop = ''
|
prop = ''
|
||||||
) {
|
) {
|
||||||
if ( typeof prop !== 'string' ) { return; }
|
if ( typeof prop !== 'string' ) { return; }
|
||||||
if ( prop === '' ) { return; }
|
if ( prop === '' ) { return; }
|
||||||
const magic = String.fromCharCode(Date.now() % 26 + 97) +
|
const exceptionToken = getExceptionToken();
|
||||||
Math.floor(Math.random() * 982451653 + 982451653).toString(36);
|
|
||||||
let owner = window;
|
let owner = window;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const pos = prop.indexOf('.');
|
const pos = prop.indexOf('.');
|
||||||
|
@ -222,26 +245,21 @@ function abortOnPropertyWrite(
|
||||||
delete owner[prop];
|
delete owner[prop];
|
||||||
Object.defineProperty(owner, prop, {
|
Object.defineProperty(owner, prop, {
|
||||||
set: function() {
|
set: function() {
|
||||||
throw new ReferenceError(magic);
|
throw new ReferenceError(exceptionToken);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const oe = window.onerror;
|
|
||||||
window.onerror = function(msg, src, line, col, error) {
|
|
||||||
if ( typeof msg === 'string' && msg.indexOf(magic) !== -1 ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ( oe instanceof Function ) {
|
|
||||||
return oe(msg, src, line, col, error);
|
|
||||||
}
|
|
||||||
}.bind();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// abort-on-stack-trace.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'abort-on-stack-trace.js',
|
name: 'abort-on-stack-trace.js',
|
||||||
aliases: [ 'aost.js' ],
|
aliases: [ 'aost.js' ],
|
||||||
fn: abortOnStackTrace,
|
fn: abortOnStackTrace,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
'get-exception-token.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
// Status is currently experimental
|
// Status is currently experimental
|
||||||
function abortOnStackTrace(
|
function abortOnStackTrace(
|
||||||
|
@ -250,19 +268,8 @@ function abortOnStackTrace(
|
||||||
logLevel = ''
|
logLevel = ''
|
||||||
) {
|
) {
|
||||||
if ( typeof chain !== 'string' ) { return; }
|
if ( typeof chain !== 'string' ) { return; }
|
||||||
const reRegexEscape = /[.*+?^${}()|[\]\\]/g;
|
const reNeedle = patternToRegex(needle);
|
||||||
if ( needle === '' ) {
|
const exceptionToken = getExceptionToken();
|
||||||
needle = '^';
|
|
||||||
} else if ( /^\/.+\/$/.test(needle) ) {
|
|
||||||
needle = needle.slice(1,-1);
|
|
||||||
} else {
|
|
||||||
needle = needle.replace(reRegexEscape, '\\$&');
|
|
||||||
}
|
|
||||||
const reNeedle = new RegExp(needle);
|
|
||||||
const magic = String.fromCharCode(Math.random() * 26 + 97) +
|
|
||||||
Math.floor(
|
|
||||||
(0.25 + Math.random() * 0.75) * Number.MAX_SAFE_INTEGER
|
|
||||||
).toString(36).slice(-8);
|
|
||||||
const log = console.log.bind(console);
|
const log = console.log.bind(console);
|
||||||
const ErrorCtor = self.Error;
|
const ErrorCtor = self.Error;
|
||||||
const mustAbort = function(err) {
|
const mustAbort = function(err) {
|
||||||
|
@ -274,7 +281,7 @@ function abortOnStackTrace(
|
||||||
// Normalize stack trace
|
// Normalize stack trace
|
||||||
const lines = [];
|
const lines = [];
|
||||||
for ( let line of err.stack.split(/[\n\r]+/) ) {
|
for ( let line of err.stack.split(/[\n\r]+/) ) {
|
||||||
if ( line.includes(magic) ) { continue; }
|
if ( line.includes(exceptionToken) ) { continue; }
|
||||||
line = line.trim();
|
line = line.trim();
|
||||||
let match = /(.*?@)?(\S+)(:\d+):\d+\)?$/.exec(line);
|
let match = /(.*?@)?(\S+)(:\d+):\d+\)?$/.exec(line);
|
||||||
if ( match === null ) { continue; }
|
if ( match === null ) { continue; }
|
||||||
|
@ -310,14 +317,14 @@ function abortOnStackTrace(
|
||||||
let v = owner[chain];
|
let v = owner[chain];
|
||||||
Object.defineProperty(owner, chain, {
|
Object.defineProperty(owner, chain, {
|
||||||
get: function() {
|
get: function() {
|
||||||
if ( mustAbort(new ErrorCtor(magic)) ) {
|
if ( mustAbort(new ErrorCtor(exceptionToken)) ) {
|
||||||
throw new ReferenceError(magic);
|
throw new ReferenceError(exceptionToken);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
},
|
},
|
||||||
set: function(a) {
|
set: function(a) {
|
||||||
if ( mustAbort(new ErrorCtor(magic)) ) {
|
if ( mustAbort(new ErrorCtor(exceptionToken)) ) {
|
||||||
throw new ReferenceError(magic);
|
throw new ReferenceError(exceptionToken);
|
||||||
}
|
}
|
||||||
v = a;
|
v = a;
|
||||||
},
|
},
|
||||||
|
@ -345,23 +352,17 @@ function abortOnStackTrace(
|
||||||
};
|
};
|
||||||
const owner = window;
|
const owner = window;
|
||||||
makeProxy(owner, chain);
|
makeProxy(owner, chain);
|
||||||
const oe = window.onerror;
|
|
||||||
window.onerror = function(msg, src, line, col, error) {
|
|
||||||
if ( typeof msg === 'string' && msg.indexOf(magic) !== -1 ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ( oe instanceof Function ) {
|
|
||||||
return oe(msg, src, line, col, error);
|
|
||||||
}
|
|
||||||
}.bind();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// addEventListener-defuser.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'addEventListener-defuser.js',
|
name: 'addEventListener-defuser.js',
|
||||||
aliases: [ 'aeld.js' ],
|
aliases: [ 'aeld.js' ],
|
||||||
fn: addEventListenerDefuser,
|
fn: addEventListenerDefuser,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
// https://github.com/uBlockOrigin/uAssets/issues/9123#issuecomment-848255120
|
// https://github.com/uBlockOrigin/uAssets/issues/9123#issuecomment-848255120
|
||||||
function addEventListenerDefuser(
|
function addEventListenerDefuser(
|
||||||
|
@ -374,22 +375,8 @@ function addEventListenerDefuser(
|
||||||
let { type = '', pattern = '' } = details;
|
let { type = '', pattern = '' } = details;
|
||||||
if ( typeof type !== 'string' ) { return; }
|
if ( typeof type !== 'string' ) { return; }
|
||||||
if ( typeof pattern !== 'string' ) { return; }
|
if ( typeof pattern !== 'string' ) { return; }
|
||||||
if ( type === '' ) {
|
const reType = patternToRegex(type);
|
||||||
type = '^';
|
const rePattern = patternToRegex(pattern);
|
||||||
} else if ( /^\/.+\/$/.test(type) ) {
|
|
||||||
type = type.slice(1,-1);
|
|
||||||
} else {
|
|
||||||
type = type.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
}
|
|
||||||
const reType = new RegExp(type);
|
|
||||||
if ( pattern === '' ) {
|
|
||||||
pattern = '^';
|
|
||||||
} else if ( /^\/.+\/$/.test(pattern) ) {
|
|
||||||
pattern = pattern.slice(1,-1);
|
|
||||||
} else {
|
|
||||||
pattern = pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
}
|
|
||||||
const rePattern = new RegExp(pattern);
|
|
||||||
const logfn = console.log.bind(console);
|
const logfn = console.log.bind(console);
|
||||||
const proto = self.EventTarget.prototype;
|
const proto = self.EventTarget.prototype;
|
||||||
proto.addEventListener = new Proxy(proto.addEventListener, {
|
proto.addEventListener = new Proxy(proto.addEventListener, {
|
||||||
|
@ -423,11 +410,14 @@ function addEventListenerDefuser(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// json-prune.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'json-prune.js',
|
name: 'json-prune.js',
|
||||||
fn: jsonPrune,
|
fn: jsonPrune,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
// When no "prune paths" argument is provided, the scriptlet is
|
// When no "prune paths" argument is provided, the scriptlet is
|
||||||
// used for logging purpose and the "needle paths" argument is
|
// used for logging purpose and the "needle paths" argument is
|
||||||
|
@ -451,15 +441,7 @@ function jsonPrune(
|
||||||
: [];
|
: [];
|
||||||
} else {
|
} else {
|
||||||
log = console.log.bind(console);
|
log = console.log.bind(console);
|
||||||
let needle;
|
reLogNeedle = patternToRegex(rawNeedlePaths);
|
||||||
if ( rawNeedlePaths === '' ) {
|
|
||||||
needle = '.?';
|
|
||||||
} else if ( rawNeedlePaths.charAt(0) === '/' && rawNeedlePaths.slice(-1) === '/' ) {
|
|
||||||
needle = rawNeedlePaths.slice(1, -1);
|
|
||||||
} else {
|
|
||||||
needle = rawNeedlePaths.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
}
|
|
||||||
reLogNeedle = new RegExp(needle);
|
|
||||||
}
|
}
|
||||||
const findOwner = function(root, path, prune = false) {
|
const findOwner = function(root, path, prune = false) {
|
||||||
let owner = root;
|
let owner = root;
|
||||||
|
@ -534,12 +516,15 @@ function jsonPrune(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// nano-setInterval-booster.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'nano-setInterval-booster.js',
|
name: 'nano-setInterval-booster.js',
|
||||||
aliases: [ 'nano-sib.js' ],
|
aliases: [ 'nano-sib.js' ],
|
||||||
fn: nanoSetIntervalBooster,
|
fn: nanoSetIntervalBooster,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
// Imported from:
|
// Imported from:
|
||||||
// https://github.com/NanoAdblocker/NanoFilters/blob/1f3be7211bb0809c5106996f52564bf10c4525f7/NanoFiltersSource/NanoResources.txt#L126
|
// https://github.com/NanoAdblocker/NanoFilters/blob/1f3be7211bb0809c5106996f52564bf10c4525f7/NanoFiltersSource/NanoResources.txt#L126
|
||||||
|
@ -559,14 +544,7 @@ function nanoSetIntervalBooster(
|
||||||
boostArg = ''
|
boostArg = ''
|
||||||
) {
|
) {
|
||||||
if ( typeof needleArg !== 'string' ) { return; }
|
if ( typeof needleArg !== 'string' ) { return; }
|
||||||
if ( needleArg === '' ) {
|
const reNeedle = patternToRegex(needleArg);
|
||||||
needleArg = '.?';
|
|
||||||
} else if ( needleArg.charAt(0) === '/' && needleArg.slice(-1) === '/' ) {
|
|
||||||
needleArg = needleArg.slice(1, -1);
|
|
||||||
} else {
|
|
||||||
needleArg = needleArg.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
}
|
|
||||||
const reNeedle = new RegExp(needleArg);
|
|
||||||
let delay = delayArg !== '*' ? parseInt(delayArg, 10) : -1;
|
let delay = delayArg !== '*' ? parseInt(delayArg, 10) : -1;
|
||||||
if ( isNaN(delay) || isFinite(delay) === false ) { delay = 1000; }
|
if ( isNaN(delay) || isFinite(delay) === false ) { delay = 1000; }
|
||||||
let boost = parseFloat(boostArg);
|
let boost = parseFloat(boostArg);
|
||||||
|
@ -587,12 +565,15 @@ function nanoSetIntervalBooster(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// nano-setTimeout-booster.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'nano-setTimeout-booster.js',
|
name: 'nano-setTimeout-booster.js',
|
||||||
aliases: [ 'nano-stb.js' ],
|
aliases: [ 'nano-stb.js' ],
|
||||||
fn: nanoSetTimeoutBooster,
|
fn: nanoSetTimeoutBooster,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
// Imported from:
|
// Imported from:
|
||||||
// https://github.com/NanoAdblocker/NanoFilters/blob/1f3be7211bb0809c5106996f52564bf10c4525f7/NanoFiltersSource/NanoResources.txt#L82
|
// https://github.com/NanoAdblocker/NanoFilters/blob/1f3be7211bb0809c5106996f52564bf10c4525f7/NanoFiltersSource/NanoResources.txt#L82
|
||||||
|
@ -613,14 +594,7 @@ function nanoSetTimeoutBooster(
|
||||||
boostArg = ''
|
boostArg = ''
|
||||||
) {
|
) {
|
||||||
if ( typeof needleArg !== 'string' ) { return; }
|
if ( typeof needleArg !== 'string' ) { return; }
|
||||||
if ( needleArg === '' ) {
|
const reNeedle = patternToRegex(needleArg);
|
||||||
needleArg = '.?';
|
|
||||||
} else if ( needleArg.charAt(0) === '/' && needleArg.slice(-1) === '/' ) {
|
|
||||||
needleArg = needleArg.slice(1, -1);
|
|
||||||
} else {
|
|
||||||
needleArg = needleArg.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
}
|
|
||||||
const reNeedle = new RegExp(needleArg);
|
|
||||||
let delay = delayArg !== '*' ? parseInt(delayArg, 10) : -1;
|
let delay = delayArg !== '*' ? parseInt(delayArg, 10) : -1;
|
||||||
if ( isNaN(delay) || isFinite(delay) === false ) { delay = 1000; }
|
if ( isNaN(delay) || isFinite(delay) === false ) { delay = 1000; }
|
||||||
let boost = parseFloat(boostArg);
|
let boost = parseFloat(boostArg);
|
||||||
|
@ -641,39 +615,37 @@ function nanoSetTimeoutBooster(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// noeval-if.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'noeval-if.js',
|
name: 'noeval-if.js',
|
||||||
fn: noevalIf,
|
fn: noEvalIf,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
function noevalIf(
|
function noEvalIf(
|
||||||
needle = ''
|
needle = ''
|
||||||
) {
|
) {
|
||||||
if ( typeof needle !== 'string' ) { return; }
|
if ( typeof needle !== 'string' ) { return; }
|
||||||
if ( needle === '' ) {
|
const reNeedle = patternToRegex(needle);
|
||||||
needle = '.?';
|
|
||||||
} else if ( needle.slice(0,1) === '/' && needle.slice(-1) === '/' ) {
|
|
||||||
needle = needle.slice(1,-1);
|
|
||||||
} else {
|
|
||||||
needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
}
|
|
||||||
needle = new RegExp(needle);
|
|
||||||
window.eval = new Proxy(window.eval, { // jshint ignore: line
|
window.eval = new Proxy(window.eval, { // jshint ignore: line
|
||||||
apply: function(target, thisArg, args) {
|
apply: function(target, thisArg, args) {
|
||||||
const a = args[0];
|
const a = args[0];
|
||||||
if ( needle.test(a.toString()) === false ) {
|
if ( reNeedle.test(a.toString()) ) { return; }
|
||||||
return target.apply(thisArg, args);
|
return target.apply(thisArg, args);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// no-fetch-if.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'no-fetch-if.js',
|
name: 'no-fetch-if.js',
|
||||||
fn: noFetchIf,
|
fn: noFetchIf,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
function noFetchIf(
|
function noFetchIf(
|
||||||
arg1 = '',
|
arg1 = '',
|
||||||
|
@ -691,14 +663,7 @@ function noFetchIf(
|
||||||
key = 'url';
|
key = 'url';
|
||||||
value = condition;
|
value = condition;
|
||||||
}
|
}
|
||||||
if ( value === '' ) {
|
needles.push({ key, re: patternToRegex(value) });
|
||||||
value = '^';
|
|
||||||
} else if ( value.startsWith('/') && value.endsWith('/') ) {
|
|
||||||
value = value.slice(1, -1);
|
|
||||||
} else {
|
|
||||||
value = value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
}
|
|
||||||
needles.push({ key, re: new RegExp(value) });
|
|
||||||
}
|
}
|
||||||
const log = needles.length === 0 ? console.log.bind(console) : undefined;
|
const log = needles.length === 0 ? console.log.bind(console) : undefined;
|
||||||
self.fetch = new Proxy(self.fetch, {
|
self.fetch = new Proxy(self.fetch, {
|
||||||
|
@ -746,8 +711,8 @@ function noFetchIf(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// refresh-defuser.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'refresh-defuser.js',
|
name: 'refresh-defuser.js',
|
||||||
fn: refreshDefuser,
|
fn: refreshDefuser,
|
||||||
|
@ -773,8 +738,8 @@ function refreshDefuser(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// remove-attr.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'remove-attr.js',
|
name: 'remove-attr.js',
|
||||||
aliases: [ 'ra.js' ],
|
aliases: [ 'ra.js' ],
|
||||||
|
@ -840,8 +805,8 @@ function removeAttr(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// remove-class.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'remove-class.js',
|
name: 'remove-class.js',
|
||||||
aliases: [ 'rc.js' ],
|
aliases: [ 'rc.js' ],
|
||||||
|
@ -905,12 +870,15 @@ function removeClass(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// no-requestAnimationFrame-if.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'no-requestAnimationFrame-if.js',
|
name: 'no-requestAnimationFrame-if.js',
|
||||||
aliases: [ 'norafif.js' ],
|
aliases: [ 'norafif.js' ],
|
||||||
fn: noRequestAnimationFrameIf,
|
fn: noRequestAnimationFrameIf,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
function noRequestAnimationFrameIf(
|
function noRequestAnimationFrameIf(
|
||||||
needle = ''
|
needle = ''
|
||||||
|
@ -918,13 +886,8 @@ function noRequestAnimationFrameIf(
|
||||||
if ( typeof needle !== 'string' ) { return; }
|
if ( typeof needle !== 'string' ) { return; }
|
||||||
const needleNot = needle.charAt(0) === '!';
|
const needleNot = needle.charAt(0) === '!';
|
||||||
if ( needleNot ) { needle = needle.slice(1); }
|
if ( needleNot ) { needle = needle.slice(1); }
|
||||||
if ( needle.startsWith('/') && needle.endsWith('/') ) {
|
|
||||||
needle = needle.slice(1, -1);
|
|
||||||
} else if ( needle !== '' ) {
|
|
||||||
needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
}
|
|
||||||
const log = needleNot === false && needle === '' ? console.log : undefined;
|
const log = needleNot === false && needle === '' ? console.log : undefined;
|
||||||
const reNeedle = new RegExp(needle);
|
const reNeedle = patternToRegex(needle);
|
||||||
window.requestAnimationFrame = new Proxy(window.requestAnimationFrame, {
|
window.requestAnimationFrame = new Proxy(window.requestAnimationFrame, {
|
||||||
apply: function(target, thisArg, args) {
|
apply: function(target, thisArg, args) {
|
||||||
const a = String(args[0]);
|
const a = String(args[0]);
|
||||||
|
@ -942,8 +905,8 @@ function noRequestAnimationFrameIf(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// set-constant.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'set-constant.js',
|
name: 'set-constant.js',
|
||||||
aliases: [ 'set.js' ],
|
aliases: [ 'set.js' ],
|
||||||
|
@ -1108,12 +1071,15 @@ function setConstant(
|
||||||
trapChain(window, chain);
|
trapChain(window, chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// no-setInterval-if.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'no-setInterval-if.js',
|
name: 'no-setInterval-if.js',
|
||||||
aliases: [ 'nosiif.js' ],
|
aliases: [ 'nosiif.js' ],
|
||||||
fn: noSetIntervalIf,
|
fn: noSetIntervalIf,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
function noSetIntervalIf(
|
function noSetIntervalIf(
|
||||||
needle = '',
|
needle = '',
|
||||||
|
@ -1129,17 +1095,10 @@ function noSetIntervalIf(
|
||||||
if ( delayNot ) { delay = delay.slice(1); }
|
if ( delayNot ) { delay = delay.slice(1); }
|
||||||
delay = parseInt(delay, 10);
|
delay = parseInt(delay, 10);
|
||||||
}
|
}
|
||||||
if ( needle === '' ) {
|
|
||||||
needle = '';
|
|
||||||
} else if ( needle.startsWith('/') && needle.endsWith('/') ) {
|
|
||||||
needle = needle.slice(1,-1);
|
|
||||||
} else {
|
|
||||||
needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
}
|
|
||||||
const log = needleNot === false && needle === '' && delay === undefined
|
const log = needleNot === false && needle === '' && delay === undefined
|
||||||
? console.log
|
? console.log
|
||||||
: undefined;
|
: undefined;
|
||||||
const reNeedle = new RegExp(needle);
|
const reNeedle = patternToRegex(needle);
|
||||||
window.setInterval = new Proxy(window.setInterval, {
|
window.setInterval = new Proxy(window.setInterval, {
|
||||||
apply: function(target, thisArg, args) {
|
apply: function(target, thisArg, args) {
|
||||||
const a = String(args[0]);
|
const a = String(args[0]);
|
||||||
|
@ -1163,12 +1122,15 @@ function noSetIntervalIf(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// no-setTimeout-if.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'no-setTimeout-if.js',
|
name: 'no-setTimeout-if.js',
|
||||||
aliases: [ 'nostif.js', 'setTimeout-defuser.js' ],
|
aliases: [ 'nostif.js', 'setTimeout-defuser.js' ],
|
||||||
fn: noSetTimeoutIf,
|
fn: noSetTimeoutIf,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
function noSetTimeoutIf(
|
function noSetTimeoutIf(
|
||||||
needle = '',
|
needle = '',
|
||||||
|
@ -1184,17 +1146,10 @@ function noSetTimeoutIf(
|
||||||
if ( delayNot ) { delay = delay.slice(1); }
|
if ( delayNot ) { delay = delay.slice(1); }
|
||||||
delay = parseInt(delay, 10);
|
delay = parseInt(delay, 10);
|
||||||
}
|
}
|
||||||
if ( needle === '' ) {
|
|
||||||
needle = '';
|
|
||||||
} else if ( needle.startsWith('/') && needle.endsWith('/') ) {
|
|
||||||
needle = needle.slice(1,-1);
|
|
||||||
} else {
|
|
||||||
needle = needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
}
|
|
||||||
const log = needleNot === false && needle === '' && delay === undefined
|
const log = needleNot === false && needle === '' && delay === undefined
|
||||||
? console.log
|
? console.log
|
||||||
: undefined;
|
: undefined;
|
||||||
const reNeedle = new RegExp(needle);
|
const reNeedle = patternToRegex(needle);
|
||||||
window.setTimeout = new Proxy(window.setTimeout, {
|
window.setTimeout = new Proxy(window.setTimeout, {
|
||||||
apply: function(target, thisArg, args) {
|
apply: function(target, thisArg, args) {
|
||||||
const a = String(args[0]);
|
const a = String(args[0]);
|
||||||
|
@ -1218,27 +1173,20 @@ function noSetTimeoutIf(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// webrtc-if.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'webrtc-if.js',
|
name: 'webrtc-if.js',
|
||||||
fn: webrtcIf,
|
fn: webrtcIf,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
function webrtcIf(
|
function webrtcIf(
|
||||||
good = ''
|
good = ''
|
||||||
) {
|
) {
|
||||||
if ( typeof good !== 'string' ) { return; }
|
if ( typeof good !== 'string' ) { return; }
|
||||||
if ( good.startsWith('/') && good.endsWith('/') ) {
|
const reGood = patternToRegex(good);
|
||||||
good = good.slice(1, -1);
|
|
||||||
} else {
|
|
||||||
good = good.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
}
|
|
||||||
let reGood;
|
|
||||||
try {
|
|
||||||
reGood = new RegExp(good);
|
|
||||||
} catch(ex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const rtcName = window.RTCPeerConnection
|
const rtcName = window.RTCPeerConnection
|
||||||
? 'RTCPeerConnection'
|
? 'RTCPeerConnection'
|
||||||
: (window.webkitRTCPeerConnection ? 'webkitRTCPeerConnection' : '');
|
: (window.webkitRTCPeerConnection ? 'webkitRTCPeerConnection' : '');
|
||||||
|
@ -1292,11 +1240,14 @@ function webrtcIf(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// no-xhr-if.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'no-xhr-if.js',
|
name: 'no-xhr-if.js',
|
||||||
fn: noXhrIf,
|
fn: noXhrIf,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
function noXhrIf(
|
function noXhrIf(
|
||||||
arg1 = ''
|
arg1 = ''
|
||||||
|
@ -1315,14 +1266,7 @@ function noXhrIf(
|
||||||
key = 'url';
|
key = 'url';
|
||||||
value = condition;
|
value = condition;
|
||||||
}
|
}
|
||||||
if ( value === '' ) {
|
needles.push({ key, re: patternToRegex(value) });
|
||||||
value = '^';
|
|
||||||
} else if ( value.startsWith('/') && value.endsWith('/') ) {
|
|
||||||
value = value.slice(1, -1);
|
|
||||||
} else {
|
|
||||||
value = value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
}
|
|
||||||
needles.push({ key, re: new RegExp(value) });
|
|
||||||
}
|
}
|
||||||
const log = needles.length === 0 ? console.log.bind(console) : undefined;
|
const log = needles.length === 0 ? console.log.bind(console) : undefined;
|
||||||
self.XMLHttpRequest = class extends self.XMLHttpRequest {
|
self.XMLHttpRequest = class extends self.XMLHttpRequest {
|
||||||
|
@ -1369,11 +1313,14 @@ function noXhrIf(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// window-close-if.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'window-close-if.js',
|
name: 'window-close-if.js',
|
||||||
fn: windowCloseIf,
|
fn: windowCloseIf,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
// https://github.com/uBlockOrigin/uAssets/issues/10323#issuecomment-992312847
|
// https://github.com/uBlockOrigin/uAssets/issues/10323#issuecomment-992312847
|
||||||
// https://github.com/AdguardTeam/Scriptlets/issues/158
|
// https://github.com/AdguardTeam/Scriptlets/issues/158
|
||||||
|
@ -1382,19 +1329,14 @@ function windowCloseIf(
|
||||||
arg1 = ''
|
arg1 = ''
|
||||||
) {
|
) {
|
||||||
if ( typeof arg1 !== 'string' ) { return; }
|
if ( typeof arg1 !== 'string' ) { return; }
|
||||||
let reStr;
|
|
||||||
let subject = '';
|
let subject = '';
|
||||||
if ( arg1 === '' ) {
|
if ( /^\/.*\/$/.test(arg1) ) {
|
||||||
reStr = '^';
|
|
||||||
} else if ( /^\/.*\/$/.test(arg1) ) {
|
|
||||||
reStr = arg1.slice(1, -1);
|
|
||||||
subject = window.location.href;
|
subject = window.location.href;
|
||||||
} else {
|
} else if ( arg1 !== '' ) {
|
||||||
reStr = arg1.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
subject = `${window.location.pathname}${window.location.search}`;
|
subject = `${window.location.pathname}${window.location.search}`;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const re = new RegExp(reStr);
|
const re = patternToRegex(arg1);
|
||||||
if ( re.test(subject) ) {
|
if ( re.test(subject) ) {
|
||||||
window.close();
|
window.close();
|
||||||
}
|
}
|
||||||
|
@ -1403,8 +1345,8 @@ function windowCloseIf(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// window.name-defuser.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'window.name-defuser.js',
|
name: 'window.name-defuser.js',
|
||||||
fn: windowNameDefuser,
|
fn: windowNameDefuser,
|
||||||
|
@ -1416,8 +1358,8 @@ function windowNameDefuser() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// overlay-buster.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'overlay-buster.js',
|
name: 'overlay-buster.js',
|
||||||
fn: overlayBuster,
|
fn: overlayBuster,
|
||||||
|
@ -1476,8 +1418,8 @@ function overlayBuster() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// alert-buster.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'alert-buster.js',
|
name: 'alert-buster.js',
|
||||||
fn: alertBuster,
|
fn: alertBuster,
|
||||||
|
@ -1491,8 +1433,8 @@ function alertBuster() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// nowebrtc.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'nowebrtc.js',
|
name: 'nowebrtc.js',
|
||||||
fn: noWebrtc,
|
fn: noWebrtc,
|
||||||
|
@ -1530,8 +1472,8 @@ function noWebrtc() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// golem.de.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'golem.de.js',
|
name: 'golem.de.js',
|
||||||
fn: golemDe,
|
fn: golemDe,
|
||||||
|
@ -1555,8 +1497,8 @@ function golemDe() {
|
||||||
}.bind(window);
|
}.bind(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// adfly-defuser.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'adfly-defuser.js',
|
name: 'adfly-defuser.js',
|
||||||
fn: adflyDefuser,
|
fn: adflyDefuser,
|
||||||
|
@ -1623,8 +1565,8 @@ function adflyDefuser() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// disable-newtab-links.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'disable-newtab-links.js',
|
name: 'disable-newtab-links.js',
|
||||||
fn: disableNewtabLinks,
|
fn: disableNewtabLinks,
|
||||||
|
@ -1644,23 +1586,21 @@ function disableNewtabLinks() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// cookie-remover.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'cookie-remover.js',
|
name: 'cookie-remover.js',
|
||||||
fn: cookieRemover,
|
fn: cookieRemover,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
// https://github.com/NanoAdblocker/NanoFilters/issues/149
|
// https://github.com/NanoAdblocker/NanoFilters/issues/149
|
||||||
function cookieRemover(
|
function cookieRemover(
|
||||||
needle = ''
|
needle = ''
|
||||||
) {
|
) {
|
||||||
if ( typeof needle !== 'string' ) { return; }
|
if ( typeof needle !== 'string' ) { return; }
|
||||||
let reName = /./;
|
const reName = patternToRegex(needle);
|
||||||
if ( /^\/.+\/$/.test(needle) ) {
|
|
||||||
reName = new RegExp(needle.slice(1,-1));
|
|
||||||
} else if ( needle !== '' ) {
|
|
||||||
reName = new RegExp(needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
|
||||||
}
|
|
||||||
const removeCookie = function() {
|
const removeCookie = function() {
|
||||||
document.cookie.split(';').forEach(cookieStr => {
|
document.cookie.split(';').forEach(cookieStr => {
|
||||||
let pos = cookieStr.indexOf('=');
|
let pos = cookieStr.indexOf('=');
|
||||||
|
@ -1700,11 +1640,14 @@ function cookieRemover(
|
||||||
window.addEventListener('beforeunload', removeCookie);
|
window.addEventListener('beforeunload', removeCookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// xml-prune.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'xml-prune.js',
|
name: 'xml-prune.js',
|
||||||
fn: xmlPrune,
|
fn: xmlPrune,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
],
|
||||||
});
|
});
|
||||||
function xmlPrune(
|
function xmlPrune(
|
||||||
selector = '',
|
selector = '',
|
||||||
|
@ -1713,14 +1656,7 @@ function xmlPrune(
|
||||||
) {
|
) {
|
||||||
if ( typeof selector !== 'string' ) { return; }
|
if ( typeof selector !== 'string' ) { return; }
|
||||||
if ( selector === '' ) { return; }
|
if ( selector === '' ) { return; }
|
||||||
let reUrl;
|
const reUrl = patternToRegex(urlPattern);
|
||||||
if ( urlPattern === '' ) {
|
|
||||||
reUrl = /^/;
|
|
||||||
} else if ( /^\/.*\/$/.test(urlPattern) ) {
|
|
||||||
reUrl = new RegExp(urlPattern.slice(1, -1));
|
|
||||||
} else {
|
|
||||||
reUrl = new RegExp(urlPattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
|
||||||
}
|
|
||||||
const pruner = text => {
|
const pruner = text => {
|
||||||
if ( (/^\s*</.test(text) && />\s*$/.test(text)) === false ) {
|
if ( (/^\s*</.test(text) && />\s*$/.test(text)) === false ) {
|
||||||
return text;
|
return text;
|
||||||
|
@ -1767,8 +1703,8 @@ function xmlPrune(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// m3u-prune.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'm3u-prune.js',
|
name: 'm3u-prune.js',
|
||||||
fn: m3uPrune,
|
fn: m3uPrune,
|
||||||
|
@ -1889,8 +1825,8 @@ function m3uPrune(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// href-sanitizer.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'href-sanitizer.js',
|
name: 'href-sanitizer.js',
|
||||||
fn: hrefSanitizer,
|
fn: hrefSanitizer,
|
||||||
|
@ -1980,8 +1916,8 @@ function hrefSanitizer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
/// call-nothrow.js
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'call-nothrow.js',
|
name: 'call-nothrow.js',
|
||||||
fn: callNothrow,
|
fn: callNothrow,
|
||||||
|
@ -2014,3 +1950,4 @@ function callNothrow(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
|
@ -34,6 +34,7 @@ import {
|
||||||
|
|
||||||
const extToMimeMap = new Map([
|
const extToMimeMap = new Map([
|
||||||
[ 'css', 'text/css' ],
|
[ 'css', 'text/css' ],
|
||||||
|
[ 'fn', 'fn/javascript' ], // invented mime type for internal use
|
||||||
[ 'gif', 'image/gif' ],
|
[ 'gif', 'image/gif' ],
|
||||||
[ 'html', 'text/html' ],
|
[ 'html', 'text/html' ],
|
||||||
[ 'js', 'text/javascript' ],
|
[ 'js', 'text/javascript' ],
|
||||||
|
@ -55,11 +56,14 @@ const typeToMimeMap = new Map([
|
||||||
|
|
||||||
const validMimes = new Set(extToMimeMap.values());
|
const validMimes = new Set(extToMimeMap.values());
|
||||||
|
|
||||||
const mimeFromName = function(name) {
|
const mimeFromName = name => {
|
||||||
const match = /\.([^.]+)$/.exec(name);
|
const match = /\.([^.]+)$/.exec(name);
|
||||||
if ( match !== null ) {
|
if ( match === null ) { return ''; }
|
||||||
return extToMimeMap.get(match[1]);
|
return extToMimeMap.get(match[1]);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const removeTopCommentBlock = text => {
|
||||||
|
return text.replace(/^\/\*[\S\s]+?\n\*\/\s*/, '');
|
||||||
};
|
};
|
||||||
|
|
||||||
// vAPI.warSecret() is optional, it could be absent in some environments,
|
// vAPI.warSecret() is optional, it could be absent in some environments,
|
||||||
|
@ -70,15 +74,19 @@ const warSecret = typeof vAPI === 'object' && vAPI !== null
|
||||||
? vAPI.warSecret
|
? vAPI.warSecret
|
||||||
: ( ) => '';
|
: ( ) => '';
|
||||||
|
|
||||||
|
const RESOURCES_SELFIE_VERSION = 7;
|
||||||
|
const RESOURCES_SELFIE_NAME = 'compiled/redirectEngine/resources';
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
const RedirectEntry = class {
|
class RedirectEntry {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.mime = '';
|
this.mime = '';
|
||||||
this.data = '';
|
this.data = '';
|
||||||
this.warURL = undefined;
|
this.warURL = undefined;
|
||||||
this.params = undefined;
|
this.params = undefined;
|
||||||
|
this.dependencies = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent redirection to web accessible resources when the request is
|
// Prevent redirection to web accessible resources when the request is
|
||||||
|
@ -116,7 +124,7 @@ const RedirectEntry = class {
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/701
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/701
|
||||||
if ( this.data === '' ) {
|
if ( this.data === '' ) {
|
||||||
const mime = typeToMimeMap.get(fctxt.type);
|
const mime = typeToMimeMap.get(fctxt.type);
|
||||||
if ( mime === undefined ) { return; }
|
if ( mime === '' ) { return; }
|
||||||
return `data:${mime},`;
|
return `data:${mime},`;
|
||||||
}
|
}
|
||||||
if ( this.data.startsWith('data:') === false ) {
|
if ( this.data.startsWith('data:') === false ) {
|
||||||
|
@ -141,10 +149,11 @@ const RedirectEntry = class {
|
||||||
return this.data;
|
return this.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromContent(mime, content) {
|
static fromContent(mime, content, dependencies = []) {
|
||||||
const r = new RedirectEntry();
|
const r = new RedirectEntry();
|
||||||
r.mime = mime;
|
r.mime = mime;
|
||||||
r.data = content;
|
r.data = content;
|
||||||
|
r.dependencies.push(...dependencies);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,93 +163,79 @@ const RedirectEntry = class {
|
||||||
r.data = selfie.data;
|
r.data = selfie.data;
|
||||||
r.warURL = selfie.warURL;
|
r.warURL = selfie.warURL;
|
||||||
r.params = selfie.params;
|
r.params = selfie.params;
|
||||||
|
r.dependencies = selfie.dependencies || [];
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
const RedirectEngine = function() {
|
class RedirectEngine {
|
||||||
|
constructor() {
|
||||||
this.aliases = new Map();
|
this.aliases = new Map();
|
||||||
this.resources = new Map();
|
this.resources = new Map();
|
||||||
this.reset();
|
this.reset();
|
||||||
this.modifyTime = Date.now();
|
this.modifyTime = Date.now();
|
||||||
this.resourceNameRegister = '';
|
this.resourceNameRegister = '';
|
||||||
};
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
reset() {
|
||||||
|
}
|
||||||
|
|
||||||
RedirectEngine.prototype.reset = function() {
|
freeze() {
|
||||||
};
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
tokenToURL(
|
||||||
|
|
||||||
RedirectEngine.prototype.freeze = function() {
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
RedirectEngine.prototype.tokenToURL = function(
|
|
||||||
fctxt,
|
fctxt,
|
||||||
token,
|
token,
|
||||||
asDataURI = false
|
asDataURI = false
|
||||||
) {
|
) {
|
||||||
const entry = this.resources.get(this.aliases.get(token) || token);
|
const entry = this.resources.get(this.aliases.get(token) || token);
|
||||||
if ( entry === undefined ) { return; }
|
if ( entry === undefined ) { return; }
|
||||||
this.resourceNameRegister = token;
|
this.resourceNameRegister = token;
|
||||||
return entry.toURL(fctxt, asDataURI);
|
return entry.toURL(fctxt, asDataURI);
|
||||||
};
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
tokenToDNR(token) {
|
||||||
|
|
||||||
RedirectEngine.prototype.tokenToDNR = function(token) {
|
|
||||||
const entry = this.resources.get(this.aliases.get(token) || token);
|
const entry = this.resources.get(this.aliases.get(token) || token);
|
||||||
if ( entry === undefined ) { return; }
|
if ( entry === undefined ) { return; }
|
||||||
if ( entry.warURL === undefined ) { return; }
|
if ( entry.warURL === undefined ) { return; }
|
||||||
return entry.warURL;
|
return entry.warURL;
|
||||||
};
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
hasToken(token) {
|
||||||
|
|
||||||
RedirectEngine.prototype.hasToken = function(token) {
|
|
||||||
if ( token === 'none' ) { return true; }
|
if ( token === 'none' ) { return true; }
|
||||||
const asDataURI = token.charCodeAt(0) === 0x25 /* '%' */;
|
const asDataURI = token.charCodeAt(0) === 0x25 /* '%' */;
|
||||||
if ( asDataURI ) {
|
if ( asDataURI ) {
|
||||||
token = token.slice(1);
|
token = token.slice(1);
|
||||||
}
|
}
|
||||||
return this.resources.get(this.aliases.get(token) || token) !== undefined;
|
return this.resources.get(this.aliases.get(token) || token) !== undefined;
|
||||||
};
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
async toSelfie() {
|
||||||
|
}
|
||||||
|
|
||||||
RedirectEngine.prototype.toSelfie = async function() {
|
async fromSelfie() {
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
RedirectEngine.prototype.fromSelfie = async function() {
|
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
contentFromName(name, mime = '') {
|
||||||
|
|
||||||
RedirectEngine.prototype.resourceContentFromName = function(name, mime) {
|
|
||||||
const entry = this.resources.get(this.aliases.get(name) || name);
|
const entry = this.resources.get(this.aliases.get(name) || name);
|
||||||
if ( entry === undefined ) { return; }
|
if ( entry === undefined ) { return; }
|
||||||
if ( mime === undefined || entry.mime.startsWith(mime) ) {
|
if ( entry.mime.startsWith(mime) === false ) { return; }
|
||||||
return entry.toContent();
|
return {
|
||||||
|
js: entry.toContent(),
|
||||||
|
dependencies: entry.dependencies.slice(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
// https://github.com/uBlockOrigin/uAssets/commit/deefe8755511
|
||||||
|
// Consider 'none' a reserved keyword, to be used to disable redirection.
|
||||||
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/1419
|
||||||
|
// Append newlines to raw text to ensure processing of trailing resource.
|
||||||
|
|
||||||
// https://github.com/uBlockOrigin/uAssets/commit/deefe875551197d655f79cb540e62dfc17c95f42
|
resourcesFromString(text) {
|
||||||
// Consider 'none' a reserved keyword, to be used to disable redirection.
|
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/1419
|
|
||||||
// Append newlines to raw text to ensure processing of trailing resource.
|
|
||||||
|
|
||||||
RedirectEngine.prototype.resourcesFromString = function(text) {
|
|
||||||
const lineIter = new LineIterator(
|
const lineIter = new LineIterator(
|
||||||
removeTopCommentBlock(text) + '\n\n'
|
removeTopCommentBlock(text) + '\n\n'
|
||||||
);
|
);
|
||||||
|
@ -296,10 +291,7 @@ RedirectEngine.prototype.resourcesFromString = function(text) {
|
||||||
const content = orphanizeString(
|
const content = orphanizeString(
|
||||||
fields.slice(2).join(encoded ? '' : '\n')
|
fields.slice(2).join(encoded ? '' : '\n')
|
||||||
);
|
);
|
||||||
this.resources.set(
|
this.resources.set(name, RedirectEntry.fromContent(mime, content));
|
||||||
name,
|
|
||||||
RedirectEntry.fromContent(mime, content)
|
|
||||||
);
|
|
||||||
if ( Array.isArray(details) ) {
|
if ( Array.isArray(details) ) {
|
||||||
for ( const { prop, value } of details ) {
|
for ( const { prop, value } of details ) {
|
||||||
if ( prop !== 'alias' ) { continue; }
|
if ( prop !== 'alias' ) { continue; }
|
||||||
|
@ -312,15 +304,9 @@ RedirectEngine.prototype.resourcesFromString = function(text) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.modifyTime = Date.now();
|
this.modifyTime = Date.now();
|
||||||
};
|
}
|
||||||
|
|
||||||
const removeTopCommentBlock = function(text) {
|
loadBuiltinResources(fetcher) {
|
||||||
return text.replace(/^\/\*[\S\s]+?\n\*\/\s*/, '');
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
RedirectEngine.prototype.loadBuiltinResources = function(fetcher) {
|
|
||||||
this.resources = new Map();
|
this.resources = new Map();
|
||||||
this.aliases = new Map();
|
this.aliases = new Map();
|
||||||
|
|
||||||
|
@ -330,7 +316,8 @@ RedirectEngine.prototype.loadBuiltinResources = function(fetcher) {
|
||||||
const { name, aliases, fn } = scriptlet;
|
const { name, aliases, fn } = scriptlet;
|
||||||
const entry = RedirectEntry.fromContent(
|
const entry = RedirectEntry.fromContent(
|
||||||
mimeFromName(name),
|
mimeFromName(name),
|
||||||
fn.toString()
|
fn.toString(),
|
||||||
|
scriptlet.dependencies,
|
||||||
);
|
);
|
||||||
this.resources.set(name, entry);
|
this.resources.set(name, entry);
|
||||||
if ( Array.isArray(aliases) === false ) { continue; }
|
if ( Array.isArray(aliases) === false ) { continue; }
|
||||||
|
@ -403,11 +390,9 @@ RedirectEngine.prototype.loadBuiltinResources = function(fetcher) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(fetches);
|
return Promise.all(fetches);
|
||||||
};
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
getResourceDetails() {
|
||||||
|
|
||||||
RedirectEngine.prototype.getResourceDetails = function() {
|
|
||||||
const out = new Map([
|
const out = new Map([
|
||||||
[ 'none', { canInject: false, canRedirect: true, aliasOf: '' } ],
|
[ 'none', { canInject: false, canRedirect: true, aliasOf: '' } ],
|
||||||
]);
|
]);
|
||||||
|
@ -429,14 +414,9 @@ RedirectEngine.prototype.getResourceDetails = function() {
|
||||||
return Array.from(out).sort((a, b) => {
|
return Array.from(out).sort((a, b) => {
|
||||||
return a[0].localeCompare(b[0]);
|
return a[0].localeCompare(b[0]);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
selfieFromResources(storage) {
|
||||||
|
|
||||||
const RESOURCES_SELFIE_VERSION = 7;
|
|
||||||
const RESOURCES_SELFIE_NAME = 'compiled/redirectEngine/resources';
|
|
||||||
|
|
||||||
RedirectEngine.prototype.selfieFromResources = function(storage) {
|
|
||||||
storage.put(
|
storage.put(
|
||||||
RESOURCES_SELFIE_NAME,
|
RESOURCES_SELFIE_NAME,
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
@ -445,9 +425,9 @@ RedirectEngine.prototype.selfieFromResources = function(storage) {
|
||||||
resources: Array.from(this.resources),
|
resources: Array.from(this.resources),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
RedirectEngine.prototype.resourcesFromSelfie = async function(storage) {
|
async resourcesFromSelfie(storage) {
|
||||||
const result = await storage.get(RESOURCES_SELFIE_NAME);
|
const result = await storage.get(RESOURCES_SELFIE_NAME);
|
||||||
let selfie;
|
let selfie;
|
||||||
try {
|
try {
|
||||||
|
@ -467,11 +447,12 @@ RedirectEngine.prototype.resourcesFromSelfie = async function(storage) {
|
||||||
this.resources.set(token, RedirectEntry.fromSelfie(entry));
|
this.resources.set(token, RedirectEntry.fromSelfie(entry));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
RedirectEngine.prototype.invalidateResourcesSelfie = function(storage) {
|
invalidateResourcesSelfie(storage) {
|
||||||
storage.remove(RESOURCES_SELFIE_NAME);
|
storage.remove(RESOURCES_SELFIE_NAME);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
|
|
@ -141,13 +141,8 @@ const normalizeRawFilter = function(parser) {
|
||||||
return `+js(${args.join(', ')})`;
|
return `+js(${args.join(', ')})`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const lookupScriptlet = function(rawToken, reng, toInject) {
|
const lookupScriptlet = function(rawToken, scriptletMap, dependencyMap) {
|
||||||
if ( toInject.has(rawToken) ) { return; }
|
if ( scriptletMap.has(rawToken) ) { return; }
|
||||||
if ( scriptletCache.resetTime < reng.modifyTime ) {
|
|
||||||
scriptletCache.reset();
|
|
||||||
}
|
|
||||||
let content = scriptletCache.lookup(rawToken);
|
|
||||||
if ( content === undefined ) {
|
|
||||||
const pos = rawToken.indexOf(',');
|
const pos = rawToken.indexOf(',');
|
||||||
let token, args = '';
|
let token, args = '';
|
||||||
if ( pos === -1 ) {
|
if ( pos === -1 ) {
|
||||||
|
@ -158,21 +153,28 @@ const lookupScriptlet = function(rawToken, reng, toInject) {
|
||||||
}
|
}
|
||||||
// TODO: The alias lookup can be removed once scriptlet resources
|
// TODO: The alias lookup can be removed once scriptlet resources
|
||||||
// with obsolete name are converted to their new name.
|
// with obsolete name are converted to their new name.
|
||||||
if ( reng.aliases.has(token) ) {
|
if ( redirectEngine.aliases.has(token) ) {
|
||||||
token = reng.aliases.get(token);
|
token = redirectEngine.aliases.get(token);
|
||||||
} else {
|
} else {
|
||||||
token = `${token}.js`;
|
token = `${token}.js`;
|
||||||
}
|
}
|
||||||
content = reng.resourceContentFromName(token, 'text/javascript');
|
const details = redirectEngine.contentFromName(token, 'text/javascript');
|
||||||
if ( !content ) { return; }
|
if ( details === undefined ) { return; }
|
||||||
content = patchScriptlet(content, args);
|
const content = patchScriptlet(details.js, args);
|
||||||
content =
|
const dependencies = details.dependencies || [];
|
||||||
'try {\n' +
|
while ( dependencies.length !== 0 ) {
|
||||||
content + '\n' +
|
const token = dependencies.shift();
|
||||||
'} catch ( e ) { }';
|
if ( dependencyMap.has(token) ) { continue; }
|
||||||
scriptletCache.add(rawToken, content);
|
const details = redirectEngine.contentFromName(token, 'fn/javascript');
|
||||||
|
if ( details === undefined ) { continue; }
|
||||||
|
dependencyMap.set(token, details.js);
|
||||||
|
if ( Array.isArray(details.dependencies) === false ) { continue; }
|
||||||
|
dependencies.push(...details.dependencies);
|
||||||
}
|
}
|
||||||
toInject.set(rawToken, content);
|
scriptletMap.set(
|
||||||
|
rawToken,
|
||||||
|
[ 'try {', content, '} catch (e) {', '}' ].join('\n')
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fill-in scriptlet argument placeholders.
|
// Fill-in scriptlet argument placeholders.
|
||||||
|
@ -183,8 +185,10 @@ const patchScriptlet = function(content, args) {
|
||||||
if ( args.startsWith('{') && args.endsWith('}') ) {
|
if ( args.startsWith('{') && args.endsWith('}') ) {
|
||||||
return content.replace('{{args}}', args);
|
return content.replace('{{args}}', args);
|
||||||
}
|
}
|
||||||
|
if ( args === '' ) {
|
||||||
|
return content.replace('{{args}}', '');
|
||||||
|
}
|
||||||
const arglist = [];
|
const arglist = [];
|
||||||
if ( args !== '' ) {
|
|
||||||
let s = args;
|
let s = args;
|
||||||
let len = s.length;
|
let len = s.length;
|
||||||
let beg = 0, pos = 0;
|
let beg = 0, pos = 0;
|
||||||
|
@ -202,12 +206,10 @@ const patchScriptlet = function(content, args) {
|
||||||
beg = pos = pos + 1;
|
beg = pos = pos + 1;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
for ( let i = 0; i < arglist.length; i++ ) {
|
for ( let i = 0; i < arglist.length; i++ ) {
|
||||||
content = content.replace(`{{${i+1}}}`, arglist[i]);
|
content = content.replace(`{{${i+1}}}`, arglist[i]);
|
||||||
}
|
}
|
||||||
content = content.replace('{{args}}', arglist.map(a => `'${a}'`).join(', '));
|
return content.replace('{{args}}', arglist.map(a => `'${a}'`).join(', '));
|
||||||
return content;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const logOne = function(tabId, url, filter) {
|
const logOne = function(tabId, url, filter) {
|
||||||
|
@ -225,6 +227,7 @@ const logOne = function(tabId, url, filter) {
|
||||||
scriptletFilteringEngine.reset = function() {
|
scriptletFilteringEngine.reset = function() {
|
||||||
scriptletDB.clear();
|
scriptletDB.clear();
|
||||||
duplicates.clear();
|
duplicates.clear();
|
||||||
|
scriptletCache.reset();
|
||||||
acceptedCount = 0;
|
acceptedCount = 0;
|
||||||
discardedCount = 0;
|
discardedCount = 0;
|
||||||
};
|
};
|
||||||
|
@ -232,6 +235,7 @@ scriptletFilteringEngine.reset = function() {
|
||||||
scriptletFilteringEngine.freeze = function() {
|
scriptletFilteringEngine.freeze = function() {
|
||||||
duplicates.clear();
|
duplicates.clear();
|
||||||
scriptletDB.collectGarbage();
|
scriptletDB.collectGarbage();
|
||||||
|
scriptletCache.reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
scriptletFilteringEngine.compile = function(parser, writer) {
|
scriptletFilteringEngine.compile = function(parser, writer) {
|
||||||
|
@ -292,7 +296,8 @@ scriptletFilteringEngine.fromCompiledContent = function(reader) {
|
||||||
|
|
||||||
const $scriptlets = new Set();
|
const $scriptlets = new Set();
|
||||||
const $exceptions = new Set();
|
const $exceptions = new Set();
|
||||||
const $scriptletToCodeMap = new Map();
|
const $scriptletMap = new Map();
|
||||||
|
const $scriptletDependencyMap = new Map();
|
||||||
|
|
||||||
scriptletFilteringEngine.retrieve = function(request, options = {}) {
|
scriptletFilteringEngine.retrieve = function(request, options = {}) {
|
||||||
if ( scriptletDB.size === 0 ) { return; }
|
if ( scriptletDB.size === 0 ) { return; }
|
||||||
|
@ -328,21 +333,39 @@ scriptletFilteringEngine.retrieve = function(request, options = {}) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$scriptletToCodeMap.clear();
|
if ( scriptletCache.resetTime < redirectEngine.modifyTime ) {
|
||||||
for ( const token of $scriptlets ) {
|
scriptletCache.reset();
|
||||||
lookupScriptlet(token, redirectEngine, $scriptletToCodeMap);
|
|
||||||
}
|
}
|
||||||
if ( $scriptletToCodeMap.size === 0 ) { return; }
|
|
||||||
|
|
||||||
// Return an array of scriptlets, and log results if needed.
|
let cacheDetails = scriptletCache.lookup(hostname);
|
||||||
const out = [];
|
if ( cacheDetails === undefined ) {
|
||||||
for ( const [ token, code ] of $scriptletToCodeMap ) {
|
const fullCode = [];
|
||||||
|
for ( const token of $scriptlets ) {
|
||||||
|
if ( $exceptions.has(token) ) { continue; }
|
||||||
|
lookupScriptlet(token, $scriptletMap, $scriptletDependencyMap);
|
||||||
|
}
|
||||||
|
for ( const token of $scriptlets ) {
|
||||||
const isException = $exceptions.has(token);
|
const isException = $exceptions.has(token);
|
||||||
if ( isException === false ) {
|
if ( isException === false ) {
|
||||||
out.push(code);
|
fullCode.push($scriptletMap.get(token));
|
||||||
}
|
}
|
||||||
if ( mustLog === false ) { continue; }
|
}
|
||||||
if ( isException ) {
|
for ( const code of $scriptletDependencyMap.values() ) {
|
||||||
|
fullCode.push(code);
|
||||||
|
}
|
||||||
|
cacheDetails = {
|
||||||
|
code: fullCode.join('\n'),
|
||||||
|
tokens: Array.from($scriptlets),
|
||||||
|
exceptions: Array.from($exceptions),
|
||||||
|
};
|
||||||
|
scriptletCache.add(hostname, cacheDetails);
|
||||||
|
$scriptletMap.clear();
|
||||||
|
$scriptletDependencyMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( mustLog ) {
|
||||||
|
for ( const token of cacheDetails.tokens ) {
|
||||||
|
if ( cacheDetails.exceptions.includes(token) ) {
|
||||||
logOne(request.tabId, request.url, `#@#+js(${token})`);
|
logOne(request.tabId, request.url, `#@#+js(${token})`);
|
||||||
} else {
|
} else {
|
||||||
options.logEntries.push({
|
options.logEntries.push({
|
||||||
|
@ -352,16 +375,16 @@ scriptletFilteringEngine.retrieve = function(request, options = {}) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( out.length === 0 ) { return; }
|
if ( cacheDetails.code === '' ) { return; }
|
||||||
|
|
||||||
|
const out = [ cacheDetails.code ];
|
||||||
|
|
||||||
if ( µb.hiddenSettings.debugScriptlets ) {
|
if ( µb.hiddenSettings.debugScriptlets ) {
|
||||||
out.unshift('debugger;');
|
out.unshift('debugger;');
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/156
|
|
||||||
// Provide a private Map() object available for use by all
|
|
||||||
// scriptlets.
|
|
||||||
out.unshift(
|
out.unshift(
|
||||||
'(function() {',
|
'(function() {',
|
||||||
'// >>>> start of private namespace',
|
'// >>>> start of private namespace',
|
||||||
|
|
Loading…
Reference in a new issue