Improve `prevent-addEventListener` scriptlet

Related feedback:
https://github.com/uBlockOrigin/uBlock-issues/issues/3061#issuecomment-1899042062
This commit is contained in:
Raymond Hill 2024-02-14 08:23:16 -05:00
parent 068b625bef
commit b22b3d729b
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
1 changed files with 37 additions and 10 deletions

View File

@ -1587,17 +1587,35 @@ function addEventListenerDefuser(
pattern = ''
) {
const safe = safeSelf();
const logPrefix = safe.makeLogPrefix('prevent-addEventListener', type, pattern);
const extraArgs = safe.getExtraArgs(Array.from(arguments), 2);
const logPrefix = safe.makeLogPrefix('prevent-addEventListener', type, pattern);
const reType = safe.patternToRegex(type, undefined, true);
const rePattern = safe.patternToRegex(pattern);
const debug = shouldDebug(extraArgs);
const targetSelector = extraArgs.elements || undefined;
const shouldPrevent = (thisArg, type, handler) => {
if ( targetSelector !== undefined ) {
const elementMatches = elem => {
if ( elem && elem.matches && elem.matches(targetSelector) ) { return true; }
const elems = Array.from(document.querySelectorAll(targetSelector));
if ( elems.includes(thisArg) === false ) { return false; }
return elems.includes(elem);
};
const elementDetails = elem => {
if ( elem instanceof Window ) { return 'window'; }
if ( elem instanceof Document ) { return 'document'; }
if ( elem instanceof Element === false ) { return '?'; }
const parts = [];
if ( elem.id !== '' ) { parts.push(`#${CSS.escape(elem.id)}`); }
for ( let i = 0; i < elem.classList.length; i++ ) {
parts.push(`.${CSS.escape(elem.classList.item(i))}`);
}
for ( let i = 0; i < elem.attributes.length; i++ ) {
const attr = elem.attributes.item(i);
if ( attr.name === 'id' ) { continue; }
if ( attr.name === 'class' ) { continue; }
parts.push(`[${CSS.escape(attr.name)}="${attr.value}"]`);
}
return parts.join('');
};
const shouldPrevent = (thisArg, type, handler) => {
const matchesType = safe.RegExp_test.call(reType, type);
const matchesHandler = safe.RegExp_test.call(rePattern, handler);
const matchesEither = matchesType || matchesHandler;
@ -1605,6 +1623,9 @@ function addEventListenerDefuser(
if ( debug === 1 && matchesBoth || debug === 2 && matchesEither ) {
debugger; // jshint ignore:line
}
if ( matchesBoth && targetSelector !== undefined ) {
if ( elementMatches(thisArg) === false ) { return false; }
}
return matchesBoth;
};
const trapEddEventListeners = ( ) => {
@ -1613,15 +1634,21 @@ function addEventListenerDefuser(
let t, h;
try {
t = String(args[0]);
h = args[1] instanceof Function
? String(safe.Function_toString(args[1]))
: String(args[1]);
if ( typeof args[1] === 'function' ) {
h = String(safe.Function_toString(args[1]));
} else if ( typeof args[1] === 'object' && args[1] !== null ) {
if ( typeof args[1].handleEvent === 'function' ) {
h = String(safe.Function_toString(args[1].handleEvent));
}
} else {
h = String(args[1]);
}
} catch(ex) {
}
if ( type === '' && pattern === '' ) {
safe.uboLog(logPrefix, `Called: ${t}\n${h}`);
safe.uboLog(logPrefix, `Called: ${t}\n${h}\n${elementDetails(thisArg)}`);
} else if ( shouldPrevent(thisArg, t, h) ) {
return safe.uboLog(logPrefix, `Prevented: ${t}\n${h}`);
return safe.uboLog(logPrefix, `Prevented: ${t}\n${h}\n${elementDetails(thisArg)}`);
}
return Reflect.apply(target, thisArg, args);
},