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 = '' pattern = ''
) { ) {
const safe = safeSelf(); const safe = safeSelf();
const logPrefix = safe.makeLogPrefix('prevent-addEventListener', type, pattern);
const extraArgs = safe.getExtraArgs(Array.from(arguments), 2); const extraArgs = safe.getExtraArgs(Array.from(arguments), 2);
const logPrefix = safe.makeLogPrefix('prevent-addEventListener', type, pattern);
const reType = safe.patternToRegex(type, undefined, true); const reType = safe.patternToRegex(type, undefined, true);
const rePattern = safe.patternToRegex(pattern); const rePattern = safe.patternToRegex(pattern);
const debug = shouldDebug(extraArgs); const debug = shouldDebug(extraArgs);
const targetSelector = extraArgs.elements || undefined; const targetSelector = extraArgs.elements || undefined;
const shouldPrevent = (thisArg, type, handler) => { const elementMatches = elem => {
if ( targetSelector !== undefined ) { if ( elem && elem.matches && elem.matches(targetSelector) ) { return true; }
const elems = Array.from(document.querySelectorAll(targetSelector)); 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 matchesType = safe.RegExp_test.call(reType, type);
const matchesHandler = safe.RegExp_test.call(rePattern, handler); const matchesHandler = safe.RegExp_test.call(rePattern, handler);
const matchesEither = matchesType || matchesHandler; const matchesEither = matchesType || matchesHandler;
@ -1605,6 +1623,9 @@ function addEventListenerDefuser(
if ( debug === 1 && matchesBoth || debug === 2 && matchesEither ) { if ( debug === 1 && matchesBoth || debug === 2 && matchesEither ) {
debugger; // jshint ignore:line debugger; // jshint ignore:line
} }
if ( matchesBoth && targetSelector !== undefined ) {
if ( elementMatches(thisArg) === false ) { return false; }
}
return matchesBoth; return matchesBoth;
}; };
const trapEddEventListeners = ( ) => { const trapEddEventListeners = ( ) => {
@ -1613,15 +1634,21 @@ function addEventListenerDefuser(
let t, h; let t, h;
try { try {
t = String(args[0]); t = String(args[0]);
h = args[1] instanceof Function if ( typeof args[1] === 'function' ) {
? String(safe.Function_toString(args[1])) h = String(safe.Function_toString(args[1]));
: String(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) { } catch(ex) {
} }
if ( type === '' && pattern === '' ) { 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) ) { } 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); return Reflect.apply(target, thisArg, args);
}, },