From 86f0d6dd978b79a34ffa257825539fb4446759a4 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Sun, 22 Oct 2023 12:35:49 -0400 Subject: [PATCH] Add `trusted-prune-outbound-object.js` scriptlet Essentially a complement of `trusted-prune-inbound-object.js` added in https://github.com/gorhill/uBlock/commit/1c9da227d714250c0b6319e2f635998f9869a70d To perform object pruning on any object returned synchronously by any given call. The arguments for `trusted-prune-outbound-object` in order are: - The name of the property to trap. Must be a function, and must exist when the scriptlet tries to install the trap. - The properties to prune (as with `json-prune`) - The properties which must all be present for pruning to occur (as with `json-prune`) The scriptlets `json-prune.js` and `evaldata-prune.js` essentially perform the same function, and will eventually be rewritten to internally delegate to generic `trusted-prune-outbound-object.js`. --- assets/resources/scriptlets.js | 45 ++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/assets/resources/scriptlets.js b/assets/resources/scriptlets.js index f43c9b2c4..62984aa38 100644 --- a/assets/resources/scriptlets.js +++ b/assets/resources/scriptlets.js @@ -4091,3 +4091,48 @@ function trustedPruneInboundObject( } /******************************************************************************/ + +builtinScriptlets.push({ + name: 'trusted-prune-outbound-object.js', + requiresTrust: true, + fn: trustedPruneOutboundObject, + dependencies: [ + 'object-prune.fn', + 'safe-self.fn', + ], +}); +function trustedPruneOutboundObject( + entryPoint = '', + rawPrunePaths = '', + rawNeedlePaths = '' +) { + if ( entryPoint === '' ) { return; } + let context = globalThis; + let prop = entryPoint; + for (;;) { + const pos = prop.indexOf('.'); + if ( pos === -1 ) { break; } + context = context[prop.slice(0, pos)]; + if ( context instanceof Object === false ) { return; } + prop = prop.slice(pos+1); + } + if ( typeof context[prop] !== 'function' ) { return; } + const safe = safeSelf(); + const extraArgs = safe.getExtraArgs(Array.from(arguments), 3); + context[prop] = new Proxy(context[prop], { + apply: function(target, thisArg, args) { + const objBefore = Reflect.apply(target, thisArg, args); + if ( objBefore instanceof Object === false ) { return objBefore; } + const objAfter = objectPruneFn( + objBefore, + rawPrunePaths, + rawNeedlePaths, + { matchAll: true }, + extraArgs + ); + return objAfter || objBefore; + }, + }); +} + +/******************************************************************************/