Skip to content

Commit 56dfdd2

Browse files
committed
Improve various scriptlets
Specifically, improve proxying of native methods.
1 parent 9ced01e commit 56dfdd2

File tree

1 file changed

+126
-142
lines changed

1 file changed

+126
-142
lines changed

assets/resources/scriptlets.js

Lines changed: 126 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,9 +1446,6 @@ function replaceFetchResponseFn(
14461446
builtinScriptlets.push({
14471447
name: 'proxy-apply.fn',
14481448
fn: proxyApplyFn,
1449-
dependencies: [
1450-
'safe-self.fn',
1451-
],
14521449
});
14531450
function proxyApplyFn(
14541451
target = '',
@@ -1465,12 +1462,28 @@ function proxyApplyFn(
14651462
}
14661463
const fn = context[prop];
14671464
if ( typeof fn !== 'function' ) { return; }
1465+
const fnname = fn.name;
1466+
const toString = (function toString() {
1467+
return `function ${fnname}() { [native code] }`;
1468+
}).bind(null);
14681469
if ( fn.prototype && fn.prototype.constructor === fn ) {
1469-
context[prop] = new Proxy(fn, { construct: handler });
1470-
return (...args) => { return Reflect.construct(...args); };
1470+
context[prop] = new Proxy(fn, {
1471+
construct: handler,
1472+
get(target, prop, receiver) {
1473+
if ( prop === 'toString' ) { return toString; }
1474+
return Reflect.get(target, prop, receiver);
1475+
},
1476+
});
1477+
return (...args) => Reflect.construct(...args);
14711478
}
1472-
context[prop] = new Proxy(fn, { apply: handler });
1473-
return (...args) => { return Reflect.apply(...args); };
1479+
context[prop] = new Proxy(fn, {
1480+
apply: handler,
1481+
get(target, prop, receiver) {
1482+
if ( prop === 'toString' ) { return toString; }
1483+
return Reflect.get(target, prop, receiver);
1484+
},
1485+
});
1486+
return (...args) => Reflect.apply(...args);
14741487
}
14751488

14761489
/*******************************************************************************
@@ -1676,6 +1689,7 @@ builtinScriptlets.push({
16761689
],
16771690
fn: addEventListenerDefuser,
16781691
dependencies: [
1692+
'proxy-apply.fn',
16791693
'run-at.fn',
16801694
'safe-self.fn',
16811695
'should-debug.fn',
@@ -1732,44 +1746,29 @@ function addEventListenerDefuser(
17321746
}
17331747
return matchesBoth;
17341748
};
1735-
const trapEddEventListeners = ( ) => {
1736-
const eventListenerHandler = {
1737-
apply: function(target, thisArg, args) {
1738-
let t, h;
1739-
try {
1740-
t = String(args[0]);
1741-
if ( typeof args[1] === 'function' ) {
1742-
h = String(safe.Function_toString(args[1]));
1743-
} else if ( typeof args[1] === 'object' && args[1] !== null ) {
1744-
if ( typeof args[1].handleEvent === 'function' ) {
1745-
h = String(safe.Function_toString(args[1].handleEvent));
1746-
}
1747-
} else {
1748-
h = String(args[1]);
1749+
runAt(( ) => {
1750+
proxyApplyFn('EventTarget.prototype.addEventListener', function(target, thisArg, args) {
1751+
let t, h;
1752+
try {
1753+
t = String(args[0]);
1754+
if ( typeof args[1] === 'function' ) {
1755+
h = String(safe.Function_toString(args[1]));
1756+
} else if ( typeof args[1] === 'object' && args[1] !== null ) {
1757+
if ( typeof args[1].handleEvent === 'function' ) {
1758+
h = String(safe.Function_toString(args[1].handleEvent));
17491759
}
1750-
} catch(ex) {
1751-
}
1752-
if ( type === '' && pattern === '' ) {
1753-
safe.uboLog(logPrefix, `Called: ${t}\n${h}\n${elementDetails(thisArg)}`);
1754-
} else if ( shouldPrevent(thisArg, t, h) ) {
1755-
return safe.uboLog(logPrefix, `Prevented: ${t}\n${h}\n${elementDetails(thisArg)}`);
1756-
}
1757-
return Reflect.apply(target, thisArg, args);
1758-
},
1759-
get(target, prop, receiver) {
1760-
if ( prop === 'toString' ) {
1761-
return target.toString.bind(target);
1760+
} else {
1761+
h = String(args[1]);
17621762
}
1763-
return Reflect.get(target, prop, receiver);
1764-
},
1765-
};
1766-
self.EventTarget.prototype.addEventListener = new Proxy(
1767-
self.EventTarget.prototype.addEventListener,
1768-
eventListenerHandler
1769-
);
1770-
};
1771-
runAt(( ) => {
1772-
trapEddEventListeners();
1763+
} catch(ex) {
1764+
}
1765+
if ( type === '' && pattern === '' ) {
1766+
safe.uboLog(logPrefix, `Called: ${t}\n${h}\n${elementDetails(thisArg)}`);
1767+
} else if ( shouldPrevent(thisArg, t, h) ) {
1768+
return safe.uboLog(logPrefix, `Prevented: ${t}\n${h}\n${elementDetails(thisArg)}`);
1769+
}
1770+
return Reflect.apply(target, thisArg, args);
1771+
});
17731772
}, extraArgs.runAt);
17741773
}
17751774

@@ -2475,6 +2474,7 @@ builtinScriptlets.push({
24752474
],
24762475
fn: noSetIntervalIf,
24772476
dependencies: [
2477+
'proxy-apply.fn',
24782478
'safe-self.fn',
24792479
],
24802480
});
@@ -2495,35 +2495,27 @@ function noSetIntervalIf(
24952495
delay = parseInt(delay, 10);
24962496
}
24972497
const reNeedle = safe.patternToRegex(needle);
2498-
self.setInterval = new Proxy(self.setInterval, {
2499-
apply: function(target, thisArg, args) {
2500-
const a = args[0] instanceof Function
2501-
? String(safe.Function_toString(args[0]))
2502-
: String(args[0]);
2503-
const b = args[1];
2504-
if ( needle === '' && delay === undefined ) {
2505-
safe.uboLog(logPrefix, `Called:\n${a}\n${b}`);
2506-
return Reflect.apply(target, thisArg, args);
2507-
}
2508-
let defuse;
2509-
if ( needle !== '' ) {
2510-
defuse = reNeedle.test(a) !== needleNot;
2511-
}
2512-
if ( defuse !== false && delay !== undefined ) {
2513-
defuse = (b === delay || isNaN(b) && isNaN(delay) ) !== delayNot;
2514-
}
2515-
if ( defuse ) {
2516-
args[0] = function(){};
2517-
safe.uboLog(logPrefix, `Prevented:\n${a}\n${b}`);
2518-
}
2498+
proxyApplyFn('setInterval', function setInterval(target, thisArg, args) {
2499+
const a = args[0] instanceof Function
2500+
? String(safe.Function_toString(args[0]))
2501+
: String(args[0]);
2502+
const b = args[1];
2503+
if ( needle === '' && delay === undefined ) {
2504+
safe.uboLog(logPrefix, `Called:\n${a}\n${b}`);
25192505
return Reflect.apply(target, thisArg, args);
2520-
},
2521-
get(target, prop, receiver) {
2522-
if ( prop === 'toString' ) {
2523-
return target.toString.bind(target);
2524-
}
2525-
return Reflect.get(target, prop, receiver);
2526-
},
2506+
}
2507+
let defuse;
2508+
if ( needle !== '' ) {
2509+
defuse = reNeedle.test(a) !== needleNot;
2510+
}
2511+
if ( defuse !== false && delay !== undefined ) {
2512+
defuse = (b === delay || isNaN(b) && isNaN(delay) ) !== delayNot;
2513+
}
2514+
if ( defuse ) {
2515+
args[0] = function(){};
2516+
safe.uboLog(logPrefix, `Prevented:\n${a}\n${b}`);
2517+
}
2518+
return Reflect.apply(target, thisArg, args);
25272519
});
25282520
}
25292521

@@ -2538,6 +2530,7 @@ builtinScriptlets.push({
25382530
],
25392531
fn: noSetTimeoutIf,
25402532
dependencies: [
2533+
'proxy-apply.fn',
25412534
'safe-self.fn',
25422535
],
25432536
});
@@ -2558,35 +2551,27 @@ function noSetTimeoutIf(
25582551
delay = parseInt(delay, 10);
25592552
}
25602553
const reNeedle = safe.patternToRegex(needle);
2561-
self.setTimeout = new Proxy(self.setTimeout, {
2562-
apply: function(target, thisArg, args) {
2563-
const a = args[0] instanceof Function
2564-
? String(safe.Function_toString(args[0]))
2565-
: String(args[0]);
2566-
const b = args[1];
2567-
if ( needle === '' && delay === undefined ) {
2568-
safe.uboLog(logPrefix, `Called:\n${a}\n${b}`);
2569-
return Reflect.apply(target, thisArg, args);
2570-
}
2571-
let defuse;
2572-
if ( needle !== '' ) {
2573-
defuse = reNeedle.test(a) !== needleNot;
2574-
}
2575-
if ( defuse !== false && delay !== undefined ) {
2576-
defuse = (b === delay || isNaN(b) && isNaN(delay) ) !== delayNot;
2577-
}
2578-
if ( defuse ) {
2579-
args[0] = function(){};
2580-
safe.uboLog(logPrefix, `Prevented:\n${a}\n${b}`);
2581-
}
2554+
proxyApplyFn('setTimeout', function setTimeout(target, thisArg, args) {
2555+
const a = args[0] instanceof Function
2556+
? String(safe.Function_toString(args[0]))
2557+
: String(args[0]);
2558+
const b = args[1];
2559+
if ( needle === '' && delay === undefined ) {
2560+
safe.uboLog(logPrefix, `Called:\n${a}\n${b}`);
25822561
return Reflect.apply(target, thisArg, args);
2583-
},
2584-
get(target, prop, receiver) {
2585-
if ( prop === 'toString' ) {
2586-
return target.toString.bind(target);
2587-
}
2588-
return Reflect.get(target, prop, receiver);
2589-
},
2562+
}
2563+
let defuse;
2564+
if ( needle !== '' ) {
2565+
defuse = reNeedle.test(a) !== needleNot;
2566+
}
2567+
if ( defuse !== false && delay !== undefined ) {
2568+
defuse = (b === delay || isNaN(b) && isNaN(delay) ) !== delayNot;
2569+
}
2570+
if ( defuse ) {
2571+
args[0] = function(){};
2572+
safe.uboLog(logPrefix, `Prevented:\n${a}\n${b}`);
2573+
}
2574+
return Reflect.apply(target, thisArg, args);
25902575
});
25912576
}
25922577

@@ -2815,6 +2800,7 @@ builtinScriptlets.push({
28152800
],
28162801
fn: noWindowOpenIf,
28172802
dependencies: [
2803+
'proxy-apply.fn',
28182804
'safe-self.fn',
28192805
],
28202806
});
@@ -2845,51 +2831,49 @@ function noWindowOpenIf(
28452831
setTimeout(( ) => { decoyElem.remove(); }, autoRemoveAfter * 1000);
28462832
return decoyElem;
28472833
};
2848-
window.open = new Proxy(window.open, {
2849-
apply: function(target, thisArg, args) {
2850-
const haystack = args.join(' ');
2851-
if ( rePattern.test(haystack) !== targetMatchResult ) {
2852-
if ( safe.logLevel > 1 ) {
2853-
safe.uboLog(logPrefix, `Allowed (${args.join(', ')})`);
2854-
}
2855-
return Reflect.apply(target, thisArg, args);
2856-
}
2857-
safe.uboLog(logPrefix, `Prevented (${args.join(', ')})`);
2858-
if ( autoRemoveAfter < 0 ) { return null; }
2859-
const decoyElem = decoy === 'obj'
2860-
? createDecoy('object', 'data', ...args)
2861-
: createDecoy('iframe', 'src', ...args);
2862-
let popup = decoyElem.contentWindow;
2863-
if ( typeof popup === 'object' && popup !== null ) {
2864-
Object.defineProperty(popup, 'closed', { value: false });
2865-
} else {
2866-
const noopFunc = (function(){}).bind(self);
2867-
popup = new Proxy(self, {
2868-
get: function(target, prop) {
2869-
if ( prop === 'closed' ) { return false; }
2870-
const r = Reflect.get(...arguments);
2871-
if ( typeof r === 'function' ) { return noopFunc; }
2872-
return target[prop];
2873-
},
2874-
set: function() {
2875-
return Reflect.set(...arguments);
2876-
},
2877-
});
2878-
}
2879-
if ( safe.logLevel !== 0 ) {
2880-
popup = new Proxy(popup, {
2881-
get: function(target, prop) {
2882-
safe.uboLog(logPrefix, 'window.open / get', prop, '===', target[prop]);
2883-
return Reflect.get(...arguments);
2884-
},
2885-
set: function(target, prop, value) {
2886-
safe.uboLog(logPrefix, 'window.open / set', prop, '=', value);
2887-
return Reflect.set(...arguments);
2888-
},
2889-
});
2834+
proxyApplyFn('open', function open(target, thisArg, args) {
2835+
const haystack = args.join(' ');
2836+
if ( rePattern.test(haystack) !== targetMatchResult ) {
2837+
if ( safe.logLevel > 1 ) {
2838+
safe.uboLog(logPrefix, `Allowed (${args.join(', ')})`);
28902839
}
2891-
return popup;
2840+
return Reflect.apply(target, thisArg, args);
2841+
}
2842+
safe.uboLog(logPrefix, `Prevented (${args.join(', ')})`);
2843+
if ( autoRemoveAfter < 0 ) { return null; }
2844+
const decoyElem = decoy === 'obj'
2845+
? createDecoy('object', 'data', ...args)
2846+
: createDecoy('iframe', 'src', ...args);
2847+
let popup = decoyElem.contentWindow;
2848+
if ( typeof popup === 'object' && popup !== null ) {
2849+
Object.defineProperty(popup, 'closed', { value: false });
2850+
} else {
2851+
const noopFunc = function open(){};
2852+
popup = new Proxy(self, {
2853+
get: function(target, prop) {
2854+
if ( prop === 'closed' ) { return false; }
2855+
const r = Reflect.get(...arguments);
2856+
if ( typeof r === 'function' ) { return noopFunc; }
2857+
return target[prop];
2858+
},
2859+
set: function() {
2860+
return Reflect.set(...arguments);
2861+
},
2862+
});
2863+
}
2864+
if ( safe.logLevel !== 0 ) {
2865+
popup = new Proxy(popup, {
2866+
get: function(target, prop) {
2867+
safe.uboLog(logPrefix, 'window.open / get', prop, '===', target[prop]);
2868+
return Reflect.get(...arguments);
2869+
},
2870+
set: function(target, prop, value) {
2871+
safe.uboLog(logPrefix, 'window.open / set', prop, '=', value);
2872+
return Reflect.set(...arguments);
2873+
},
2874+
});
28922875
}
2876+
return popup;
28932877
});
28942878
}
28952879

0 commit comments

Comments
 (0)