mirror of https://github.com/gorhill/uBlock.git
Add abort-on-stack-trace scriptlet
This new scriplet has become necessary as a countermeasure to new bypass mechanisms by some websites, as discussed with filter list maintainers. Also related discussion: https://github.com/AdguardTeam/Scriptlets/issues/82 Scriptlet: abort-on-stack-trace Alias: aost Argument 1: The property to trap in order to launch the stack trace matching code, ex. Math.random Argument 2: The string (needle) to match against the stack trace. If the empty string, always match. There is a special string which can be used to match inline script context, <inline-script>. Argument 3: Whether to log, and if so how: Empty string: do not log 1: log stack trace for all access to trapped property 2: log stack trace for defused access to trapped property 3: log stack trace for non-defused access to trapped property
This commit is contained in:
parent
45bd8f5bf4
commit
b735ac6b6a
|
@ -191,6 +191,101 @@
|
|||
})();
|
||||
|
||||
|
||||
/// abort-on-stack-trace.js
|
||||
/// alias aost.js
|
||||
// Status is currently experimental
|
||||
(function() {
|
||||
let chain = '{{1}}';
|
||||
let needle = '{{2}}';
|
||||
let logLevel = '{{3}}';
|
||||
const reRegexEscape = /[.*+?^${}()|[\]\\]/g;
|
||||
if ( needle === '' || needle === '{{2}}' ) {
|
||||
needle = '^';
|
||||
} else if ( /^\/.+\/$/.test(needle) ) {
|
||||
needle = needle.slice(1,-1);
|
||||
} else {
|
||||
needle = needle.replace(reRegexEscape, '\\$&');
|
||||
}
|
||||
const reNeedle = new RegExp(needle, 'im');
|
||||
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 ErrorCtor = self.Error;
|
||||
const mustAbort = function(err) {
|
||||
let docURL = self.location.href;
|
||||
const pos = docURL.indexOf('#');
|
||||
if ( pos !== -1 ) {
|
||||
docURL = docURL.slice(0, pos);
|
||||
}
|
||||
const reDocURL = new RegExp(docURL.replace(reRegexEscape, '\\$&'), 'g');
|
||||
const stack = err.stack
|
||||
.replace(/^.*?\b[gs]et\b[^\n\r]+?[\n\r]*/m, '')
|
||||
.replace(reDocURL, '<inline-script>');
|
||||
const r = reNeedle.test(stack);
|
||||
if (
|
||||
logLevel === '1' ||
|
||||
logLevel === '2' && r ||
|
||||
logLevel === '3' && !r
|
||||
) {
|
||||
log(stack);
|
||||
}
|
||||
return r;
|
||||
};
|
||||
const makeProxy = function(owner, chain) {
|
||||
const pos = chain.indexOf('.');
|
||||
if ( pos === -1 ) {
|
||||
let v = owner[chain];
|
||||
Object.defineProperty(owner, chain, {
|
||||
get: function() {
|
||||
if ( mustAbort(new ErrorCtor(magic)) ) {
|
||||
throw new ReferenceError(magic);
|
||||
}
|
||||
return v;
|
||||
},
|
||||
set: function(a) {
|
||||
if ( mustAbort(new ErrorCtor(magic)) ) {
|
||||
throw new ReferenceError(magic);
|
||||
}
|
||||
v = a;
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
const prop = chain.slice(0, pos);
|
||||
let v = owner[prop];
|
||||
chain = chain.slice(pos + 1);
|
||||
if ( v ) {
|
||||
makeProxy(v, chain);
|
||||
return;
|
||||
}
|
||||
const desc = Object.getOwnPropertyDescriptor(owner, prop);
|
||||
if ( desc && desc.set !== undefined ) { return; }
|
||||
Object.defineProperty(owner, prop, {
|
||||
get: function() { return v; },
|
||||
set: function(a) {
|
||||
v = a;
|
||||
if ( a instanceof Object ) {
|
||||
makeProxy(a, chain);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const owner = window;
|
||||
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
|
||||
/// alias aeld.js
|
||||
(function() {
|
||||
|
|
Loading…
Reference in New Issue