mirror of
https://github.com/gorhill/uBlock.git
synced 2024-10-06 09:37:12 +02:00
Ensure document.documentElement is present when executing acs
scriptlet
Related issue: - https://github.com/uBlockOrigin/uBlock-issues/issues/2670
This commit is contained in:
parent
9878156820
commit
8d1669f9b5
@ -159,6 +159,132 @@ function runAt(fn, when) {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
builtinScriptlets.push({
|
||||||
|
name: 'run-at-html-element.fn',
|
||||||
|
fn: runAtHtmlElement,
|
||||||
|
});
|
||||||
|
function runAtHtmlElement(fn) {
|
||||||
|
if ( document.documentElement ) {
|
||||||
|
fn();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const observer = new MutationObserver(( ) => {
|
||||||
|
fn();
|
||||||
|
observer.disconnect();
|
||||||
|
});
|
||||||
|
observer.observe(document, { childList: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
builtinScriptlets.push({
|
||||||
|
name: 'abort-current-script-core.fn',
|
||||||
|
fn: abortCurrentScriptCore,
|
||||||
|
dependencies: [
|
||||||
|
'pattern-to-regex.fn',
|
||||||
|
'get-exception-token.fn',
|
||||||
|
'safe-self.fn',
|
||||||
|
'should-debug.fn',
|
||||||
|
'should-log.fn',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
// Issues to mind before changing anything:
|
||||||
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/2154
|
||||||
|
function abortCurrentScriptCore(
|
||||||
|
arg1 = '',
|
||||||
|
arg2 = '',
|
||||||
|
arg3 = ''
|
||||||
|
) {
|
||||||
|
const details = typeof arg1 !== 'object'
|
||||||
|
? { target: arg1, needle: arg2, context: arg3 }
|
||||||
|
: arg1;
|
||||||
|
const { target = '', needle = '', context = '' } = details;
|
||||||
|
if ( typeof target !== 'string' ) { return; }
|
||||||
|
if ( target === '' ) { return; }
|
||||||
|
const safe = safeSelf();
|
||||||
|
const reNeedle = patternToRegex(needle);
|
||||||
|
const reContext = patternToRegex(context);
|
||||||
|
const thisScript = document.currentScript;
|
||||||
|
const chain = target.split('.');
|
||||||
|
let owner = window;
|
||||||
|
let prop;
|
||||||
|
for (;;) {
|
||||||
|
prop = chain.shift();
|
||||||
|
if ( chain.length === 0 ) { break; }
|
||||||
|
owner = owner[prop];
|
||||||
|
if ( owner instanceof Object === false ) { return; }
|
||||||
|
}
|
||||||
|
let value;
|
||||||
|
let desc = Object.getOwnPropertyDescriptor(owner, prop);
|
||||||
|
if (
|
||||||
|
desc instanceof Object === false ||
|
||||||
|
desc.get instanceof Function === false
|
||||||
|
) {
|
||||||
|
value = owner[prop];
|
||||||
|
desc = undefined;
|
||||||
|
}
|
||||||
|
const log = shouldLog(details);
|
||||||
|
const debug = shouldDebug(details);
|
||||||
|
const exceptionToken = getExceptionToken();
|
||||||
|
const scriptTexts = new WeakMap();
|
||||||
|
const getScriptText = elem => {
|
||||||
|
let text = elem.textContent;
|
||||||
|
if ( text.trim() !== '' ) { return text; }
|
||||||
|
if ( scriptTexts.has(elem) ) { return scriptTexts.get(elem); }
|
||||||
|
const [ , mime, content ] =
|
||||||
|
/^data:([^,]*),(.+)$/.exec(elem.src.trim()) ||
|
||||||
|
[ '', '', '' ];
|
||||||
|
try {
|
||||||
|
switch ( true ) {
|
||||||
|
case mime.endsWith(';base64'):
|
||||||
|
text = self.atob(content);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
text = self.decodeURIComponent(content);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch(ex) {
|
||||||
|
}
|
||||||
|
scriptTexts.set(elem, text);
|
||||||
|
return text;
|
||||||
|
};
|
||||||
|
const validate = ( ) => {
|
||||||
|
if ( debug ) { debugger; } // jshint ignore: line
|
||||||
|
const e = document.currentScript;
|
||||||
|
if ( e instanceof HTMLScriptElement === false ) { return; }
|
||||||
|
if ( e === thisScript ) { return; }
|
||||||
|
if ( reContext.test(e.src) === false ) { return; }
|
||||||
|
if ( log && e.src !== '' ) { safe.uboLog(`matched src: ${e.src}`); }
|
||||||
|
const scriptText = getScriptText(e);
|
||||||
|
if ( reNeedle.test(scriptText) === false ) { return; }
|
||||||
|
if ( log ) { safe.uboLog(`matched script text: ${scriptText}`); }
|
||||||
|
throw new ReferenceError(exceptionToken);
|
||||||
|
};
|
||||||
|
if ( debug ) { debugger; } // jshint ignore: line
|
||||||
|
try {
|
||||||
|
Object.defineProperty(owner, prop, {
|
||||||
|
get: function() {
|
||||||
|
validate();
|
||||||
|
return desc instanceof Object
|
||||||
|
? desc.get.call(owner)
|
||||||
|
: value;
|
||||||
|
},
|
||||||
|
set: function(a) {
|
||||||
|
validate();
|
||||||
|
if ( desc instanceof Object ) {
|
||||||
|
desc.set.call(owner, a);
|
||||||
|
} else {
|
||||||
|
value = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch(ex) {
|
||||||
|
if ( log ) { safe.uboLog(ex); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
builtinScriptlets.push({
|
builtinScriptlets.push({
|
||||||
name: 'set-constant-core.fn',
|
name: 'set-constant-core.fn',
|
||||||
fn: setConstantCore,
|
fn: setConstantCore,
|
||||||
@ -373,106 +499,20 @@ builtinScriptlets.push({
|
|||||||
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: [
|
dependencies: [
|
||||||
'pattern-to-regex.fn',
|
'abort-current-script-core.fn',
|
||||||
'get-exception-token.fn',
|
'run-at-html-element.fn',
|
||||||
'safe-self.fn',
|
|
||||||
'should-debug.fn',
|
|
||||||
'should-log.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
|
||||||
function abortCurrentScript(
|
function abortCurrentScript(
|
||||||
arg1 = '',
|
arg1,
|
||||||
arg2 = '',
|
arg2,
|
||||||
arg3 = ''
|
arg3
|
||||||
) {
|
) {
|
||||||
const details = typeof arg1 !== 'object'
|
runAtHtmlElement(( ) => {
|
||||||
? { target: arg1, needle: arg2, context: arg3 }
|
abortCurrentScriptCore(arg1, arg2, arg3);
|
||||||
: arg1;
|
|
||||||
const { target = '', needle = '', context = '' } = details;
|
|
||||||
if ( typeof target !== 'string' ) { return; }
|
|
||||||
if ( target === '' ) { return; }
|
|
||||||
const safe = safeSelf();
|
|
||||||
const reNeedle = patternToRegex(needle);
|
|
||||||
const reContext = patternToRegex(context);
|
|
||||||
const thisScript = document.currentScript;
|
|
||||||
const chain = target.split('.');
|
|
||||||
let owner = window;
|
|
||||||
let prop;
|
|
||||||
for (;;) {
|
|
||||||
prop = chain.shift();
|
|
||||||
if ( chain.length === 0 ) { break; }
|
|
||||||
owner = owner[prop];
|
|
||||||
if ( owner instanceof Object === false ) { return; }
|
|
||||||
}
|
|
||||||
let value;
|
|
||||||
let desc = Object.getOwnPropertyDescriptor(owner, prop);
|
|
||||||
if (
|
|
||||||
desc instanceof Object === false ||
|
|
||||||
desc.get instanceof Function === false
|
|
||||||
) {
|
|
||||||
value = owner[prop];
|
|
||||||
desc = undefined;
|
|
||||||
}
|
|
||||||
const log = shouldLog(details);
|
|
||||||
const debug = shouldDebug(details);
|
|
||||||
const exceptionToken = getExceptionToken();
|
|
||||||
const scriptTexts = new WeakMap();
|
|
||||||
const getScriptText = elem => {
|
|
||||||
let text = elem.textContent;
|
|
||||||
if ( text.trim() !== '' ) { return text; }
|
|
||||||
if ( scriptTexts.has(elem) ) { return scriptTexts.get(elem); }
|
|
||||||
const [ , mime, content ] =
|
|
||||||
/^data:([^,]*),(.+)$/.exec(elem.src.trim()) ||
|
|
||||||
[ '', '', '' ];
|
|
||||||
try {
|
|
||||||
switch ( true ) {
|
|
||||||
case mime.endsWith(';base64'):
|
|
||||||
text = self.atob(content);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
text = self.decodeURIComponent(content);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch(ex) {
|
|
||||||
}
|
|
||||||
scriptTexts.set(elem, text);
|
|
||||||
return text;
|
|
||||||
};
|
|
||||||
const validate = ( ) => {
|
|
||||||
if ( debug ) { debugger; } // jshint ignore: line
|
|
||||||
const e = document.currentScript;
|
|
||||||
if ( e instanceof HTMLScriptElement === false ) { return; }
|
|
||||||
if ( e === thisScript ) { return; }
|
|
||||||
if ( reContext.test(e.src) === false ) { return; }
|
|
||||||
if ( log && e.src !== '' ) { safe.uboLog(`matched src: ${e.src}`); }
|
|
||||||
const scriptText = getScriptText(e);
|
|
||||||
if ( reNeedle.test(scriptText) === false ) { return; }
|
|
||||||
if ( log ) { safe.uboLog(`matched script text: ${scriptText}`); }
|
|
||||||
throw new ReferenceError(exceptionToken);
|
|
||||||
};
|
|
||||||
if ( debug ) { debugger; } // jshint ignore: line
|
|
||||||
try {
|
|
||||||
Object.defineProperty(owner, prop, {
|
|
||||||
get: function() {
|
|
||||||
validate();
|
|
||||||
return desc instanceof Object
|
|
||||||
? desc.get.call(owner)
|
|
||||||
: value;
|
|
||||||
},
|
|
||||||
set: function(a) {
|
|
||||||
validate();
|
|
||||||
if ( desc instanceof Object ) {
|
|
||||||
desc.set.call(owner, a);
|
|
||||||
} else {
|
|
||||||
value = a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} catch(ex) {
|
|
||||||
if ( log ) { safe.uboLog(ex); }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
Loading…
Reference in New Issue
Block a user