@browserless.io/browserless 2.20.2 → 2.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -1
- package/bin/browserless.js +2 -1
- package/build/browserless.js +3 -2
- package/build/browsers/index.d.ts +3 -2
- package/build/browsers/index.js +3 -1
- package/build/routes/chrome/http/content.post.body.json +8 -8
- package/build/routes/chrome/http/pdf.post.body.json +8 -8
- package/build/routes/chrome/http/scrape.post.body.json +8 -8
- package/build/routes/chrome/http/screenshot.post.body.json +8 -8
- package/build/routes/chrome/tests/pdf.spec.js +24 -12
- package/build/routes/chromium/http/content.post.body.json +8 -8
- package/build/routes/chromium/http/pdf.post.body.json +8 -8
- package/build/routes/chromium/http/scrape.post.body.json +8 -8
- package/build/routes/chromium/http/screenshot.post.body.json +8 -8
- package/build/routes/chromium/tests/pdf.spec.js +24 -12
- package/build/shared/pdf.http.js +10 -5
- package/extensions/ublock/_locales/ar/messages.json +5 -1
- package/extensions/ublock/_locales/az/messages.json +4 -0
- package/extensions/ublock/_locales/be/messages.json +4 -0
- package/extensions/ublock/_locales/bg/messages.json +4 -0
- package/extensions/ublock/_locales/bn/messages.json +4 -0
- package/extensions/ublock/_locales/br_FR/messages.json +9 -5
- package/extensions/ublock/_locales/bs/messages.json +4 -0
- package/extensions/ublock/_locales/ca/messages.json +5 -1
- package/extensions/ublock/_locales/cs/messages.json +4 -0
- package/extensions/ublock/_locales/cv/messages.json +4 -0
- package/extensions/ublock/_locales/cy/messages.json +4 -0
- package/extensions/ublock/_locales/da/messages.json +4 -0
- package/extensions/ublock/_locales/de/messages.json +4 -0
- package/extensions/ublock/_locales/el/messages.json +8 -4
- package/extensions/ublock/_locales/en/messages.json +4 -0
- package/extensions/ublock/_locales/en_GB/messages.json +4 -0
- package/extensions/ublock/_locales/eo/messages.json +9 -5
- package/extensions/ublock/_locales/es/messages.json +4 -0
- package/extensions/ublock/_locales/et/messages.json +4 -0
- package/extensions/ublock/_locales/eu/messages.json +4 -0
- package/extensions/ublock/_locales/fa/messages.json +4 -0
- package/extensions/ublock/_locales/fi/messages.json +6 -2
- package/extensions/ublock/_locales/fil/messages.json +4 -0
- package/extensions/ublock/_locales/fr/messages.json +4 -0
- package/extensions/ublock/_locales/fy/messages.json +4 -0
- package/extensions/ublock/_locales/gl/messages.json +12 -8
- package/extensions/ublock/_locales/gu/messages.json +4 -0
- package/extensions/ublock/_locales/he/messages.json +4 -0
- package/extensions/ublock/_locales/hi/messages.json +4 -0
- package/extensions/ublock/_locales/hr/messages.json +4 -0
- package/extensions/ublock/_locales/hu/messages.json +68 -64
- package/extensions/ublock/_locales/hy/messages.json +4 -0
- package/extensions/ublock/_locales/id/messages.json +6 -2
- package/extensions/ublock/_locales/it/messages.json +4 -0
- package/extensions/ublock/_locales/ja/messages.json +4 -0
- package/extensions/ublock/_locales/ka/messages.json +4 -0
- package/extensions/ublock/_locales/kk/messages.json +4 -0
- package/extensions/ublock/_locales/kn/messages.json +4 -0
- package/extensions/ublock/_locales/ko/messages.json +4 -0
- package/extensions/ublock/_locales/lt/messages.json +4 -0
- package/extensions/ublock/_locales/lv/messages.json +4 -0
- package/extensions/ublock/_locales/mk/messages.json +4 -0
- package/extensions/ublock/_locales/ml/messages.json +4 -0
- package/extensions/ublock/_locales/mr/messages.json +4 -0
- package/extensions/ublock/_locales/ms/messages.json +4 -0
- package/extensions/ublock/_locales/nb/messages.json +4 -0
- package/extensions/ublock/_locales/nl/messages.json +4 -0
- package/extensions/ublock/_locales/no/messages.json +4 -0
- package/extensions/ublock/_locales/oc/messages.json +4 -0
- package/extensions/ublock/_locales/pa/messages.json +8 -4
- package/extensions/ublock/_locales/pl/messages.json +4 -0
- package/extensions/ublock/_locales/pt_BR/messages.json +4 -0
- package/extensions/ublock/_locales/pt_PT/messages.json +4 -0
- package/extensions/ublock/_locales/ro/messages.json +4 -0
- package/extensions/ublock/_locales/ru/messages.json +4 -0
- package/extensions/ublock/_locales/si/messages.json +4 -0
- package/extensions/ublock/_locales/sk/messages.json +4 -0
- package/extensions/ublock/_locales/sl/messages.json +4 -0
- package/extensions/ublock/_locales/so/messages.json +4 -0
- package/extensions/ublock/_locales/sq/messages.json +4 -0
- package/extensions/ublock/_locales/sr/messages.json +6 -2
- package/extensions/ublock/_locales/sv/messages.json +4 -0
- package/extensions/ublock/_locales/sw/messages.json +4 -0
- package/extensions/ublock/_locales/ta/messages.json +4 -0
- package/extensions/ublock/_locales/te/messages.json +4 -0
- package/extensions/ublock/_locales/th/messages.json +4 -0
- package/extensions/ublock/_locales/tr/messages.json +4 -0
- package/extensions/ublock/_locales/uk/messages.json +4 -0
- package/extensions/ublock/_locales/ur/messages.json +4 -0
- package/extensions/ublock/_locales/vi/messages.json +4 -0
- package/extensions/ublock/_locales/zh_CN/messages.json +4 -0
- package/extensions/ublock/_locales/zh_TW/messages.json +5 -1
- package/extensions/ublock/assets/assets.json +8 -6
- package/extensions/ublock/assets/resources/scriptlets.js +455 -301
- package/extensions/ublock/assets/thirdparties/easylist/easylist.txt +4441 -6643
- package/extensions/ublock/assets/thirdparties/easylist/easyprivacy.txt +401 -307
- package/extensions/ublock/assets/thirdparties/pgl.yoyo.org/as/serverlist +34 -29
- package/extensions/ublock/assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat +682 -709
- package/extensions/ublock/assets/thirdparties/urlhaus-filter/urlhaus-filter-online.txt +2439 -1999
- package/extensions/ublock/assets/ublock/badlists.txt +7 -0
- package/extensions/ublock/assets/ublock/badware.min.txt +992 -552
- package/extensions/ublock/assets/ublock/filters.min.txt +1253 -864
- package/extensions/ublock/assets/ublock/privacy.min.txt +58 -31
- package/extensions/ublock/assets/ublock/quick-fixes.min.txt +118 -126
- package/extensions/ublock/assets/ublock/unbreak.min.txt +129 -109
- package/extensions/ublock/js/background.js +4 -3
- package/extensions/ublock/js/benchmarks.js +29 -29
- package/extensions/ublock/js/codemirror/ubo-static-filtering.js +1 -0
- package/extensions/ublock/js/contextmenu.js +20 -21
- package/extensions/ublock/js/devtools.js +137 -3
- package/extensions/ublock/js/filtering-context.js +98 -43
- package/extensions/ublock/js/logger-ui.js +1 -1
- package/extensions/ublock/js/messaging.js +57 -135
- package/extensions/ublock/js/pagestore.js +44 -31
- package/extensions/ublock/js/redirect-resources.js +14 -4
- package/extensions/ublock/js/scriptlet-filtering.js +4 -1
- package/extensions/ublock/js/static-filtering-parser.js +107 -37
- package/extensions/ublock/js/static-net-filtering.js +514 -250
- package/extensions/ublock/js/storage.js +2 -1
- package/extensions/ublock/js/traffic.js +8 -4
- package/extensions/ublock/js/vapi-background.js +1 -0
- package/extensions/ublock/js/vapi-common.js +1 -0
- package/extensions/ublock/logger-ui.html +2 -3
- package/extensions/ublock/manifest.json +2 -2
- package/extensions/ublock/support.html +1 -0
- package/extensions/ublock/web_accessible_resources/noop-vast2.xml +1 -0
- package/extensions/ublock/web_accessible_resources/noop-vast3.xml +1 -0
- package/extensions/ublock/web_accessible_resources/noop-vast4.xml +1 -0
- package/package.json +16 -16
- package/src/browserless.ts +3 -2
- package/src/browsers/index.ts +2 -0
- package/src/routes/chrome/tests/pdf.spec.ts +24 -12
- package/src/routes/chromium/tests/pdf.spec.ts +24 -12
- package/src/shared/pdf.http.ts +10 -6
- package/static/docs/swagger.json +10 -10
- package/static/docs/swagger.min.json +9 -9
- package/static/function/client.js +9 -9
- package/static/function/index.html +9 -9
- /package/extensions/ublock/web_accessible_resources/{noop-vmap1.0.xml → noop-vmap1.xml} +0 -0
|
@@ -97,7 +97,7 @@ function safeSelf() {
|
|
|
97
97
|
},
|
|
98
98
|
initPattern(pattern, options = {}) {
|
|
99
99
|
if ( pattern === '' ) {
|
|
100
|
-
return { matchAll: true };
|
|
100
|
+
return { matchAll: true, expect: true };
|
|
101
101
|
}
|
|
102
102
|
const expect = (options.canNegate !== true || pattern.startsWith('!') === false);
|
|
103
103
|
if ( expect === false ) {
|
|
@@ -163,6 +163,12 @@ function safeSelf() {
|
|
|
163
163
|
}
|
|
164
164
|
return self.requestAnimationFrame(fn);
|
|
165
165
|
},
|
|
166
|
+
offIdle(id) {
|
|
167
|
+
if ( self.requestIdleCallback ) {
|
|
168
|
+
return self.cancelIdleCallback(id);
|
|
169
|
+
}
|
|
170
|
+
return self.cancelAnimationFrame(id);
|
|
171
|
+
}
|
|
166
172
|
};
|
|
167
173
|
scriptletGlobals.safeSelf = safe;
|
|
168
174
|
if ( scriptletGlobals.bcSecret === undefined ) { return safe; }
|
|
@@ -170,9 +176,18 @@ function safeSelf() {
|
|
|
170
176
|
const bc = new self.BroadcastChannel(scriptletGlobals.bcSecret);
|
|
171
177
|
let bcBuffer = [];
|
|
172
178
|
safe.logLevel = scriptletGlobals.logLevel || 1;
|
|
179
|
+
let lastLogType = '';
|
|
180
|
+
let lastLogText = '';
|
|
181
|
+
let lastLogTime = 0;
|
|
173
182
|
safe.sendToLogger = (type, ...args) => {
|
|
174
183
|
if ( args.length === 0 ) { return; }
|
|
175
184
|
const text = `[${document.location.hostname || document.location.href}]${args.join(' ')}`;
|
|
185
|
+
if ( text === lastLogText && type === lastLogType ) {
|
|
186
|
+
if ( (Date.now() - lastLogTime) < 5000 ) { return; }
|
|
187
|
+
}
|
|
188
|
+
lastLogType = type;
|
|
189
|
+
lastLogText = text;
|
|
190
|
+
lastLogTime = Date.now();
|
|
176
191
|
if ( bcBuffer === undefined ) {
|
|
177
192
|
return bc.postMessage({ what: 'messageToLogger', type, text });
|
|
178
193
|
}
|
|
@@ -203,17 +218,28 @@ function safeSelf() {
|
|
|
203
218
|
/******************************************************************************/
|
|
204
219
|
|
|
205
220
|
builtinScriptlets.push({
|
|
206
|
-
name: 'get-
|
|
207
|
-
fn:
|
|
221
|
+
name: 'get-random-token.fn',
|
|
222
|
+
fn: getRandomToken,
|
|
208
223
|
dependencies: [
|
|
209
224
|
'safe-self.fn',
|
|
210
225
|
],
|
|
211
226
|
});
|
|
212
|
-
function
|
|
227
|
+
function getRandomToken() {
|
|
213
228
|
const safe = safeSelf();
|
|
214
|
-
|
|
215
|
-
safe.String_fromCharCode(Date.now() % 26 + 97) +
|
|
229
|
+
return safe.String_fromCharCode(Date.now() % 26 + 97) +
|
|
216
230
|
safe.Math_floor(safe.Math_random() * 982451653 + 982451653).toString(36);
|
|
231
|
+
}
|
|
232
|
+
/******************************************************************************/
|
|
233
|
+
|
|
234
|
+
builtinScriptlets.push({
|
|
235
|
+
name: 'get-exception-token.fn',
|
|
236
|
+
fn: getExceptionToken,
|
|
237
|
+
dependencies: [
|
|
238
|
+
'get-random-token.fn',
|
|
239
|
+
],
|
|
240
|
+
});
|
|
241
|
+
function getExceptionToken() {
|
|
242
|
+
const token = getRandomToken();
|
|
217
243
|
const oe = self.onerror;
|
|
218
244
|
self.onerror = function(msg, ...args) {
|
|
219
245
|
if ( typeof msg === 'string' && msg.includes(token) ) { return true; }
|
|
@@ -247,7 +273,7 @@ builtinScriptlets.push({
|
|
|
247
273
|
function runAt(fn, when) {
|
|
248
274
|
const intFromReadyState = state => {
|
|
249
275
|
const targets = {
|
|
250
|
-
'loading': 1,
|
|
276
|
+
'loading': 1, 'asap': 1,
|
|
251
277
|
'interactive': 2, 'end': 2, '2': 2,
|
|
252
278
|
'complete': 3, 'idle': 3, '3': 3,
|
|
253
279
|
};
|
|
@@ -509,12 +535,16 @@ function validateConstantFn(trusted, raw, extraArgs = {}) {
|
|
|
509
535
|
value = function(){ return true; };
|
|
510
536
|
} else if ( raw === 'falseFunc' ) {
|
|
511
537
|
value = function(){ return false; };
|
|
538
|
+
} else if ( raw === 'throwFunc' ) {
|
|
539
|
+
value = function(){ throw ''; };
|
|
512
540
|
} else if ( /^-?\d+$/.test(raw) ) {
|
|
513
541
|
value = parseInt(raw);
|
|
514
542
|
if ( isNaN(raw) ) { return; }
|
|
515
543
|
if ( Math.abs(raw) > 0x7FFF ) { return; }
|
|
516
544
|
} else if ( trusted ) {
|
|
517
|
-
if ( raw.startsWith('
|
|
545
|
+
if ( raw.startsWith('json:') ) {
|
|
546
|
+
try { value = safe.JSON_parse(raw.slice(5)); } catch(ex) { return; }
|
|
547
|
+
} else if ( raw.startsWith('{') && raw.endsWith('}') ) {
|
|
518
548
|
try { value = safe.JSON_parse(raw).value; } catch(ex) { return; }
|
|
519
549
|
}
|
|
520
550
|
} else {
|
|
@@ -701,6 +731,7 @@ builtinScriptlets.push({
|
|
|
701
731
|
name: 'replace-node-text.fn',
|
|
702
732
|
fn: replaceNodeTextFn,
|
|
703
733
|
dependencies: [
|
|
734
|
+
'get-random-token.fn',
|
|
704
735
|
'run-at.fn',
|
|
705
736
|
'safe-self.fn',
|
|
706
737
|
],
|
|
@@ -730,6 +761,18 @@ function replaceNodeTextFn(
|
|
|
730
761
|
safe.uboLog(logPrefix, 'Quitting');
|
|
731
762
|
}
|
|
732
763
|
};
|
|
764
|
+
const textContentFactory = (( ) => {
|
|
765
|
+
const out = { createScript: s => s };
|
|
766
|
+
const { trustedTypes: tt } = self;
|
|
767
|
+
if ( tt instanceof Object ) {
|
|
768
|
+
if ( typeof tt.getPropertyType === 'function' ) {
|
|
769
|
+
if ( tt.getPropertyType('script', 'textContent') === 'TrustedScript' ) {
|
|
770
|
+
return tt.createPolicy(getRandomToken(), out);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
return out;
|
|
775
|
+
})();
|
|
733
776
|
let sedCount = extraArgs.sedCount || 0;
|
|
734
777
|
const handleNode = node => {
|
|
735
778
|
const before = node.textContent;
|
|
@@ -747,7 +790,9 @@ function replaceNodeTextFn(
|
|
|
747
790
|
const after = pattern !== ''
|
|
748
791
|
? before.replace(rePattern, replacement)
|
|
749
792
|
: replacement;
|
|
750
|
-
node.textContent =
|
|
793
|
+
node.textContent = node.nodeName === 'SCRIPT'
|
|
794
|
+
? textContentFactory.createScript(after)
|
|
795
|
+
: after;
|
|
751
796
|
if ( safe.logLevel > 1 ) {
|
|
752
797
|
safe.uboLog(logPrefix, `Text before:\n${before.trim()}`);
|
|
753
798
|
}
|
|
@@ -922,6 +967,33 @@ function objectFindOwnerFn(
|
|
|
922
967
|
|
|
923
968
|
/******************************************************************************/
|
|
924
969
|
|
|
970
|
+
builtinScriptlets.push({
|
|
971
|
+
name: 'get-safe-cookie-values.fn',
|
|
972
|
+
fn: getSafeCookieValuesFn,
|
|
973
|
+
});
|
|
974
|
+
function getSafeCookieValuesFn() {
|
|
975
|
+
return [
|
|
976
|
+
'accept', 'reject',
|
|
977
|
+
'accepted', 'rejected', 'notaccepted',
|
|
978
|
+
'allow', 'disallow', 'deny',
|
|
979
|
+
'allowed', 'denied',
|
|
980
|
+
'approved', 'disapproved',
|
|
981
|
+
'checked', 'unchecked',
|
|
982
|
+
'dismiss', 'dismissed',
|
|
983
|
+
'enable', 'disable',
|
|
984
|
+
'enabled', 'disabled',
|
|
985
|
+
'essential', 'nonessential',
|
|
986
|
+
'hide', 'hidden',
|
|
987
|
+
'necessary', 'required',
|
|
988
|
+
'ok',
|
|
989
|
+
'on', 'off',
|
|
990
|
+
'true', 't', 'false', 'f',
|
|
991
|
+
'yes', 'y', 'no', 'n',
|
|
992
|
+
];
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
/******************************************************************************/
|
|
996
|
+
|
|
925
997
|
builtinScriptlets.push({
|
|
926
998
|
name: 'get-all-cookies.fn',
|
|
927
999
|
fn: getAllCookiesFn,
|
|
@@ -1044,6 +1116,7 @@ builtinScriptlets.push({
|
|
|
1044
1116
|
name: 'set-local-storage-item.fn',
|
|
1045
1117
|
fn: setLocalStorageItemFn,
|
|
1046
1118
|
dependencies: [
|
|
1119
|
+
'get-safe-cookie-values.fn',
|
|
1047
1120
|
'safe-self.fn',
|
|
1048
1121
|
],
|
|
1049
1122
|
});
|
|
@@ -1065,13 +1138,9 @@ function setLocalStorageItemFn(
|
|
|
1065
1138
|
const trustedValues = [
|
|
1066
1139
|
'',
|
|
1067
1140
|
'undefined', 'null',
|
|
1068
|
-
'false', 'true',
|
|
1069
|
-
'on', 'off',
|
|
1070
|
-
'yes', 'no',
|
|
1071
|
-
'accept', 'reject',
|
|
1072
|
-
'accepted', 'rejected',
|
|
1073
1141
|
'{}', '[]', '""',
|
|
1074
1142
|
'$remove$',
|
|
1143
|
+
...getSafeCookieValuesFn(),
|
|
1075
1144
|
];
|
|
1076
1145
|
|
|
1077
1146
|
if ( trusted ) {
|
|
@@ -1414,9 +1483,6 @@ function replaceFetchResponseFn(
|
|
|
1414
1483
|
builtinScriptlets.push({
|
|
1415
1484
|
name: 'proxy-apply.fn',
|
|
1416
1485
|
fn: proxyApplyFn,
|
|
1417
|
-
dependencies: [
|
|
1418
|
-
'safe-self.fn',
|
|
1419
|
-
],
|
|
1420
1486
|
});
|
|
1421
1487
|
function proxyApplyFn(
|
|
1422
1488
|
target = '',
|
|
@@ -1433,12 +1499,70 @@ function proxyApplyFn(
|
|
|
1433
1499
|
}
|
|
1434
1500
|
const fn = context[prop];
|
|
1435
1501
|
if ( typeof fn !== 'function' ) { return; }
|
|
1436
|
-
if (
|
|
1437
|
-
|
|
1438
|
-
|
|
1502
|
+
if ( proxyApplyFn.CtorContext === undefined ) {
|
|
1503
|
+
proxyApplyFn.ctorContexts = [];
|
|
1504
|
+
proxyApplyFn.CtorContext = class {
|
|
1505
|
+
constructor(...args) {
|
|
1506
|
+
this.init(...args);
|
|
1507
|
+
}
|
|
1508
|
+
init(callFn, callArgs) {
|
|
1509
|
+
this.callFn = callFn;
|
|
1510
|
+
this.callArgs = callArgs;
|
|
1511
|
+
return this;
|
|
1512
|
+
}
|
|
1513
|
+
reflect() {
|
|
1514
|
+
const r = Reflect.construct(this.callFn, this.callArgs);
|
|
1515
|
+
this.callFn = this.callArgs = undefined;
|
|
1516
|
+
proxyApplyFn.ctorContexts.push(this);
|
|
1517
|
+
return r;
|
|
1518
|
+
}
|
|
1519
|
+
static factory(...args) {
|
|
1520
|
+
return proxyApplyFn.ctorContexts.length !== 0
|
|
1521
|
+
? proxyApplyFn.ctorContexts.pop().init(...args)
|
|
1522
|
+
: new proxyApplyFn.CtorContext(...args);
|
|
1523
|
+
}
|
|
1524
|
+
};
|
|
1525
|
+
proxyApplyFn.applyContexts = [];
|
|
1526
|
+
proxyApplyFn.ApplyContext = class {
|
|
1527
|
+
constructor(...args) {
|
|
1528
|
+
this.init(...args);
|
|
1529
|
+
}
|
|
1530
|
+
init(callFn, thisArg, callArgs) {
|
|
1531
|
+
this.callFn = callFn;
|
|
1532
|
+
this.thisArg = thisArg;
|
|
1533
|
+
this.callArgs = callArgs;
|
|
1534
|
+
return this;
|
|
1535
|
+
}
|
|
1536
|
+
reflect() {
|
|
1537
|
+
const r = Reflect.apply(this.callFn, this.thisArg, this.callArgs);
|
|
1538
|
+
this.callFn = this.thisArg = this.callArgs = undefined;
|
|
1539
|
+
proxyApplyFn.applyContexts.push(this);
|
|
1540
|
+
return r;
|
|
1541
|
+
}
|
|
1542
|
+
static factory(...args) {
|
|
1543
|
+
return proxyApplyFn.applyContexts.length !== 0
|
|
1544
|
+
? proxyApplyFn.applyContexts.pop().init(...args)
|
|
1545
|
+
: new proxyApplyFn.ApplyContext(...args);
|
|
1546
|
+
}
|
|
1547
|
+
};
|
|
1548
|
+
}
|
|
1549
|
+
const fnStr = fn.toString();
|
|
1550
|
+
const toString = (function toString() { return fnStr; }).bind(null);
|
|
1551
|
+
const proxyDetails = {
|
|
1552
|
+
apply(target, thisArg, args) {
|
|
1553
|
+
return handler(proxyApplyFn.ApplyContext.factory(target, thisArg, args));
|
|
1554
|
+
},
|
|
1555
|
+
get(target, prop) {
|
|
1556
|
+
if ( prop === 'toString' ) { return toString; }
|
|
1557
|
+
return Reflect.get(target, prop);
|
|
1558
|
+
},
|
|
1559
|
+
};
|
|
1560
|
+
if ( fn.prototype?.constructor === fn ) {
|
|
1561
|
+
proxyDetails.construct = function(target, args) {
|
|
1562
|
+
return handler(proxyApplyFn.CtorContext.factory(target, args));
|
|
1563
|
+
};
|
|
1439
1564
|
}
|
|
1440
|
-
context[prop] = new Proxy(fn,
|
|
1441
|
-
return (...args) => { return Reflect.apply(...args); };
|
|
1565
|
+
context[prop] = new Proxy(fn, proxyDetails);
|
|
1442
1566
|
}
|
|
1443
1567
|
|
|
1444
1568
|
/*******************************************************************************
|
|
@@ -1644,6 +1768,7 @@ builtinScriptlets.push({
|
|
|
1644
1768
|
],
|
|
1645
1769
|
fn: addEventListenerDefuser,
|
|
1646
1770
|
dependencies: [
|
|
1771
|
+
'proxy-apply.fn',
|
|
1647
1772
|
'run-at.fn',
|
|
1648
1773
|
'safe-self.fn',
|
|
1649
1774
|
'should-debug.fn',
|
|
@@ -1700,44 +1825,30 @@ function addEventListenerDefuser(
|
|
|
1700
1825
|
}
|
|
1701
1826
|
return matchesBoth;
|
|
1702
1827
|
};
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
}
|
|
1715
|
-
} else {
|
|
1716
|
-
h = String(args[1]);
|
|
1828
|
+
runAt(( ) => {
|
|
1829
|
+
proxyApplyFn('EventTarget.prototype.addEventListener', function(context) {
|
|
1830
|
+
const { callArgs, thisArg } = context;
|
|
1831
|
+
let t, h;
|
|
1832
|
+
try {
|
|
1833
|
+
t = String(callArgs[0]);
|
|
1834
|
+
if ( typeof callArgs[1] === 'function' ) {
|
|
1835
|
+
h = String(safe.Function_toString(callArgs[1]));
|
|
1836
|
+
} else if ( typeof callArgs[1] === 'object' && callArgs[1] !== null ) {
|
|
1837
|
+
if ( typeof callArgs[1].handleEvent === 'function' ) {
|
|
1838
|
+
h = String(safe.Function_toString(callArgs[1].handleEvent));
|
|
1717
1839
|
}
|
|
1718
|
-
}
|
|
1719
|
-
|
|
1720
|
-
if ( type === '' && pattern === '' ) {
|
|
1721
|
-
safe.uboLog(logPrefix, `Called: ${t}\n${h}\n${elementDetails(thisArg)}`);
|
|
1722
|
-
} else if ( shouldPrevent(thisArg, t, h) ) {
|
|
1723
|
-
return safe.uboLog(logPrefix, `Prevented: ${t}\n${h}\n${elementDetails(thisArg)}`);
|
|
1724
|
-
}
|
|
1725
|
-
return Reflect.apply(target, thisArg, args);
|
|
1726
|
-
},
|
|
1727
|
-
get(target, prop, receiver) {
|
|
1728
|
-
if ( prop === 'toString' ) {
|
|
1729
|
-
return target.toString.bind(target);
|
|
1840
|
+
} else {
|
|
1841
|
+
h = String(callArgs[1]);
|
|
1730
1842
|
}
|
|
1731
|
-
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
trapEddEventListeners();
|
|
1843
|
+
} catch(ex) {
|
|
1844
|
+
}
|
|
1845
|
+
if ( type === '' && pattern === '' ) {
|
|
1846
|
+
safe.uboLog(logPrefix, `Called: ${t}\n${h}\n${elementDetails(thisArg)}`);
|
|
1847
|
+
} else if ( shouldPrevent(thisArg, t, h) ) {
|
|
1848
|
+
return safe.uboLog(logPrefix, `Prevented: ${t}\n${h}\n${elementDetails(thisArg)}`);
|
|
1849
|
+
}
|
|
1850
|
+
return context.reflect();
|
|
1851
|
+
});
|
|
1741
1852
|
}, extraArgs.runAt);
|
|
1742
1853
|
}
|
|
1743
1854
|
|
|
@@ -2074,6 +2185,7 @@ builtinScriptlets.push({
|
|
|
2074
2185
|
fn: noFetchIf,
|
|
2075
2186
|
dependencies: [
|
|
2076
2187
|
'generate-content.fn',
|
|
2188
|
+
'proxy-apply.fn',
|
|
2077
2189
|
'safe-self.fn',
|
|
2078
2190
|
],
|
|
2079
2191
|
});
|
|
@@ -2096,7 +2208,7 @@ function noFetchIf(
|
|
|
2096
2208
|
key = 'url';
|
|
2097
2209
|
value = condition;
|
|
2098
2210
|
}
|
|
2099
|
-
needles.push({ key,
|
|
2211
|
+
needles.push({ key, pattern: safe.initPattern(value, { canNegate: true }) });
|
|
2100
2212
|
}
|
|
2101
2213
|
const validResponseProps = {
|
|
2102
2214
|
ok: [ false, true ],
|
|
@@ -2120,58 +2232,59 @@ function noFetchIf(
|
|
|
2120
2232
|
responseProps.type = { value: responseType };
|
|
2121
2233
|
}
|
|
2122
2234
|
}
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
}
|
|
2137
|
-
if ( typeof v !== 'string' ) { continue; }
|
|
2138
|
-
props.set(prop, v);
|
|
2139
|
-
}
|
|
2140
|
-
if ( propsToMatch === '' && responseBody === '' ) {
|
|
2141
|
-
const out = Array.from(props).map(a => `${a[0]}:${a[1]}`);
|
|
2142
|
-
safe.uboLog(logPrefix, `Called: ${out.join('\n')}`);
|
|
2143
|
-
return Reflect.apply(target, thisArg, args);
|
|
2144
|
-
}
|
|
2145
|
-
proceed = needles.length === 0;
|
|
2146
|
-
for ( const { key, re } of needles ) {
|
|
2147
|
-
if (
|
|
2148
|
-
props.has(key) === false ||
|
|
2149
|
-
re.test(props.get(key)) === false
|
|
2150
|
-
) {
|
|
2151
|
-
proceed = true;
|
|
2152
|
-
break;
|
|
2153
|
-
}
|
|
2235
|
+
proxyApplyFn('fetch', function fetch(context) {
|
|
2236
|
+
const { callArgs } = context;
|
|
2237
|
+
const details = callArgs[0] instanceof self.Request
|
|
2238
|
+
? callArgs[0]
|
|
2239
|
+
: Object.assign({ url: callArgs[0] }, callArgs[1]);
|
|
2240
|
+
let proceed = true;
|
|
2241
|
+
try {
|
|
2242
|
+
const props = new Map();
|
|
2243
|
+
for ( const prop in details ) {
|
|
2244
|
+
let v = details[prop];
|
|
2245
|
+
if ( typeof v !== 'string' ) {
|
|
2246
|
+
try { v = safe.JSON_stringify(v); }
|
|
2247
|
+
catch(ex) { }
|
|
2154
2248
|
}
|
|
2155
|
-
|
|
2249
|
+
if ( typeof v !== 'string' ) { continue; }
|
|
2250
|
+
props.set(prop, v);
|
|
2156
2251
|
}
|
|
2157
|
-
if (
|
|
2158
|
-
|
|
2252
|
+
if ( safe.logLevel > 1 || propsToMatch === '' && responseBody === '' ) {
|
|
2253
|
+
const out = Array.from(props).map(a => `${a[0]}:${a[1]}`);
|
|
2254
|
+
safe.uboLog(logPrefix, `Called: ${out.join('\n')}`);
|
|
2159
2255
|
}
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2256
|
+
if ( propsToMatch === '' && responseBody === '' ) {
|
|
2257
|
+
return context.reflect();
|
|
2258
|
+
}
|
|
2259
|
+
proceed = needles.length === 0;
|
|
2260
|
+
for ( const { key, pattern } of needles ) {
|
|
2261
|
+
if (
|
|
2262
|
+
pattern.expect && props.has(key) === false ||
|
|
2263
|
+
safe.testPattern(pattern, props.get(key)) === false
|
|
2264
|
+
) {
|
|
2265
|
+
proceed = true;
|
|
2266
|
+
break;
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
} catch(ex) {
|
|
2174
2270
|
}
|
|
2271
|
+
if ( proceed ) {
|
|
2272
|
+
return context.reflect();
|
|
2273
|
+
}
|
|
2274
|
+
return generateContentFn(responseBody).then(text => {
|
|
2275
|
+
safe.uboLog(logPrefix, `Prevented with response "${text}"`);
|
|
2276
|
+
const response = new Response(text, {
|
|
2277
|
+
headers: {
|
|
2278
|
+
'Content-Length': text.length,
|
|
2279
|
+
}
|
|
2280
|
+
});
|
|
2281
|
+
const props = Object.assign(
|
|
2282
|
+
{ url: { value: details.url } },
|
|
2283
|
+
responseProps
|
|
2284
|
+
);
|
|
2285
|
+
safe.Object_defineProperties(response, props);
|
|
2286
|
+
return response;
|
|
2287
|
+
});
|
|
2175
2288
|
});
|
|
2176
2289
|
}
|
|
2177
2290
|
|
|
@@ -2240,9 +2353,20 @@ function removeAttr(
|
|
|
2240
2353
|
if ( safe.logLevel > 1 ) {
|
|
2241
2354
|
safe.uboLog(logPrefix, `Target selector:\n\t${selector}`);
|
|
2242
2355
|
}
|
|
2243
|
-
|
|
2356
|
+
const asap = /\basap\b/.test(behavior);
|
|
2357
|
+
let timerId;
|
|
2358
|
+
const rmattrAsync = ( ) => {
|
|
2359
|
+
if ( timerId !== undefined ) { return; }
|
|
2360
|
+
timerId = safe.onIdle(( ) => {
|
|
2361
|
+
timerId = undefined;
|
|
2362
|
+
rmattr();
|
|
2363
|
+
}, { timeout: 17 });
|
|
2364
|
+
};
|
|
2244
2365
|
const rmattr = ( ) => {
|
|
2245
|
-
|
|
2366
|
+
if ( timerId !== undefined ) {
|
|
2367
|
+
safe.offIdle(timerId);
|
|
2368
|
+
timerId = undefined;
|
|
2369
|
+
}
|
|
2246
2370
|
try {
|
|
2247
2371
|
const nodes = document.querySelectorAll(selector);
|
|
2248
2372
|
for ( const node of nodes ) {
|
|
@@ -2256,7 +2380,7 @@ function removeAttr(
|
|
|
2256
2380
|
}
|
|
2257
2381
|
};
|
|
2258
2382
|
const mutationHandler = mutations => {
|
|
2259
|
-
if (
|
|
2383
|
+
if ( timerId !== undefined ) { return; }
|
|
2260
2384
|
let skip = true;
|
|
2261
2385
|
for ( let i = 0; i < mutations.length && skip; i++ ) {
|
|
2262
2386
|
const { type, addedNodes, removedNodes } = mutations[i];
|
|
@@ -2269,7 +2393,7 @@ function removeAttr(
|
|
|
2269
2393
|
}
|
|
2270
2394
|
}
|
|
2271
2395
|
if ( skip ) { return; }
|
|
2272
|
-
|
|
2396
|
+
asap ? rmattr() : rmattrAsync();
|
|
2273
2397
|
};
|
|
2274
2398
|
const start = ( ) => {
|
|
2275
2399
|
rmattr();
|
|
@@ -2282,9 +2406,7 @@ function removeAttr(
|
|
|
2282
2406
|
subtree: true,
|
|
2283
2407
|
});
|
|
2284
2408
|
};
|
|
2285
|
-
runAt(( ) => {
|
|
2286
|
-
start();
|
|
2287
|
-
}, /\bcomplete\b/.test(behavior) ? 'idle' : 'interactive');
|
|
2409
|
+
runAt(( ) => { start(); }, behavior.split(/\s+/));
|
|
2288
2410
|
}
|
|
2289
2411
|
|
|
2290
2412
|
/******************************************************************************/
|
|
@@ -2434,6 +2556,7 @@ builtinScriptlets.push({
|
|
|
2434
2556
|
],
|
|
2435
2557
|
fn: noSetIntervalIf,
|
|
2436
2558
|
dependencies: [
|
|
2559
|
+
'proxy-apply.fn',
|
|
2437
2560
|
'safe-self.fn',
|
|
2438
2561
|
],
|
|
2439
2562
|
});
|
|
@@ -2454,35 +2577,28 @@ function noSetIntervalIf(
|
|
|
2454
2577
|
delay = parseInt(delay, 10);
|
|
2455
2578
|
}
|
|
2456
2579
|
const reNeedle = safe.patternToRegex(needle);
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
},
|
|
2480
|
-
get(target, prop, receiver) {
|
|
2481
|
-
if ( prop === 'toString' ) {
|
|
2482
|
-
return target.toString.bind(target);
|
|
2483
|
-
}
|
|
2484
|
-
return Reflect.get(target, prop, receiver);
|
|
2485
|
-
},
|
|
2580
|
+
proxyApplyFn('setInterval', function setInterval(context) {
|
|
2581
|
+
const { callArgs } = context;
|
|
2582
|
+
const a = callArgs[0] instanceof Function
|
|
2583
|
+
? String(safe.Function_toString(callArgs[0]))
|
|
2584
|
+
: String(callArgs[0]);
|
|
2585
|
+
const b = callArgs[1];
|
|
2586
|
+
if ( needle === '' && delay === undefined ) {
|
|
2587
|
+
safe.uboLog(logPrefix, `Called:\n${a}\n${b}`);
|
|
2588
|
+
return context.reflect();
|
|
2589
|
+
}
|
|
2590
|
+
let defuse;
|
|
2591
|
+
if ( needle !== '' ) {
|
|
2592
|
+
defuse = reNeedle.test(a) !== needleNot;
|
|
2593
|
+
}
|
|
2594
|
+
if ( defuse !== false && delay !== undefined ) {
|
|
2595
|
+
defuse = (b === delay || isNaN(b) && isNaN(delay) ) !== delayNot;
|
|
2596
|
+
}
|
|
2597
|
+
if ( defuse ) {
|
|
2598
|
+
callArgs[0] = function(){};
|
|
2599
|
+
safe.uboLog(logPrefix, `Prevented:\n${a}\n${b}`);
|
|
2600
|
+
}
|
|
2601
|
+
return context.reflect();
|
|
2486
2602
|
});
|
|
2487
2603
|
}
|
|
2488
2604
|
|
|
@@ -2497,6 +2613,7 @@ builtinScriptlets.push({
|
|
|
2497
2613
|
],
|
|
2498
2614
|
fn: noSetTimeoutIf,
|
|
2499
2615
|
dependencies: [
|
|
2616
|
+
'proxy-apply.fn',
|
|
2500
2617
|
'safe-self.fn',
|
|
2501
2618
|
],
|
|
2502
2619
|
});
|
|
@@ -2517,35 +2634,28 @@ function noSetTimeoutIf(
|
|
|
2517
2634
|
delay = parseInt(delay, 10);
|
|
2518
2635
|
}
|
|
2519
2636
|
const reNeedle = safe.patternToRegex(needle);
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
},
|
|
2543
|
-
get(target, prop, receiver) {
|
|
2544
|
-
if ( prop === 'toString' ) {
|
|
2545
|
-
return target.toString.bind(target);
|
|
2546
|
-
}
|
|
2547
|
-
return Reflect.get(target, prop, receiver);
|
|
2548
|
-
},
|
|
2637
|
+
proxyApplyFn('setTimeout', function setTimeout(context) {
|
|
2638
|
+
const { callArgs } = context;
|
|
2639
|
+
const a = callArgs[0] instanceof Function
|
|
2640
|
+
? String(safe.Function_toString(callArgs[0]))
|
|
2641
|
+
: String(callArgs[0]);
|
|
2642
|
+
const b = callArgs[1];
|
|
2643
|
+
if ( needle === '' && delay === undefined ) {
|
|
2644
|
+
safe.uboLog(logPrefix, `Called:\n${a}\n${b}`);
|
|
2645
|
+
return context.reflect();
|
|
2646
|
+
}
|
|
2647
|
+
let defuse;
|
|
2648
|
+
if ( needle !== '' ) {
|
|
2649
|
+
defuse = reNeedle.test(a) !== needleNot;
|
|
2650
|
+
}
|
|
2651
|
+
if ( defuse !== false && delay !== undefined ) {
|
|
2652
|
+
defuse = (b === delay || isNaN(b) && isNaN(delay) ) !== delayNot;
|
|
2653
|
+
}
|
|
2654
|
+
if ( defuse ) {
|
|
2655
|
+
callArgs[0] = function(){};
|
|
2656
|
+
safe.uboLog(logPrefix, `Prevented:\n${a}\n${b}`);
|
|
2657
|
+
}
|
|
2658
|
+
return context.reflect();
|
|
2549
2659
|
});
|
|
2550
2660
|
}
|
|
2551
2661
|
|
|
@@ -2647,6 +2757,13 @@ function noXhrIf(
|
|
|
2647
2757
|
'content-type': '',
|
|
2648
2758
|
'content-length': '',
|
|
2649
2759
|
};
|
|
2760
|
+
const safeDispatchEvent = (xhr, type) => {
|
|
2761
|
+
try {
|
|
2762
|
+
xhr.dispatchEvent(new Event(type));
|
|
2763
|
+
} catch(_) {
|
|
2764
|
+
}
|
|
2765
|
+
};
|
|
2766
|
+
const XHRBefore = XMLHttpRequest.prototype;
|
|
2650
2767
|
self.XMLHttpRequest = class extends self.XMLHttpRequest {
|
|
2651
2768
|
open(method, url, ...args) {
|
|
2652
2769
|
xhrInstances.delete(this);
|
|
@@ -2673,27 +2790,26 @@ function noXhrIf(
|
|
|
2673
2790
|
let promise = Promise.resolve({
|
|
2674
2791
|
xhr: this,
|
|
2675
2792
|
directive,
|
|
2676
|
-
|
|
2677
|
-
readyState: { value: 4 },
|
|
2793
|
+
response: {
|
|
2678
2794
|
response: { value: '' },
|
|
2679
2795
|
responseText: { value: '' },
|
|
2680
2796
|
responseXML: { value: null },
|
|
2681
2797
|
responseURL: { value: haystack.url },
|
|
2682
|
-
|
|
2683
|
-
statusText: { value: 'OK' },
|
|
2684
|
-
},
|
|
2798
|
+
}
|
|
2685
2799
|
});
|
|
2686
2800
|
switch ( this.responseType ) {
|
|
2687
2801
|
case 'arraybuffer':
|
|
2688
2802
|
promise = promise.then(details => {
|
|
2689
|
-
|
|
2803
|
+
const response = details.response;
|
|
2804
|
+
response.response.value = new ArrayBuffer(0);
|
|
2690
2805
|
return details;
|
|
2691
2806
|
});
|
|
2692
2807
|
haystack.headers['content-type'] = 'application/octet-stream';
|
|
2693
2808
|
break;
|
|
2694
2809
|
case 'blob':
|
|
2695
2810
|
promise = promise.then(details => {
|
|
2696
|
-
|
|
2811
|
+
const response = details.response;
|
|
2812
|
+
response.response.value = new Blob([]);
|
|
2697
2813
|
return details;
|
|
2698
2814
|
});
|
|
2699
2815
|
haystack.headers['content-type'] = 'application/octet-stream';
|
|
@@ -2702,8 +2818,9 @@ function noXhrIf(
|
|
|
2702
2818
|
promise = promise.then(details => {
|
|
2703
2819
|
const parser = new DOMParser();
|
|
2704
2820
|
const doc = parser.parseFromString('', 'text/html');
|
|
2705
|
-
|
|
2706
|
-
|
|
2821
|
+
const response = details.response;
|
|
2822
|
+
response.response.value = doc;
|
|
2823
|
+
response.responseXML.value = doc;
|
|
2707
2824
|
return details;
|
|
2708
2825
|
});
|
|
2709
2826
|
haystack.headers['content-type'] = 'text/html';
|
|
@@ -2711,8 +2828,9 @@ function noXhrIf(
|
|
|
2711
2828
|
}
|
|
2712
2829
|
case 'json':
|
|
2713
2830
|
promise = promise.then(details => {
|
|
2714
|
-
|
|
2715
|
-
|
|
2831
|
+
const response = details.response;
|
|
2832
|
+
response.response.value = {};
|
|
2833
|
+
response.responseText.value = '{}';
|
|
2716
2834
|
return details;
|
|
2717
2835
|
});
|
|
2718
2836
|
haystack.headers['content-type'] = 'application/json';
|
|
@@ -2721,8 +2839,9 @@ function noXhrIf(
|
|
|
2721
2839
|
if ( directive === '' ) { break; }
|
|
2722
2840
|
promise = promise.then(details => {
|
|
2723
2841
|
return generateContentFn(details.directive).then(text => {
|
|
2724
|
-
|
|
2725
|
-
|
|
2842
|
+
const response = details.response;
|
|
2843
|
+
response.response.value = text;
|
|
2844
|
+
response.responseText.value = text;
|
|
2726
2845
|
return details;
|
|
2727
2846
|
});
|
|
2728
2847
|
});
|
|
@@ -2730,11 +2849,35 @@ function noXhrIf(
|
|
|
2730
2849
|
break;
|
|
2731
2850
|
}
|
|
2732
2851
|
promise.then(details => {
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
details.xhr
|
|
2737
|
-
details
|
|
2852
|
+
Object.defineProperties(details.xhr, {
|
|
2853
|
+
readyState: { value: 1, configurable: true },
|
|
2854
|
+
});
|
|
2855
|
+
safeDispatchEvent(details.xhr, 'readystatechange');
|
|
2856
|
+
return details;
|
|
2857
|
+
}).then(details => {
|
|
2858
|
+
const response = details.response;
|
|
2859
|
+
haystack.headers['content-length'] = `${response.response.value}`.length;
|
|
2860
|
+
Object.defineProperties(details.xhr, {
|
|
2861
|
+
readyState: { value: 2, configurable: true },
|
|
2862
|
+
status: { value: 200 },
|
|
2863
|
+
statusText: { value: 'OK' },
|
|
2864
|
+
});
|
|
2865
|
+
safeDispatchEvent(details.xhr, 'readystatechange');
|
|
2866
|
+
return details;
|
|
2867
|
+
}).then(details => {
|
|
2868
|
+
Object.defineProperties(details.xhr, {
|
|
2869
|
+
readyState: { value: 3, configurable: true },
|
|
2870
|
+
});
|
|
2871
|
+
Object.defineProperties(details.xhr, details.response);
|
|
2872
|
+
safeDispatchEvent(details.xhr, 'readystatechange');
|
|
2873
|
+
return details;
|
|
2874
|
+
}).then(details => {
|
|
2875
|
+
Object.defineProperties(details.xhr, {
|
|
2876
|
+
readyState: { value: 4 },
|
|
2877
|
+
});
|
|
2878
|
+
safeDispatchEvent(details.xhr, 'readystatechange');
|
|
2879
|
+
safeDispatchEvent(details.xhr, 'load');
|
|
2880
|
+
safeDispatchEvent(details.xhr, 'loadend');
|
|
2738
2881
|
safe.uboLog(logPrefix, `Prevented with response:\n${details.xhr.response}`);
|
|
2739
2882
|
});
|
|
2740
2883
|
}
|
|
@@ -2761,6 +2904,18 @@ function noXhrIf(
|
|
|
2761
2904
|
return out.join('\r\n');
|
|
2762
2905
|
}
|
|
2763
2906
|
};
|
|
2907
|
+
self.XMLHttpRequest.prototype.open.toString = function() {
|
|
2908
|
+
return XHRBefore.open.toString();
|
|
2909
|
+
};
|
|
2910
|
+
self.XMLHttpRequest.prototype.send.toString = function() {
|
|
2911
|
+
return XHRBefore.send.toString();
|
|
2912
|
+
};
|
|
2913
|
+
self.XMLHttpRequest.prototype.getResponseHeader.toString = function() {
|
|
2914
|
+
return XHRBefore.getResponseHeader.toString();
|
|
2915
|
+
};
|
|
2916
|
+
self.XMLHttpRequest.prototype.getAllResponseHeaders.toString = function() {
|
|
2917
|
+
return XHRBefore.getAllResponseHeaders.toString();
|
|
2918
|
+
};
|
|
2764
2919
|
}
|
|
2765
2920
|
|
|
2766
2921
|
/******************************************************************************/
|
|
@@ -2774,6 +2929,7 @@ builtinScriptlets.push({
|
|
|
2774
2929
|
],
|
|
2775
2930
|
fn: noWindowOpenIf,
|
|
2776
2931
|
dependencies: [
|
|
2932
|
+
'proxy-apply.fn',
|
|
2777
2933
|
'safe-self.fn',
|
|
2778
2934
|
],
|
|
2779
2935
|
});
|
|
@@ -2789,10 +2945,8 @@ function noWindowOpenIf(
|
|
|
2789
2945
|
pattern = pattern.slice(1);
|
|
2790
2946
|
}
|
|
2791
2947
|
const rePattern = safe.patternToRegex(pattern);
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
autoRemoveAfter = -1;
|
|
2795
|
-
}
|
|
2948
|
+
const autoRemoveAfter = (parseFloat(delay) || 0) * 1000;
|
|
2949
|
+
const setTimeout = self.setTimeout;
|
|
2796
2950
|
const createDecoy = function(tag, urlProp, url) {
|
|
2797
2951
|
const decoyElem = document.createElement(tag);
|
|
2798
2952
|
decoyElem[urlProp] = url;
|
|
@@ -2801,54 +2955,63 @@ function noWindowOpenIf(
|
|
|
2801
2955
|
decoyElem.style.setProperty('top','-1px', 'important');
|
|
2802
2956
|
decoyElem.style.setProperty('width','1px', 'important');
|
|
2803
2957
|
document.body.appendChild(decoyElem);
|
|
2804
|
-
setTimeout(( ) => { decoyElem.remove(); }, autoRemoveAfter
|
|
2958
|
+
setTimeout(( ) => { decoyElem.remove(); }, autoRemoveAfter);
|
|
2805
2959
|
return decoyElem;
|
|
2806
2960
|
};
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
}
|
|
2814
|
-
return Reflect.apply(target, thisArg, args);
|
|
2815
|
-
}
|
|
2816
|
-
safe.uboLog(logPrefix, `Prevented (${args.join(', ')})`);
|
|
2817
|
-
if ( autoRemoveAfter < 0 ) { return null; }
|
|
2818
|
-
const decoyElem = decoy === 'obj'
|
|
2819
|
-
? createDecoy('object', 'data', ...args)
|
|
2820
|
-
: createDecoy('iframe', 'src', ...args);
|
|
2821
|
-
let popup = decoyElem.contentWindow;
|
|
2822
|
-
if ( typeof popup === 'object' && popup !== null ) {
|
|
2823
|
-
Object.defineProperty(popup, 'closed', { value: false });
|
|
2824
|
-
} else {
|
|
2825
|
-
const noopFunc = (function(){}).bind(self);
|
|
2826
|
-
popup = new Proxy(self, {
|
|
2827
|
-
get: function(target, prop) {
|
|
2828
|
-
if ( prop === 'closed' ) { return false; }
|
|
2829
|
-
const r = Reflect.get(...arguments);
|
|
2830
|
-
if ( typeof r === 'function' ) { return noopFunc; }
|
|
2831
|
-
return target[prop];
|
|
2832
|
-
},
|
|
2833
|
-
set: function() {
|
|
2834
|
-
return Reflect.set(...arguments);
|
|
2835
|
-
},
|
|
2836
|
-
});
|
|
2837
|
-
}
|
|
2838
|
-
if ( safe.logLevel !== 0 ) {
|
|
2839
|
-
popup = new Proxy(popup, {
|
|
2840
|
-
get: function(target, prop) {
|
|
2841
|
-
safe.uboLog(logPrefix, 'window.open / get', prop, '===', target[prop]);
|
|
2842
|
-
return Reflect.get(...arguments);
|
|
2843
|
-
},
|
|
2844
|
-
set: function(target, prop, value) {
|
|
2845
|
-
safe.uboLog(logPrefix, 'window.open / set', prop, '=', value);
|
|
2846
|
-
return Reflect.set(...arguments);
|
|
2847
|
-
},
|
|
2848
|
-
});
|
|
2961
|
+
const noopFunc = function(){};
|
|
2962
|
+
proxyApplyFn('open', function open(context) {
|
|
2963
|
+
const { callArgs } = context;
|
|
2964
|
+
const haystack = callArgs.join(' ');
|
|
2965
|
+
if ( rePattern.test(haystack) !== targetMatchResult ) {
|
|
2966
|
+
if ( safe.logLevel > 1 ) {
|
|
2967
|
+
safe.uboLog(logPrefix, `Allowed (${callArgs.join(', ')})`);
|
|
2849
2968
|
}
|
|
2850
|
-
return
|
|
2969
|
+
return context.reflect();
|
|
2970
|
+
}
|
|
2971
|
+
safe.uboLog(logPrefix, `Prevented (${callArgs.join(', ')})`);
|
|
2972
|
+
if ( delay === '' ) { return null; }
|
|
2973
|
+
if ( decoy === 'blank' ) {
|
|
2974
|
+
callArgs[0] = 'about:blank';
|
|
2975
|
+
const r = context.reflect();
|
|
2976
|
+
setTimeout(( ) => { r.close(); }, autoRemoveAfter);
|
|
2977
|
+
return r;
|
|
2978
|
+
}
|
|
2979
|
+
const decoyElem = decoy === 'obj'
|
|
2980
|
+
? createDecoy('object', 'data', ...callArgs)
|
|
2981
|
+
: createDecoy('iframe', 'src', ...callArgs);
|
|
2982
|
+
let popup = decoyElem.contentWindow;
|
|
2983
|
+
if ( typeof popup === 'object' && popup !== null ) {
|
|
2984
|
+
Object.defineProperty(popup, 'closed', { value: false });
|
|
2985
|
+
} else {
|
|
2986
|
+
popup = new Proxy(self, {
|
|
2987
|
+
get: function(target, prop, ...args) {
|
|
2988
|
+
if ( prop === 'closed' ) { return false; }
|
|
2989
|
+
const r = Reflect.get(target, prop, ...args);
|
|
2990
|
+
if ( typeof r === 'function' ) { return noopFunc; }
|
|
2991
|
+
return r;
|
|
2992
|
+
},
|
|
2993
|
+
set: function(...args) {
|
|
2994
|
+
return Reflect.set(...args);
|
|
2995
|
+
},
|
|
2996
|
+
});
|
|
2851
2997
|
}
|
|
2998
|
+
if ( safe.logLevel !== 0 ) {
|
|
2999
|
+
popup = new Proxy(popup, {
|
|
3000
|
+
get: function(target, prop, ...args) {
|
|
3001
|
+
const r = Reflect.get(target, prop, ...args);
|
|
3002
|
+
safe.uboLog(logPrefix, `popup / get ${prop} === ${r}`);
|
|
3003
|
+
if ( typeof r === 'function' ) {
|
|
3004
|
+
return (...args) => { return r.call(target, ...args); };
|
|
3005
|
+
}
|
|
3006
|
+
return r;
|
|
3007
|
+
},
|
|
3008
|
+
set: function(target, prop, value, ...args) {
|
|
3009
|
+
safe.uboLog(logPrefix, `popup / set ${prop} = ${value}`);
|
|
3010
|
+
return Reflect.set(target, prop, value, ...args);
|
|
3011
|
+
},
|
|
3012
|
+
});
|
|
3013
|
+
}
|
|
3014
|
+
return popup;
|
|
2852
3015
|
});
|
|
2853
3016
|
}
|
|
2854
3017
|
|
|
@@ -2974,11 +3137,11 @@ function alertBuster() {
|
|
|
2974
3137
|
apply: function(a) {
|
|
2975
3138
|
console.info(a);
|
|
2976
3139
|
},
|
|
2977
|
-
get(target, prop
|
|
3140
|
+
get(target, prop) {
|
|
2978
3141
|
if ( prop === 'toString' ) {
|
|
2979
3142
|
return target.toString.bind(target);
|
|
2980
3143
|
}
|
|
2981
|
-
return Reflect.get(target, prop
|
|
3144
|
+
return Reflect.get(target, prop);
|
|
2982
3145
|
},
|
|
2983
3146
|
});
|
|
2984
3147
|
}
|
|
@@ -3245,6 +3408,9 @@ function xmlPrune(
|
|
|
3245
3408
|
const serializer = new XMLSerializer();
|
|
3246
3409
|
const textout = serializer.serializeToString(thisArg.responseXML);
|
|
3247
3410
|
Object.defineProperty(thisArg, 'responseText', { value: textout });
|
|
3411
|
+
if ( typeof thisArg.response === 'string' ) {
|
|
3412
|
+
Object.defineProperty(thisArg, 'response', { value: textout });
|
|
3413
|
+
}
|
|
3248
3414
|
return;
|
|
3249
3415
|
}
|
|
3250
3416
|
if (
|
|
@@ -3510,9 +3676,12 @@ function hrefSanitizer(
|
|
|
3510
3676
|
const end = recursive ? source.indexOf('?', 1) : source.length;
|
|
3511
3677
|
try {
|
|
3512
3678
|
const url = new URL(href, document.location);
|
|
3513
|
-
|
|
3679
|
+
let value = url.searchParams.get(source.slice(1, end));
|
|
3514
3680
|
if ( value === null ) { return href }
|
|
3515
3681
|
if ( recursive ) { return extractParam(value, source.slice(end)); }
|
|
3682
|
+
if ( value.includes(' ') ) {
|
|
3683
|
+
value = value.replace(/ /g, '%20');
|
|
3684
|
+
}
|
|
3516
3685
|
return value;
|
|
3517
3686
|
} catch(x) {
|
|
3518
3687
|
}
|
|
@@ -3695,7 +3864,7 @@ function spoofCSS(
|
|
|
3695
3864
|
const targetElements = new WeakSet(document.querySelectorAll(selector));
|
|
3696
3865
|
if ( targetElements.has(args[0]) === false ) { return style; }
|
|
3697
3866
|
const proxiedStyle = new Proxy(style, {
|
|
3698
|
-
get(target, prop
|
|
3867
|
+
get(target, prop) {
|
|
3699
3868
|
if ( typeof target[prop] === 'function' ) {
|
|
3700
3869
|
if ( prop === 'getPropertyValue' ) {
|
|
3701
3870
|
return cloackFunc(function getPropertyValue(prop) {
|
|
@@ -3707,7 +3876,7 @@ function spoofCSS(
|
|
|
3707
3876
|
if ( instanceProperties.includes(prop) ) {
|
|
3708
3877
|
return Reflect.get(target, prop);
|
|
3709
3878
|
}
|
|
3710
|
-
return spoofStyle(prop, Reflect.get(target, prop
|
|
3879
|
+
return spoofStyle(prop, Reflect.get(target, prop));
|
|
3711
3880
|
},
|
|
3712
3881
|
getOwnPropertyDescriptor(target, prop) {
|
|
3713
3882
|
if ( propToValueMap.has(prop) ) {
|
|
@@ -3723,11 +3892,11 @@ function spoofCSS(
|
|
|
3723
3892
|
});
|
|
3724
3893
|
return proxiedStyle;
|
|
3725
3894
|
},
|
|
3726
|
-
get(target, prop
|
|
3895
|
+
get(target, prop) {
|
|
3727
3896
|
if ( prop === 'toString' ) {
|
|
3728
3897
|
return target.toString.bind(target);
|
|
3729
3898
|
}
|
|
3730
|
-
return Reflect.get(target, prop
|
|
3899
|
+
return Reflect.get(target, prop);
|
|
3731
3900
|
},
|
|
3732
3901
|
});
|
|
3733
3902
|
Element.prototype.getBoundingClientRect = new Proxy(Element.prototype.getBoundingClientRect, {
|
|
@@ -3746,11 +3915,11 @@ function spoofCSS(
|
|
|
3746
3915
|
}
|
|
3747
3916
|
return new self.DOMRect(rect.x, rect.y, width, height);
|
|
3748
3917
|
},
|
|
3749
|
-
get(target, prop
|
|
3918
|
+
get(target, prop) {
|
|
3750
3919
|
if ( prop === 'toString' ) {
|
|
3751
3920
|
return target.toString.bind(target);
|
|
3752
3921
|
}
|
|
3753
|
-
return Reflect.get(target, prop
|
|
3922
|
+
return Reflect.get(target, prop);
|
|
3754
3923
|
},
|
|
3755
3924
|
});
|
|
3756
3925
|
}
|
|
@@ -3792,6 +3961,7 @@ builtinScriptlets.push({
|
|
|
3792
3961
|
fn: setCookie,
|
|
3793
3962
|
world: 'ISOLATED',
|
|
3794
3963
|
dependencies: [
|
|
3964
|
+
'get-safe-cookie-values.fn',
|
|
3795
3965
|
'safe-self.fn',
|
|
3796
3966
|
'set-cookie.fn',
|
|
3797
3967
|
],
|
|
@@ -3804,27 +3974,10 @@ function setCookie(
|
|
|
3804
3974
|
if ( name === '' ) { return; }
|
|
3805
3975
|
const safe = safeSelf();
|
|
3806
3976
|
const logPrefix = safe.makeLogPrefix('set-cookie', name, value, path);
|
|
3807
|
-
|
|
3808
|
-
const validValues = [
|
|
3809
|
-
'accept', 'reject',
|
|
3810
|
-
'accepted', 'rejected', 'notaccepted',
|
|
3811
|
-
'allow', 'deny',
|
|
3812
|
-
'allowed', 'disallow',
|
|
3813
|
-
'enable', 'disable',
|
|
3814
|
-
'enabled', 'disabled',
|
|
3815
|
-
'ok',
|
|
3816
|
-
'on', 'off',
|
|
3817
|
-
'true', 't', 'false', 'f',
|
|
3818
|
-
'yes', 'y', 'no', 'n',
|
|
3819
|
-
'necessary', 'required',
|
|
3820
|
-
'approved', 'disapproved',
|
|
3821
|
-
'hide', 'hidden',
|
|
3822
|
-
'essential', 'nonessential',
|
|
3823
|
-
'dismiss', 'dismissed',
|
|
3824
|
-
];
|
|
3825
3977
|
const normalized = value.toLowerCase();
|
|
3826
3978
|
const match = /^("?)(.+)\1$/.exec(normalized);
|
|
3827
3979
|
const unquoted = match && match[2] || normalized;
|
|
3980
|
+
const validValues = getSafeCookieValuesFn();
|
|
3828
3981
|
if ( validValues.includes(unquoted) === false ) {
|
|
3829
3982
|
if ( /^\d+$/.test(unquoted) === false ) { return; }
|
|
3830
3983
|
const n = parseInt(value, 10);
|
|
@@ -4757,8 +4910,8 @@ function trustedPruneOutboundObject(
|
|
|
4757
4910
|
if ( propChain === '' ) { return; }
|
|
4758
4911
|
const safe = safeSelf();
|
|
4759
4912
|
const extraArgs = safe.getExtraArgs(Array.from(arguments), 3);
|
|
4760
|
-
|
|
4761
|
-
const objBefore =
|
|
4913
|
+
proxyApplyFn(propChain, function(context) {
|
|
4914
|
+
const objBefore = context.reflect();
|
|
4762
4915
|
if ( objBefore instanceof Object === false ) { return objBefore; }
|
|
4763
4916
|
const objAfter = objectPruneFn(
|
|
4764
4917
|
objBefore,
|
|
@@ -4791,26 +4944,27 @@ function trustedReplaceArgument(
|
|
|
4791
4944
|
if ( propChain === '' ) { return; }
|
|
4792
4945
|
const safe = safeSelf();
|
|
4793
4946
|
const logPrefix = safe.makeLogPrefix('trusted-replace-argument', propChain, argposRaw, argraw);
|
|
4794
|
-
const
|
|
4947
|
+
const argoffset = parseInt(argposRaw, 10) || 0;
|
|
4795
4948
|
const extraArgs = safe.getExtraArgs(Array.from(arguments), 3);
|
|
4796
4949
|
const normalValue = validateConstantFn(true, argraw, extraArgs);
|
|
4797
4950
|
const reCondition = extraArgs.condition
|
|
4798
4951
|
? safe.patternToRegex(extraArgs.condition)
|
|
4799
4952
|
: /^/;
|
|
4800
|
-
|
|
4953
|
+
proxyApplyFn(propChain, function(context) {
|
|
4954
|
+
const { callArgs } = context;
|
|
4801
4955
|
if ( argposRaw === '' ) {
|
|
4802
|
-
safe.uboLog(logPrefix, `Arguments:\n${
|
|
4803
|
-
return
|
|
4804
|
-
}
|
|
4805
|
-
const
|
|
4806
|
-
if (
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
return
|
|
4956
|
+
safe.uboLog(logPrefix, `Arguments:\n${callArgs.join('\n')}`);
|
|
4957
|
+
return context.reflect();
|
|
4958
|
+
}
|
|
4959
|
+
const argpos = argoffset >= 0 ? argoffset : callArgs.length - argoffset;
|
|
4960
|
+
if ( argpos >= 0 && argpos < callArgs.length ) {
|
|
4961
|
+
const argBefore = callArgs[argpos];
|
|
4962
|
+
if ( safe.RegExp_test.call(reCondition, argBefore) ) {
|
|
4963
|
+
callArgs[argpos] = normalValue;
|
|
4964
|
+
safe.uboLog(logPrefix, `Replaced argument:\nBefore: ${JSON.stringify(argBefore)}\nAfter: ${normalValue}`);
|
|
4965
|
+
}
|
|
4966
|
+
}
|
|
4967
|
+
return context.reflect();
|
|
4814
4968
|
});
|
|
4815
4969
|
}
|
|
4816
4970
|
|
|
@@ -4827,24 +4981,27 @@ builtinScriptlets.push({
|
|
|
4827
4981
|
});
|
|
4828
4982
|
function trustedReplaceOutboundText(
|
|
4829
4983
|
propChain = '',
|
|
4830
|
-
|
|
4831
|
-
|
|
4984
|
+
rawPattern = '',
|
|
4985
|
+
rawReplacement = '',
|
|
4832
4986
|
...args
|
|
4833
4987
|
) {
|
|
4834
4988
|
if ( propChain === '' ) { return; }
|
|
4835
4989
|
const safe = safeSelf();
|
|
4836
|
-
const logPrefix = safe.makeLogPrefix('trusted-replace-outbound-text', propChain,
|
|
4837
|
-
const rePattern = safe.patternToRegex(
|
|
4990
|
+
const logPrefix = safe.makeLogPrefix('trusted-replace-outbound-text', propChain, rawPattern, rawReplacement, ...args);
|
|
4991
|
+
const rePattern = safe.patternToRegex(rawPattern);
|
|
4992
|
+
const replacement = rawReplacement.startsWith('json:')
|
|
4993
|
+
? safe.JSON_parse(rawReplacement.slice(5))
|
|
4994
|
+
: rawReplacement;
|
|
4838
4995
|
const extraArgs = safe.getExtraArgs(args);
|
|
4839
4996
|
const reCondition = safe.patternToRegex(extraArgs.condition || '');
|
|
4840
|
-
|
|
4841
|
-
const encodedTextBefore =
|
|
4997
|
+
proxyApplyFn(propChain, function(context) {
|
|
4998
|
+
const encodedTextBefore = context.reflect();
|
|
4842
4999
|
let textBefore = encodedTextBefore;
|
|
4843
5000
|
if ( extraArgs.encoding === 'base64' ) {
|
|
4844
5001
|
try { textBefore = self.atob(encodedTextBefore); }
|
|
4845
5002
|
catch(ex) { return encodedTextBefore; }
|
|
4846
5003
|
}
|
|
4847
|
-
if (
|
|
5004
|
+
if ( rawPattern === '' ) {
|
|
4848
5005
|
safe.uboLog(logPrefix, 'Decoded outbound text:\n', textBefore);
|
|
4849
5006
|
return encodedTextBefore;
|
|
4850
5007
|
}
|
|
@@ -4915,34 +5072,31 @@ function trustedSuppressNativeMethod(
|
|
|
4915
5072
|
return { type: 'exact', value: undefined };
|
|
4916
5073
|
}
|
|
4917
5074
|
});
|
|
4918
|
-
|
|
5075
|
+
proxyApplyFn(methodPath, function(context) {
|
|
5076
|
+
const { callArgs } = context;
|
|
4919
5077
|
if ( signature === '' ) {
|
|
4920
|
-
safe.uboLog(logPrefix, `Arguments:\n${
|
|
4921
|
-
return
|
|
4922
|
-
}
|
|
4923
|
-
const arglist = args[args.length-1];
|
|
4924
|
-
if ( Array.isArray(arglist) === false ) {
|
|
4925
|
-
return reflector(...args);
|
|
5078
|
+
safe.uboLog(logPrefix, `Arguments:\n${callArgs.join('\n')}`);
|
|
5079
|
+
return context.reflect();
|
|
4926
5080
|
}
|
|
4927
|
-
if (
|
|
4928
|
-
return
|
|
5081
|
+
if ( callArgs.length < signatureArgs.length ) {
|
|
5082
|
+
return context.reflect();
|
|
4929
5083
|
}
|
|
4930
5084
|
for ( let i = 0; i < signatureArgs.length; i++ ) {
|
|
4931
5085
|
const signatureArg = signatureArgs[i];
|
|
4932
5086
|
if ( signatureArg === undefined ) { continue; }
|
|
4933
|
-
const targetArg =
|
|
5087
|
+
const targetArg = callArgs[i];
|
|
4934
5088
|
if ( signatureArg.type === 'exact' ) {
|
|
4935
5089
|
if ( targetArg !== signatureArg.value ) {
|
|
4936
|
-
return
|
|
5090
|
+
return context.reflect();
|
|
4937
5091
|
}
|
|
4938
5092
|
}
|
|
4939
5093
|
if ( signatureArg.type === 'pattern' ) {
|
|
4940
5094
|
if ( safe.RegExp_test.call(signatureArg.re, targetArg) === false ) {
|
|
4941
|
-
return
|
|
5095
|
+
return context.reflect();
|
|
4942
5096
|
}
|
|
4943
5097
|
}
|
|
4944
5098
|
}
|
|
4945
|
-
safe.uboLog(logPrefix, `Suppressed:\n${
|
|
5099
|
+
safe.uboLog(logPrefix, `Suppressed:\n${callArgs.join('\n')}`);
|
|
4946
5100
|
if ( how === 'abort' ) {
|
|
4947
5101
|
throw new ReferenceError();
|
|
4948
5102
|
}
|