Add stackNeedle argument to json-prune scriptlet · gorhill/uBlock@4649ae4 (original) (raw)
`@@ -46,6 +46,7 @@ function safeSelf() {
`
46
46
`return scriptletGlobals.get('safeSelf');
`
47
47
`}
`
48
48
`const safe = {
`
``
49
`+
'Error': self.Error,
`
49
50
`'Object_defineProperty': Object.defineProperty.bind(Object),
`
50
51
`'RegExp': self.RegExp,
`
51
52
`'RegExp_test': self.RegExp.prototype.test,
`
`@@ -620,6 +621,7 @@ builtinScriptlets.push({
`
620
621
`name: 'object-prune.fn',
`
621
622
`fn: objectPrune,
`
622
623
`dependencies: [
`
``
624
`+
'matches-stack-trace.fn',
`
623
625
`'pattern-to-regex.fn',
`
624
626
`],
`
625
627
`});
`
`@@ -632,9 +634,10 @@ builtinScriptlets.push({
`
632
634
`function objectPrune(
`
633
635
`obj,
`
634
636
`rawPrunePaths,
`
635
``
`-
rawNeedlePaths
`
``
637
`+
rawNeedlePaths,
`
``
638
`+
stackNeedle = ''
`
636
639
`) {
`
637
``
`-
if ( typeof rawPrunePaths !== 'string' ) { return; }
`
``
640
`+
if ( typeof rawPrunePaths !== 'string' ) { return obj; }
`
638
641
`const prunePaths = rawPrunePaths !== ''
`
639
642
` ? rawPrunePaths.split(/ +/)
`
640
643
` : [];
`
`@@ -648,6 +651,11 @@ function objectPrune(
`
648
651
`log = console.log.bind(console);
`
649
652
`reLogNeedle = patternToRegex(rawNeedlePaths);
`
650
653
`}
`
``
654
`+
if ( stackNeedle !== '' ) {
`
``
655
`+
if ( matchesStackTrace(patternToRegex(stackNeedle), log ? '1' : 0) === false ) {
`
``
656
`+
return obj;
`
``
657
`+
}
`
``
658
`+
}
`
651
659
`const findOwner = function(root, path, prune = false) {
`
652
660
`let owner = root;
`
653
661
`let chain = path;
`
`@@ -802,6 +810,60 @@ function setLocalStorageItemCore(
`
802
810
`}
`
803
811
`}
`
804
812
``
``
813
`+
/******************************************************************************/
`
``
814
+
``
815
`+
builtinScriptlets.push({
`
``
816
`+
name: 'matches-stack-trace.fn',
`
``
817
`+
fn: matchesStackTrace,
`
``
818
`+
dependencies: [
`
``
819
`+
'safe-self.fn',
`
``
820
`+
],
`
``
821
`+
});
`
``
822
`+
function matchesStackTrace(
`
``
823
`+
reNeedle,
`
``
824
`+
logLevel = 0
`
``
825
`+
) {
`
``
826
`+
if ( reNeedle === undefined ) { return false; }
`
``
827
`+
const safe = safeSelf();
`
``
828
`+
const exceptionToken = getExceptionToken();
`
``
829
`+
const error = new safe.Error(exceptionToken);
`
``
830
`+
const docURL = new URL(self.location.href);
`
``
831
`+
docURL.hash = '';
`
``
832
`+
// Normalize stack trace
`
``
833
`+
const reLine = /(.*?@)?(\S+)(:\d+):\d+)?$/;
`
``
834
`+
const lines = [];
`
``
835
`+
for ( let line of error.stack.split(/[\n\r]+/) ) {
`
``
836
`+
if ( line.includes(exceptionToken) ) { continue; }
`
``
837
`+
line = line.trim();
`
``
838
`+
const match = safe.RegExp_exec.call(reLine, line);
`
``
839
`+
if ( match === null ) { continue; }
`
``
840
`+
let url = match[2];
`
``
841
`+
if ( url.startsWith('(') ) { url = url.slice(1); }
`
``
842
`+
if ( url === docURL.href ) {
`
``
843
`+
url = 'inlineScript';
`
``
844
`+
} else if ( url.startsWith('') ) {
`
``
845
`+
url = 'injectedScript';
`
``
846
`+
}
`
``
847
`+
let fn = match[1] !== undefined
`
``
848
`+
? match[1].slice(0, -1)
`
``
849
`+
: line.slice(0, match.index).trim();
`
``
850
`+
if ( fn.startsWith('at') ) { fn = fn.slice(2).trim(); }
`
``
851
`+
let rowcol = match[3];
`
``
852
`` +
lines.push(' ' + ${fn} <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>u</mi><mi>r</mi><mi>l</mi></mrow><annotation encoding="application/x-tex">{url}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord"><span class="mord mathnormal">u</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span></span></span></span></span>{rowcol}:1.trim());
``
``
853
`+
}
`
``
854
`` +
lines[0] = stackDepth:${lines.length-1};
``
``
855
`+
const stack = lines.join('\t');
`
``
856
`+
const r = safe.RegExp_test.call(reNeedle, stack);
`
``
857
`+
if (
`
``
858
`+
logLevel === '1' ||
`
``
859
`+
logLevel === '2' && r ||
`
``
860
`+
logLevel === '3' && !r
`
``
861
`+
) {
`
``
862
`+
safe.uboLog(stack.replace(/\t/g, '\n'));
`
``
863
`+
}
`
``
864
`+
return r;
`
``
865
`+
}
`
``
866
+
805
867
`/*******************************************************************************
`
806
868
``
807
869
` Injectable scriptlets
`
`@@ -931,8 +993,8 @@ builtinScriptlets.push({
`
931
993
`fn: abortOnStackTrace,
`
932
994
`dependencies: [
`
933
995
`'get-exception-token.fn',
`
``
996
`+
'matches-stack-trace.fn',
`
934
997
`'pattern-to-regex.fn',
`
935
``
`-
'safe-self.fn',
`
936
998
`],
`
937
999
`});
`
938
1000
`// Status is currently experimental
`
`@@ -942,64 +1004,21 @@ function abortOnStackTrace(
`
942
1004
`logLevel = ''
`
943
1005
`) {
`
944
1006
`if ( typeof chain !== 'string' ) { return; }
`
945
``
`-
const safe = safeSelf();
`
946
1007
`const reNeedle = patternToRegex(needle);
`
947
``
`-
const exceptionToken = getExceptionToken();
`
948
``
`-
const ErrorCtor = self.Error;
`
949
``
`-
const mustAbort = function(err) {
`
950
``
`-
let docURL = self.location.href;
`
951
``
`-
const pos = docURL.indexOf('#');
`
952
``
`-
if ( pos !== -1 ) {
`
953
``
`-
docURL = docURL.slice(0, pos);
`
954
``
`-
}
`
955
``
`-
// Normalize stack trace
`
956
``
`-
const reLine = /(.*?@)?(\S+)(:\d+):\d+)?$/;
`
957
``
`-
const lines = [];
`
958
``
`-
for ( let line of err.stack.split(/[\n\r]+/) ) {
`
959
``
`-
if ( line.includes(exceptionToken) ) { continue; }
`
960
``
`-
line = line.trim();
`
961
``
`-
const match = safe.RegExp_exec.call(reLine, line);
`
962
``
`-
if ( match === null ) { continue; }
`
963
``
`-
let url = match[2];
`
964
``
`-
if ( url.startsWith('(') ) { url = url.slice(1); }
`
965
``
`-
if ( url === docURL ) {
`
966
``
`-
url = 'inlineScript';
`
967
``
`-
} else if ( url.startsWith('') ) {
`
968
``
`-
url = 'injectedScript';
`
969
``
`-
}
`
970
``
`-
let fn = match[1] !== undefined
`
971
``
`-
? match[1].slice(0, -1)
`
972
``
`-
: line.slice(0, match.index).trim();
`
973
``
`-
if ( fn.startsWith('at') ) { fn = fn.slice(2).trim(); }
`
974
``
`-
let rowcol = match[3];
`
975
``
`` -
lines.push(' ' + ${fn} <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>u</mi><mi>r</mi><mi>l</mi></mrow><annotation encoding="application/x-tex">{url}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord"><span class="mord mathnormal">u</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span></span></span></span></span>{rowcol}:1.trim());
``
976
``
`-
}
`
977
``
`` -
lines[0] = stackDepth:${lines.length-1};
``
978
``
`-
const stack = lines.join('\t');
`
979
``
`-
const r = safe.RegExp_test.call(reNeedle, stack);
`
980
``
`-
if (
`
981
``
`-
logLevel === '1' ||
`
982
``
`-
logLevel === '2' && r ||
`
983
``
`-
logLevel === '3' && !r
`
984
``
`-
) {
`
985
``
`-
safe.uboLog(stack.replace(/\t/g, '\n'));
`
986
``
`-
}
`
987
``
`-
return r;
`
988
``
`-
};
`
989
1008
`const makeProxy = function(owner, chain) {
`
990
1009
`const pos = chain.indexOf('.');
`
991
1010
`if ( pos === -1 ) {
`
992
1011
`let v = owner[chain];
`
993
1012
`Object.defineProperty(owner, chain, {
`
994
1013
`get: function() {
`
995
``
`-
if ( mustAbort(new ErrorCtor(exceptionToken)) ) {
`
996
``
`-
throw new ReferenceError(exceptionToken);
`
``
1014
`+
if ( matchesStackTrace(reNeedle, logLevel) ) {
`
``
1015
`+
throw new ReferenceError(getExceptionToken());
`
997
1016
`}
`
998
1017
`return v;
`
999
1018
`},
`
1000
1019
`set: function(a) {
`
1001
``
`-
if ( mustAbort(new ErrorCtor(exceptionToken)) ) {
`
1002
``
`-
throw new ReferenceError(exceptionToken);
`
``
1020
`+
if ( matchesStackTrace(reNeedle, logLevel) ) {
`
``
1021
`+
throw new ReferenceError(getExceptionToken());
`
1003
1022
`}
`
1004
1023
`v = a;
`
1005
1024
`},
`
`@@ -1114,21 +1133,23 @@ builtinScriptlets.push({
`
1114
1133
`// - Add support for "remove everything if needle matches" case
`
1115
1134
`function jsonPrune(
`
1116
1135
`rawPrunePaths = '',
`
1117
``
`-
rawNeedlePaths = ''
`
``
1136
`+
rawNeedlePaths = '',
`
``
1137
`+
stackNeedle = ''
`
1118
1138
`) {
`
1119
1139
`JSON.parse = new Proxy(JSON.parse, {
`
1120
1140
`apply: function(target, thisArg, args) {
`
1121
1141
`return objectPrune(
`
1122
1142
`Reflect.apply(target, thisArg, args),
`
1123
1143
`rawPrunePaths,
`
1124
``
`-
rawNeedlePaths
`
``
1144
`+
rawNeedlePaths,
`
``
1145
`+
stackNeedle
`
1125
1146
`);
`
1126
1147
`},
`
1127
1148
`});
`
1128
1149
`Response.prototype.json = new Proxy(Response.prototype.json, {
`
1129
1150
`apply: function(target, thisArg, args) {
`
1130
1151
`return Reflect.apply(target, thisArg, args).then(o =>
`
1131
``
`-
objectPrune(o, rawPrunePaths, rawNeedlePaths)
`
``
1152
`+
objectPrune(o, rawPrunePaths, rawNeedlePaths, stackNeedle)
`
1132
1153
`);
`
1133
1154
`},
`
1134
1155
`});
`