From 9c51da035b96e4ecde77f514c847c617552a96a6 Mon Sep 17 00:00:00 2001 From: Ghostery Adblocker Bot Date: Mon, 7 Sep 2026 20:17:26 +0000 Subject: [PATCH] Update scriptlets --- package.json | 2 +- ubo.js | 5279 ++++++++++++++++++++++++++------------------------ 2 files changed, 2783 insertions(+), 2498 deletions(-) diff --git a/package.json b/package.json index 6148aca..2bd6c25 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "type": "module", "scripts": { - "build": "deno build.ts --tagName 1.73.1b0 > ubo.js", + "build": "deno build.ts --tagName 1.74.1b4 > ubo.js", "test": "node --test" }, "author": { diff --git a/ubo.js b/ubo.js index f5ea50e..75dbece 100644 --- a/ubo.js +++ b/ubo.js @@ -119,8 +119,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -133,7 +132,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -144,10 +143,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -200,7 +197,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -486,8 +483,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -500,7 +496,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -511,10 +507,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -567,7 +561,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -791,8 +785,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -805,7 +798,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -816,10 +809,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -872,7 +863,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -989,8 +980,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -1003,7 +993,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -1014,10 +1004,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -1070,7 +1058,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -1287,8 +1275,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -1301,7 +1288,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -1312,10 +1299,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -1368,7 +1353,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -1674,8 +1659,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -1688,7 +1672,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -1699,10 +1683,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -1755,7 +1737,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -2012,8 +1994,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -2026,7 +2007,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -2037,10 +2018,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -2093,7 +2072,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -2875,8 +2854,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -2889,7 +2867,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -2900,10 +2878,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -2956,7 +2932,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -3738,8 +3714,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -3752,7 +3727,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -3763,10 +3738,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -3819,7 +3792,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -4600,8 +4573,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -4614,7 +4586,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -4625,10 +4597,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -4681,7 +4651,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -5462,8 +5432,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -5476,7 +5445,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -5487,10 +5456,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -5543,7 +5510,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -6352,8 +6319,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -6366,7 +6332,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -6377,10 +6343,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -6433,7 +6397,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -7242,8 +7206,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -7256,7 +7219,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -7267,10 +7230,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -7323,7 +7284,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -8115,8 +8076,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -8129,7 +8089,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -8140,10 +8100,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -8196,7 +8154,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -9060,8 +9018,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -9074,7 +9031,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -9085,10 +9042,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -9141,7 +9096,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -9905,8 +9860,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -9919,7 +9873,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -9930,10 +9884,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -9986,7 +9938,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -10750,8 +10702,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -10764,7 +10715,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -10775,10 +10726,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -10831,7 +10780,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -11598,8 +11547,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -11612,7 +11560,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -11623,10 +11571,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -11679,7 +11625,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -12389,8 +12335,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -12403,7 +12348,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -12414,10 +12359,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -12470,7 +12413,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -13277,8 +13220,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -13291,7 +13233,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -13302,10 +13244,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -13358,7 +13298,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -14170,8 +14110,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -14184,7 +14123,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -14195,10 +14134,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -14251,7 +14188,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -15014,8 +14951,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -15028,7 +14964,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -15039,10 +14975,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -15095,7 +15029,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -15858,8 +15792,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -15872,7 +15805,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -15883,10 +15816,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -15939,7 +15870,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -16685,8 +16616,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -16699,7 +16629,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -16710,10 +16640,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -16766,7 +16694,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -18177,8 +18105,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -18191,7 +18118,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -18202,10 +18129,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -18258,7 +18183,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -19138,8 +19063,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -19152,7 +19076,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -19163,10 +19087,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -19219,7 +19141,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -20099,8 +20021,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -20113,7 +20034,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -20124,10 +20045,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -20180,7 +20099,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -21057,8 +20976,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -21071,7 +20989,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -21082,10 +21000,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -21138,7 +21054,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -21369,8 +21285,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -21383,7 +21298,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -21394,10 +21309,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -21450,7 +21363,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -22227,8 +22140,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -22241,7 +22153,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -22252,10 +22164,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -22308,7 +22218,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -23753,8 +23663,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -23767,7 +23676,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -23778,10 +23687,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -23834,7 +23741,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -24741,8 +24648,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -24755,7 +24661,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -24766,10 +24672,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -24822,7 +24726,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -25066,8 +24970,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -25080,7 +24983,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -25091,10 +24994,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -25147,7 +25048,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -25424,8 +25325,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -25438,7 +25338,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -25449,10 +25349,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -25505,7 +25403,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -25905,8 +25803,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -25919,7 +25816,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -25930,10 +25827,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -25986,7 +25881,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -26377,8 +26272,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -26391,7 +26285,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -26402,10 +26296,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -26458,7 +26350,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -26899,8 +26791,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -26913,7 +26804,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -26924,10 +26815,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -26980,7 +26869,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -27368,8 +27257,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -27382,7 +27270,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -27393,10 +27281,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -27449,7 +27335,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -27818,8 +27704,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -27832,7 +27717,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -27843,10 +27728,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -27899,7 +27782,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -28118,8 +28001,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -28132,7 +28014,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -28143,10 +28025,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -28199,7 +28079,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -28423,8 +28303,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -28437,7 +28316,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -28448,10 +28327,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -28504,7 +28381,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -28756,8 +28633,8 @@ function preventAddEventListener( return parts.join(''); }; const shouldPrevent = (thisArg, type, handler) => { - const matchesType = safe.RegExp_test.call(reType, type); - const matchesHandler = safe.RegExp_test.call(rePattern, handler); + const matchesType = safe.RegExp_test(reType, type); + const matchesHandler = safe.RegExp_test(rePattern, handler); const matchesEither = matchesType || matchesHandler; const matchesBoth = matchesType && matchesHandler; if ( safe.logLevel > 1 && matchesEither ) { @@ -28829,8 +28706,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -28843,7 +28719,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -28854,10 +28730,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -28910,7 +28784,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -29177,8 +29051,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -29191,7 +29064,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -29202,10 +29075,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -29258,7 +29129,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -29451,40 +29322,51 @@ function preventClipboardWrite(matches = '', ...varargs) { const extraArgs = safe.parseVarargs(varargs); const excludePattern = extraArgs.excludeMatches && safe.initPattern(extraArgs.excludeMatches); + const htmlTemplate = [ + '
', + '${warning}\n', + '', + '
', + ].join(''); const domAlert = clipboardText => { const doc = document; - const div = doc.createElement('div'); - const span = doc.createElement('span'); - span.style = 'flex-grow:1;padding:0.5em 0 0.5em 0.5em;'; - const { domAlert } = extraArgs; - const placeholder = /\$\{text\}/.exec(domAlert); - if ( placeholder ) { + const domAlert = extraArgs.domAlert.replace(/\\n/g, '\n'); + let html; + if ( domAlert.includes('${text}') ) { const code = doc.createElement('code'); - code.style = 'background-color:#ddc;font-family:monospace;padding:0.25em;user-select:none;word-break:break-all'; + const styles = [ + 'background-color: #ddc', + 'display: inline-block', + 'font-family: monospace', + 'font-size: 100%', + 'max-height: 8em', + 'overflow: auto', + 'padding: 0.25em', + 'width: 100%;', + 'word-break: break-all' + ]; + if ( Boolean(extraArgs.selectable ?? true) === false ) { + styles.push('user-select: none'); + } + code.style = styles.join(';'); code.textContent = clipboardText; - span.append( - domAlert.slice(0, placeholder.index), - code, - domAlert.slice(placeholder.index + placeholder[0].length) + html = htmlTemplate.replace('${warning}', + domAlert.replace('${text}', code.outerHTML) ); } else { - span.append(domAlert); + html = htmlTemplate.replace('${warning}', domAlert); } - const button = doc.createElement('button'); - button.style = 'padding:1em'; - button.textContent = '×'; + if ( currentAlert ) { currentAlert.remove(); } + const domParser = new DOMParser(); + const fragment = domParser.parseFromString(html, 'text/html'); + currentAlert = fragment.querySelector('div'); + const button = currentAlert.querySelector('button'); button.addEventListener('click', ( ) => { if ( currentAlert === null ) { return; } currentAlert.remove(); currentAlert = null; }); - div.append(span, button); - div.style = 'background-color:beige;color:black;border:1px solid black;display:flex;font-size:medium;position:fixed;text-align:center;top:0;width:100%;z-index:2147483647'; - doc.documentElement.append(div); - if ( currentAlert ) { - currentAlert.remove(); - } - currentAlert = div; + doc.documentElement.append(currentAlert); }; let currentAlert = null; const prevent = text => { @@ -29510,7 +29392,7 @@ function preventClipboardWrite(matches = '', ...varargs) { const { callArgs } = context; if ( callArgs[0] === 'copy' || callArgs[0] === 'cut' ) { const text = document.getSelection()?.toString(); - if ( text && prevent(text) ) { return false; } + if ( prevent(text) ) { return true; } } return context.reflect(); }, { skipToString: true }); @@ -29538,8 +29420,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -29552,7 +29433,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -29563,10 +29444,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -29619,7 +29498,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -29953,8 +29832,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -29967,7 +29845,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -29978,10 +29856,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -30034,7 +29910,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -30460,8 +30336,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -30474,7 +30349,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -30485,10 +30360,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -30541,7 +30414,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -30765,8 +30638,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -30779,7 +30651,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -30790,10 +30662,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -30846,7 +30716,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -31004,8 +30874,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -31018,7 +30887,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -31029,10 +30898,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -31085,7 +30952,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -31249,8 +31116,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -31263,7 +31129,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -31274,10 +31140,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -31330,7 +31194,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -31456,8 +31320,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -31470,7 +31333,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -31481,10 +31344,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -31537,7 +31398,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -31797,8 +31658,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -31811,7 +31671,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -31822,10 +31682,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -31878,7 +31736,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -32138,8 +31996,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -32152,7 +32009,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -32163,10 +32020,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -32219,7 +32074,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -32431,147 +32286,61 @@ preventRequestAnimationFrame(...args); }; -scriptlets['prevent-xhr.js'] = { -aliases: ["no-xhr-if.js"], +scriptlets['set-constant.js'] = { +aliases: ["set.js"], requiresTrust: false, func: function (scriptletGlobals = {}, ...args) { -function proxyApplyFn( - target = '', - handler = '', - options = {} -) { - let context = globalThis; - let prop = target; - 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); - } - const fn = context[prop]; - if ( typeof fn !== 'function' ) { return; } - if ( proxyApplyFn.CtorContext === undefined ) { - proxyApplyFn.ctorContexts = []; - proxyApplyFn.CtorContext = class { - constructor(...args) { - this.init(...args); - } - init(callFn, callArgs) { - this.callFn = callFn; - this.callArgs = callArgs; - return this; - } - reflect() { - const r = Reflect.construct(this.callFn, this.callArgs); - this.callFn = this.callArgs = this.private = undefined; - proxyApplyFn.ctorContexts.push(this); - return r; - } - static factory(...args) { - return proxyApplyFn.ctorContexts.length !== 0 - ? proxyApplyFn.ctorContexts.pop().init(...args) - : new proxyApplyFn.CtorContext(...args); - } - }; - proxyApplyFn.applyContexts = []; - proxyApplyFn.ApplyContext = class { - constructor(...args) { - this.init(...args); - } - init(callFn, thisArg, callArgs) { - this.callFn = callFn; - this.thisArg = thisArg; - this.callArgs = callArgs; - return this; - } - reflect() { - const r = Reflect.apply(this.callFn, this.thisArg, this.callArgs); - this.callFn = this.thisArg = this.callArgs = this.private = undefined; - proxyApplyFn.applyContexts.push(this); - return r; - } - static factory(...args) { - return proxyApplyFn.applyContexts.length !== 0 - ? proxyApplyFn.applyContexts.pop().init(...args) - : new proxyApplyFn.ApplyContext(...args); - } - }; - proxyApplyFn.isCtor = new Map(); - proxyApplyFn.proxies = new WeakMap(); - if ( (options.skipToString || proxyApplyFn.skipToString) !== true ) { - proxyApplyFn.nativeToString = Function.prototype.toString; - const proxiedToString = new Proxy(Function.prototype.toString, { - apply(target, thisArg) { - let proxied = thisArg; - for(;;) { - const fn = proxyApplyFn.proxies.get(proxied); - if ( fn === undefined ) { break; } - proxied = fn; - } - return proxyApplyFn.nativeToString.call(proxied); - } - }); - proxyApplyFn.proxies.set(proxiedToString, proxyApplyFn.nativeToString); - Function.prototype.toString = proxiedToString; - } - } - if ( proxyApplyFn.isCtor.has(target) === false ) { - proxyApplyFn.isCtor.set(target, fn.prototype?.constructor === fn); - } - const proxyDetails = { - apply(target, thisArg, args) { - return handler(proxyApplyFn.ApplyContext.factory(target, thisArg, args)); - } - }; - if ( proxyApplyFn.isCtor.get(target) ) { - proxyDetails.construct = function(target, args) { - return handler(proxyApplyFn.CtorContext.factory(target, args)); - }; - } - const proxiedTarget = new Proxy(fn, proxyDetails); - proxyApplyFn.proxies.set(proxiedTarget, fn); - context[prop] = proxiedTarget; -} -function parsePropertiesToMatchFn(propsToMatch, implicit = '') { +function validateConstantFn(trusted, raw, extraArgs = {}) { const safe = safeSelf(); - const needles = new Map(); - if ( propsToMatch === undefined || propsToMatch === '' ) { return needles; } - const options = { canNegate: true }; - for ( const needle of safe.String_split.call(propsToMatch, /\s+/) ) { - let [ prop, pattern ] = safe.String_split.call(needle, ':'); - if ( prop === '' ) { continue; } - if ( pattern !== undefined && /[^$\w -]/.test(prop) ) { - prop = `${prop}:${pattern}`; - pattern = undefined; - } - if ( pattern !== undefined ) { - needles.set(prop, safe.initPattern(pattern, options)); - } else if ( implicit !== '' ) { - needles.set(implicit, safe.initPattern(prop, options)); + let value; + if ( raw === 'undefined' ) { + value = undefined; + } else if ( raw === 'false' ) { + value = false; + } else if ( raw === 'true' ) { + value = true; + } else if ( raw === 'null' ) { + value = null; + } else if ( raw === "''" || raw === '' ) { + value = ''; + } else if ( raw === '[]' || raw === 'emptyArr' ) { + value = []; + } else if ( raw === '{}' || raw === 'emptyObj' ) { + value = {}; + } else if ( raw === 'noopFunc' ) { + value = function(){}; + } else if ( raw === 'trueFunc' ) { + value = function(){ return true; }; + } else if ( raw === 'falseFunc' ) { + value = function(){ return false; }; + } else if ( raw === 'throwFunc' ) { + value = function(){ throw ''; }; + } else if ( /^-?\d+$/.test(raw) ) { + value = parseInt(raw); + if ( isNaN(raw) ) { return; } + if ( Math.abs(raw) > 0x7FFF ) { return; } + } else if ( trusted ) { + if ( raw.startsWith('json:') ) { + try { value = safe.JSON_parse(raw.slice(5)); } catch { return; } + } else if ( raw.startsWith('{') && raw.endsWith('}') ) { + try { value = safe.JSON_parse(raw).value; } catch { return; } } + } else { + return; } - return needles; -} -function matchObjectPropertiesFn(propNeedles, ...objs) { - const safe = safeSelf(); - const matched = []; - for ( const obj of objs ) { - if ( obj instanceof Object === false ) { continue; } - for ( const [ prop, details ] of propNeedles ) { - let value = obj[prop]; - if ( value === undefined ) { continue; } - if ( typeof value !== 'string' ) { - try { value = safe.JSON_stringify(value); } - catch { } - if ( typeof value !== 'string' ) { continue; } - } - if ( safe.testPattern(details, value) === false ) { return; } - matched.push(`${prop}: ${value}`); + if ( extraArgs.as !== undefined ) { + if ( extraArgs.as === 'function' ) { + return ( ) => value; + } else if ( extraArgs.as === 'callback' ) { + return ( ) => (( ) => value); + } else if ( extraArgs.as === 'resolved' ) { + return Promise.resolve(value); + } else if ( extraArgs.as === 'rejected' ) { + return Promise.reject(value); } } - return matched; + return value; } function safeSelf() { if ( safeSelf.safe ) { @@ -32581,8 +32350,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -32595,7 +32363,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -32606,10 +32374,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -32662,7 +32428,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -32750,387 +32516,249 @@ function safeSelf() { } return safe; } -function generateContentFn(trusted, directive) { - const safe = safeSelf(); - const randomize = len => { - const chunks = []; - let textSize = 0; - do { - const s = safe.Math_random().toString(36).slice(2); - chunks.push(s); - textSize += s.length; +function runAt(fn, when) { + const intFromReadyState = state => { + const targets = { + 'loading': 1, 'asap': 1, + 'interactive': 2, 'end': 2, '2': 2, + 'complete': 3, 'idle': 3, '3': 3, + }; + const tokens = Array.isArray(state) ? state : [ state ]; + for ( const token of tokens ) { + const prop = `${token}`; + if ( Object.hasOwn(targets, prop) === false ) { continue; } + return targets[prop]; } - while ( textSize < len ); - return chunks.join(' ').slice(0, len); + return 0; }; - if ( directive === 'true' ) { - return randomize(10); - } - if ( directive === 'emptyObj' ) { - return '{}'; - } - if ( directive === 'emptyArr' ) { - return '[]'; - } - if ( directive === 'emptyStr' ) { - return ''; - } - if ( directive.startsWith('length:') ) { - const match = /^length:(\d+)(?:-(\d+))?$/.exec(directive); - if ( match === null ) { return ''; } - const min = parseInt(match[1], 10); - const extent = safe.Math_max(parseInt(match[2], 10) || 0, min) - min; - const len = safe.Math_min(min + extent * safe.Math_random(), 500000); - return randomize(len | 0); - } - if ( directive.startsWith('war:') ) { - if ( scriptletGlobals.warOrigin === undefined ) { return ''; } - return new Promise(resolve => { - const warOrigin = scriptletGlobals.warOrigin; - const warName = directive.slice(4); - const fullpath = [ warOrigin, '/', warName ]; - const warSecret = scriptletGlobals.warSecret; - if ( warSecret !== undefined ) { - fullpath.push('?secret=', warSecret); - } - const warXHR = new safe.XMLHttpRequest(); - warXHR.responseType = 'text'; - warXHR.onloadend = ev => { - resolve(ev.target.responseText || ''); - }; - warXHR.open('GET', fullpath.join('')); - warXHR.send(); - }).catch(( ) => ''); - } - if ( directive.startsWith('join:') ) { - const parts = directive.slice(7) - .split(directive.slice(5, 7)) - .map(a => generateContentFn(trusted, a)); - return parts.some(a => a instanceof Promise) - ? Promise.all(parts).then(parts => parts.join('')) - : parts.join(''); - } - if ( trusted ) { - return directive; + const runAt = intFromReadyState(when); + if ( intFromReadyState(document.readyState) >= runAt ) { + fn(); return; } - return ''; + const onStateChange = ( ) => { + if ( intFromReadyState(document.readyState) < runAt ) { return; } + fn(); + safe.removeEventListener.apply(document, args); + }; + const safe = safeSelf(); + const args = [ 'readystatechange', onStateChange, { capture: true } ]; + safe.addEventListener.apply(document, args); } -function preventXhrFn( +function setConstantFn( trusted = false, - propsToMatch = '', - directive = '' + chain = '', + rawValue = '', + ...varargs ) { - if ( typeof propsToMatch !== 'string' ) { return; } + if ( chain === '' ) { return; } const safe = safeSelf(); - const scriptletName = trusted ? 'trusted-prevent-xhr' : 'prevent-xhr'; - const logPrefix = safe.makeLogPrefix(scriptletName, propsToMatch, directive); - const xhrInstances = new WeakMap(); - const propNeedles = parsePropertiesToMatchFn(propsToMatch, 'url'); - const warOrigin = scriptletGlobals.warOrigin; - const safeDispatchEvent = (xhr, type) => { - try { - xhr.dispatchEvent(new Event(type)); - } catch { - } - }; - proxyApplyFn('XMLHttpRequest.prototype.open', function(context) { - const { thisArg, callArgs } = context; - xhrInstances.delete(thisArg); - const [ method, url, ...args ] = callArgs; - if ( warOrigin !== undefined && url.startsWith(warOrigin) ) { - return context.reflect(); - } - const haystack = { method, url }; - if ( propsToMatch === '' && directive === '' ) { - safe.uboLog(logPrefix, `Called: ${safe.JSON_stringify(haystack, null, 2)}`); - return context.reflect(); - } - if ( matchObjectPropertiesFn(propNeedles, haystack) ) { - const xhrDetails = Object.assign(haystack, { - xhr: thisArg, - defer: args.length === 0 || !!args[0], - directive, - headers: { - 'date': '', - 'content-type': '', - 'content-length': '', + const logPrefix = safe.makeLogPrefix('set-constant', chain, rawValue); + const extraArgs = safe.parseVarargs(varargs); + function setConstant(chain, rawValue) { + const trappedProp = (( ) => { + const pos = chain.lastIndexOf('.'); + if ( pos === -1 ) { return chain; } + return chain.slice(pos+1); + })(); + const cloakFunc = fn => { + safe.Object_defineProperty(fn, 'name', { value: trappedProp }); + return new Proxy(fn, { + defineProperty(target, prop) { + if ( prop !== 'toString' ) { + return Reflect.defineProperty(...arguments); + } + return true; }, - url: haystack.url, - props: { - response: { value: '' }, - responseText: { value: '' }, - responseXML: { value: null }, + deleteProperty(target, prop) { + if ( prop !== 'toString' ) { + return Reflect.deleteProperty(...arguments); + } + return true; + }, + get(target, prop) { + if ( prop === 'toString' ) { + return function() { + return `function ${trappedProp}() { [native code] }`; + }.bind(null); + } + return Reflect.get(...arguments); }, }); - xhrInstances.set(thisArg, xhrDetails); - } - return context.reflect(); - }); - proxyApplyFn('XMLHttpRequest.prototype.send', function(context) { - const { thisArg } = context; - const xhrDetails = xhrInstances.get(thisArg); - if ( xhrDetails === undefined ) { - return context.reflect(); - } - xhrDetails.headers['date'] = (new Date()).toUTCString(); - let xhrText = ''; - switch ( thisArg.responseType ) { - case 'arraybuffer': - xhrDetails.props.response.value = new ArrayBuffer(0); - xhrDetails.headers['content-type'] = 'application/octet-stream'; - break; - case 'blob': - xhrDetails.props.response.value = new Blob([]); - xhrDetails.headers['content-type'] = 'application/octet-stream'; - break; - case 'document': { - const parser = new DOMParser(); - const doc = parser.parseFromString('', 'text/html'); - xhrDetails.props.response.value = doc; - xhrDetails.props.responseXML.value = doc; - xhrDetails.headers['content-type'] = 'text/html'; - break; + }; + if ( trappedProp === '' ) { return; } + const thisScript = document.currentScript; + let normalValue = validateConstantFn(trusted, rawValue, extraArgs); + if ( rawValue === 'noopFunc' || rawValue === 'trueFunc' || rawValue === 'falseFunc' ) { + normalValue = cloakFunc(normalValue); } - case 'json': - xhrDetails.props.response.value = {}; - xhrDetails.props.responseText.value = '{}'; - xhrDetails.headers['content-type'] = 'application/json'; - break; - default: { - if ( directive === '' ) { break; } - xhrText = generateContentFn(trusted, xhrDetails.directive); - if ( xhrText instanceof Promise ) { - xhrText = xhrText.then(text => { - xhrDetails.props.response.value = text; - xhrDetails.props.responseText.value = text; + let aborted = false; + const mustAbort = function(v) { + if ( trusted ) { return false; } + if ( aborted ) { return true; } + aborted = + (v !== undefined && v !== null) && + (normalValue !== undefined && normalValue !== null) && + (typeof v !== typeof normalValue); + if ( aborted ) { + safe.uboLog(logPrefix, `Aborted because value set to ${v}`); + } + return aborted; + }; + // https://github.com/uBlockOrigin/uBlock-issues/issues/156 + // Support multiple trappers for the same property. + const trapProp = function(owner, prop, configurable, handler) { + if ( handler.init(configurable ? owner[prop] : normalValue) === false ) { return; } + const odesc = safe.Object_getOwnPropertyDescriptor(owner, prop); + let prevGetter, prevSetter; + if ( odesc instanceof safe.Object ) { + owner[prop] = normalValue; + if ( odesc.get instanceof Function ) { + prevGetter = odesc.get; + } + if ( odesc.set instanceof Function ) { + prevSetter = odesc.set; + } + } + try { + safe.Object_defineProperty(owner, prop, { + configurable, + get() { + if ( prevGetter !== undefined ) { + prevGetter(); + } + return handler.getter(); + }, + set(a) { + if ( prevSetter !== undefined ) { + prevSetter(a); + } + handler.setter(a); + } }); - } else { - xhrDetails.props.response.value = xhrText; - xhrDetails.props.responseText.value = xhrText; + safe.uboLog(logPrefix, 'Trap installed'); + } catch(ex) { + safe.uboErr(logPrefix, ex); } - xhrDetails.headers['content-type'] = 'text/plain'; - break; - } - } - if ( xhrDetails.defer === false ) { - xhrDetails.headers['content-length'] = `${xhrDetails.props.response.value}`.length; - Object.defineProperties(xhrDetails.xhr, { - readyState: { value: 4 }, - responseURL: { value: xhrDetails.url }, - status: { value: 200 }, - statusText: { value: 'OK' }, - }); - Object.defineProperties(xhrDetails.xhr, xhrDetails.props); - return; - } - Promise.resolve(xhrText).then(( ) => xhrDetails).then(details => { - Object.defineProperties(details.xhr, { - readyState: { value: 1, configurable: true }, - responseURL: { value: xhrDetails.url }, - }); - safeDispatchEvent(details.xhr, 'readystatechange'); - return details; - }).then(details => { - xhrDetails.headers['content-length'] = `${details.props.response.value}`.length; - Object.defineProperties(details.xhr, { - readyState: { value: 2, configurable: true }, - status: { value: 200 }, - statusText: { value: 'OK' }, + }; + const trapChain = function(owner, chain) { + const pos = chain.indexOf('.'); + if ( pos === -1 ) { + trapProp(owner, chain, false, { + v: undefined, + init: function(v) { + if ( mustAbort(v) ) { return false; } + this.v = v; + return true; + }, + getter: function() { + if ( document.currentScript === thisScript ) { + return this.v; + } + safe.uboLog(logPrefix, 'Property read'); + return normalValue; + }, + setter: function(a) { + if ( mustAbort(a) === false ) { return; } + normalValue = a; + } + }); + return; + } + const prop = chain.slice(0, pos); + const v = owner[prop]; + chain = chain.slice(pos + 1); + if ( v instanceof safe.Object || typeof v === 'object' && v !== null ) { + trapChain(v, chain); + return; + } + trapProp(owner, prop, true, { + v: undefined, + init: function(v) { + this.v = v; + return true; + }, + getter: function() { + return this.v; + }, + setter: function(a) { + this.v = a; + if ( a instanceof safe.Object ) { + trapChain(a, chain); + } + } }); - safeDispatchEvent(details.xhr, 'readystatechange'); - return details; - }).then(details => { - Object.defineProperties(details.xhr, { - readyState: { value: 3, configurable: true }, - }); - Object.defineProperties(details.xhr, details.props); - safeDispatchEvent(details.xhr, 'readystatechange'); - return details; - }).then(details => { - Object.defineProperties(details.xhr, { - readyState: { value: 4 }, - }); - safeDispatchEvent(details.xhr, 'readystatechange'); - safeDispatchEvent(details.xhr, 'load'); - safeDispatchEvent(details.xhr, 'loadend'); - safe.uboLog(logPrefix, `Prevented with response:\n${details.xhr.response}`); - }); - }); - proxyApplyFn('XMLHttpRequest.prototype.getResponseHeader', function(context) { - const { thisArg } = context; - const xhrDetails = xhrInstances.get(thisArg); - if ( xhrDetails === undefined || thisArg.readyState < thisArg.HEADERS_RECEIVED ) { - return context.reflect(); - } - const headerName = `${context.callArgs[0]}`; - const value = xhrDetails.headers[headerName.toLowerCase()]; - if ( value !== undefined && value !== '' ) { return value; } - return null; - }); - proxyApplyFn('XMLHttpRequest.prototype.getAllResponseHeaders', function(context) { - const { thisArg } = context; - const xhrDetails = xhrInstances.get(thisArg); - if ( xhrDetails === undefined || thisArg.readyState < thisArg.HEADERS_RECEIVED ) { - return context.reflect(); - } - const out = []; - for ( const [ name, value ] of Object.entries(xhrDetails.headers) ) { - if ( !value ) { continue; } - out.push(`${name}: ${value}`); - } - if ( out.length !== 0 ) { out.push(''); } - return out.join('\r\n'); - }); + }; + trapChain(window, chain); + } + runAt(( ) => { + setConstant(chain, rawValue); + }, extraArgs.runAt); } -function preventXhr(...args) { - preventXhrFn(false, ...args); +function setConstant( + ...args +) { + setConstantFn(false, ...args); }; -preventXhr(...args); +setConstant(...args); }, }; -scriptlets['trusted-prevent-xhr.js'] = { -aliases: [], +scriptlets['trusted-set-constant.js'] = { +aliases: ["trusted-set.js"], -requiresTrust: false, +requiresTrust: true, func: function (scriptletGlobals = {}, ...args) { -function proxyApplyFn( - target = '', - handler = '', - options = {} -) { - let context = globalThis; - let prop = target; - 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); - } - const fn = context[prop]; - if ( typeof fn !== 'function' ) { return; } - if ( proxyApplyFn.CtorContext === undefined ) { - proxyApplyFn.ctorContexts = []; - proxyApplyFn.CtorContext = class { - constructor(...args) { - this.init(...args); - } - init(callFn, callArgs) { - this.callFn = callFn; - this.callArgs = callArgs; - return this; - } - reflect() { - const r = Reflect.construct(this.callFn, this.callArgs); - this.callFn = this.callArgs = this.private = undefined; - proxyApplyFn.ctorContexts.push(this); - return r; - } - static factory(...args) { - return proxyApplyFn.ctorContexts.length !== 0 - ? proxyApplyFn.ctorContexts.pop().init(...args) - : new proxyApplyFn.CtorContext(...args); - } - }; - proxyApplyFn.applyContexts = []; - proxyApplyFn.ApplyContext = class { - constructor(...args) { - this.init(...args); - } - init(callFn, thisArg, callArgs) { - this.callFn = callFn; - this.thisArg = thisArg; - this.callArgs = callArgs; - return this; - } - reflect() { - const r = Reflect.apply(this.callFn, this.thisArg, this.callArgs); - this.callFn = this.thisArg = this.callArgs = this.private = undefined; - proxyApplyFn.applyContexts.push(this); - return r; - } - static factory(...args) { - return proxyApplyFn.applyContexts.length !== 0 - ? proxyApplyFn.applyContexts.pop().init(...args) - : new proxyApplyFn.ApplyContext(...args); - } - }; - proxyApplyFn.isCtor = new Map(); - proxyApplyFn.proxies = new WeakMap(); - if ( (options.skipToString || proxyApplyFn.skipToString) !== true ) { - proxyApplyFn.nativeToString = Function.prototype.toString; - const proxiedToString = new Proxy(Function.prototype.toString, { - apply(target, thisArg) { - let proxied = thisArg; - for(;;) { - const fn = proxyApplyFn.proxies.get(proxied); - if ( fn === undefined ) { break; } - proxied = fn; - } - return proxyApplyFn.nativeToString.call(proxied); - } - }); - proxyApplyFn.proxies.set(proxiedToString, proxyApplyFn.nativeToString); - Function.prototype.toString = proxiedToString; - } - } - if ( proxyApplyFn.isCtor.has(target) === false ) { - proxyApplyFn.isCtor.set(target, fn.prototype?.constructor === fn); - } - const proxyDetails = { - apply(target, thisArg, args) { - return handler(proxyApplyFn.ApplyContext.factory(target, thisArg, args)); - } - }; - if ( proxyApplyFn.isCtor.get(target) ) { - proxyDetails.construct = function(target, args) { - return handler(proxyApplyFn.CtorContext.factory(target, args)); - }; - } - const proxiedTarget = new Proxy(fn, proxyDetails); - proxyApplyFn.proxies.set(proxiedTarget, fn); - context[prop] = proxiedTarget; -} -function parsePropertiesToMatchFn(propsToMatch, implicit = '') { +function validateConstantFn(trusted, raw, extraArgs = {}) { const safe = safeSelf(); - const needles = new Map(); - if ( propsToMatch === undefined || propsToMatch === '' ) { return needles; } - const options = { canNegate: true }; - for ( const needle of safe.String_split.call(propsToMatch, /\s+/) ) { - let [ prop, pattern ] = safe.String_split.call(needle, ':'); - if ( prop === '' ) { continue; } - if ( pattern !== undefined && /[^$\w -]/.test(prop) ) { - prop = `${prop}:${pattern}`; - pattern = undefined; - } - if ( pattern !== undefined ) { - needles.set(prop, safe.initPattern(pattern, options)); - } else if ( implicit !== '' ) { - needles.set(implicit, safe.initPattern(prop, options)); + let value; + if ( raw === 'undefined' ) { + value = undefined; + } else if ( raw === 'false' ) { + value = false; + } else if ( raw === 'true' ) { + value = true; + } else if ( raw === 'null' ) { + value = null; + } else if ( raw === "''" || raw === '' ) { + value = ''; + } else if ( raw === '[]' || raw === 'emptyArr' ) { + value = []; + } else if ( raw === '{}' || raw === 'emptyObj' ) { + value = {}; + } else if ( raw === 'noopFunc' ) { + value = function(){}; + } else if ( raw === 'trueFunc' ) { + value = function(){ return true; }; + } else if ( raw === 'falseFunc' ) { + value = function(){ return false; }; + } else if ( raw === 'throwFunc' ) { + value = function(){ throw ''; }; + } else if ( /^-?\d+$/.test(raw) ) { + value = parseInt(raw); + if ( isNaN(raw) ) { return; } + if ( Math.abs(raw) > 0x7FFF ) { return; } + } else if ( trusted ) { + if ( raw.startsWith('json:') ) { + try { value = safe.JSON_parse(raw.slice(5)); } catch { return; } + } else if ( raw.startsWith('{') && raw.endsWith('}') ) { + try { value = safe.JSON_parse(raw).value; } catch { return; } } + } else { + return; } - return needles; -} -function matchObjectPropertiesFn(propNeedles, ...objs) { - const safe = safeSelf(); - const matched = []; - for ( const obj of objs ) { - if ( obj instanceof Object === false ) { continue; } - for ( const [ prop, details ] of propNeedles ) { - let value = obj[prop]; - if ( value === undefined ) { continue; } - if ( typeof value !== 'string' ) { - try { value = safe.JSON_stringify(value); } - catch { } - if ( typeof value !== 'string' ) { continue; } - } - if ( safe.testPattern(details, value) === false ) { return; } - matched.push(`${prop}: ${value}`); + if ( extraArgs.as !== undefined ) { + if ( extraArgs.as === 'function' ) { + return ( ) => value; + } else if ( extraArgs.as === 'callback' ) { + return ( ) => (( ) => value); + } else if ( extraArgs.as === 'resolved' ) { + return Promise.resolve(value); + } else if ( extraArgs.as === 'rejected' ) { + return Promise.reject(value); } } - return matched; + return value; } function safeSelf() { if ( safeSelf.safe ) { @@ -33140,8 +32768,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -33154,7 +32781,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -33165,10 +32792,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -33221,7 +32846,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -33309,601 +32934,128 @@ function safeSelf() { } return safe; } -function generateContentFn(trusted, directive) { - const safe = safeSelf(); - const randomize = len => { - const chunks = []; - let textSize = 0; - do { - const s = safe.Math_random().toString(36).slice(2); - chunks.push(s); - textSize += s.length; +function runAt(fn, when) { + const intFromReadyState = state => { + const targets = { + 'loading': 1, 'asap': 1, + 'interactive': 2, 'end': 2, '2': 2, + 'complete': 3, 'idle': 3, '3': 3, + }; + const tokens = Array.isArray(state) ? state : [ state ]; + for ( const token of tokens ) { + const prop = `${token}`; + if ( Object.hasOwn(targets, prop) === false ) { continue; } + return targets[prop]; } - while ( textSize < len ); - return chunks.join(' ').slice(0, len); + return 0; }; - if ( directive === 'true' ) { - return randomize(10); - } - if ( directive === 'emptyObj' ) { - return '{}'; - } - if ( directive === 'emptyArr' ) { - return '[]'; - } - if ( directive === 'emptyStr' ) { - return ''; - } - if ( directive.startsWith('length:') ) { - const match = /^length:(\d+)(?:-(\d+))?$/.exec(directive); - if ( match === null ) { return ''; } - const min = parseInt(match[1], 10); - const extent = safe.Math_max(parseInt(match[2], 10) || 0, min) - min; - const len = safe.Math_min(min + extent * safe.Math_random(), 500000); - return randomize(len | 0); - } - if ( directive.startsWith('war:') ) { - if ( scriptletGlobals.warOrigin === undefined ) { return ''; } - return new Promise(resolve => { - const warOrigin = scriptletGlobals.warOrigin; - const warName = directive.slice(4); - const fullpath = [ warOrigin, '/', warName ]; - const warSecret = scriptletGlobals.warSecret; - if ( warSecret !== undefined ) { - fullpath.push('?secret=', warSecret); - } - const warXHR = new safe.XMLHttpRequest(); - warXHR.responseType = 'text'; - warXHR.onloadend = ev => { - resolve(ev.target.responseText || ''); - }; - warXHR.open('GET', fullpath.join('')); - warXHR.send(); - }).catch(( ) => ''); - } - if ( directive.startsWith('join:') ) { - const parts = directive.slice(7) - .split(directive.slice(5, 7)) - .map(a => generateContentFn(trusted, a)); - return parts.some(a => a instanceof Promise) - ? Promise.all(parts).then(parts => parts.join('')) - : parts.join(''); - } - if ( trusted ) { - return directive; + const runAt = intFromReadyState(when); + if ( intFromReadyState(document.readyState) >= runAt ) { + fn(); return; } - return ''; + const onStateChange = ( ) => { + if ( intFromReadyState(document.readyState) < runAt ) { return; } + fn(); + safe.removeEventListener.apply(document, args); + }; + const safe = safeSelf(); + const args = [ 'readystatechange', onStateChange, { capture: true } ]; + safe.addEventListener.apply(document, args); } -function preventXhrFn( +function setConstantFn( trusted = false, - propsToMatch = '', - directive = '' + chain = '', + rawValue = '', + ...varargs ) { - if ( typeof propsToMatch !== 'string' ) { return; } + if ( chain === '' ) { return; } const safe = safeSelf(); - const scriptletName = trusted ? 'trusted-prevent-xhr' : 'prevent-xhr'; - const logPrefix = safe.makeLogPrefix(scriptletName, propsToMatch, directive); - const xhrInstances = new WeakMap(); - const propNeedles = parsePropertiesToMatchFn(propsToMatch, 'url'); - const warOrigin = scriptletGlobals.warOrigin; - const safeDispatchEvent = (xhr, type) => { - try { - xhr.dispatchEvent(new Event(type)); - } catch { - } - }; - proxyApplyFn('XMLHttpRequest.prototype.open', function(context) { - const { thisArg, callArgs } = context; - xhrInstances.delete(thisArg); - const [ method, url, ...args ] = callArgs; - if ( warOrigin !== undefined && url.startsWith(warOrigin) ) { - return context.reflect(); - } - const haystack = { method, url }; - if ( propsToMatch === '' && directive === '' ) { - safe.uboLog(logPrefix, `Called: ${safe.JSON_stringify(haystack, null, 2)}`); - return context.reflect(); - } - if ( matchObjectPropertiesFn(propNeedles, haystack) ) { - const xhrDetails = Object.assign(haystack, { - xhr: thisArg, - defer: args.length === 0 || !!args[0], - directive, - headers: { - 'date': '', - 'content-type': '', - 'content-length': '', + const logPrefix = safe.makeLogPrefix('set-constant', chain, rawValue); + const extraArgs = safe.parseVarargs(varargs); + function setConstant(chain, rawValue) { + const trappedProp = (( ) => { + const pos = chain.lastIndexOf('.'); + if ( pos === -1 ) { return chain; } + return chain.slice(pos+1); + })(); + const cloakFunc = fn => { + safe.Object_defineProperty(fn, 'name', { value: trappedProp }); + return new Proxy(fn, { + defineProperty(target, prop) { + if ( prop !== 'toString' ) { + return Reflect.defineProperty(...arguments); + } + return true; }, - url: haystack.url, - props: { - response: { value: '' }, - responseText: { value: '' }, - responseXML: { value: null }, + deleteProperty(target, prop) { + if ( prop !== 'toString' ) { + return Reflect.deleteProperty(...arguments); + } + return true; + }, + get(target, prop) { + if ( prop === 'toString' ) { + return function() { + return `function ${trappedProp}() { [native code] }`; + }.bind(null); + } + return Reflect.get(...arguments); }, }); - xhrInstances.set(thisArg, xhrDetails); - } - return context.reflect(); - }); - proxyApplyFn('XMLHttpRequest.prototype.send', function(context) { - const { thisArg } = context; - const xhrDetails = xhrInstances.get(thisArg); - if ( xhrDetails === undefined ) { - return context.reflect(); - } - xhrDetails.headers['date'] = (new Date()).toUTCString(); - let xhrText = ''; - switch ( thisArg.responseType ) { - case 'arraybuffer': - xhrDetails.props.response.value = new ArrayBuffer(0); - xhrDetails.headers['content-type'] = 'application/octet-stream'; - break; - case 'blob': - xhrDetails.props.response.value = new Blob([]); - xhrDetails.headers['content-type'] = 'application/octet-stream'; - break; - case 'document': { - const parser = new DOMParser(); - const doc = parser.parseFromString('', 'text/html'); - xhrDetails.props.response.value = doc; - xhrDetails.props.responseXML.value = doc; - xhrDetails.headers['content-type'] = 'text/html'; - break; + }; + if ( trappedProp === '' ) { return; } + const thisScript = document.currentScript; + let normalValue = validateConstantFn(trusted, rawValue, extraArgs); + if ( rawValue === 'noopFunc' || rawValue === 'trueFunc' || rawValue === 'falseFunc' ) { + normalValue = cloakFunc(normalValue); } - case 'json': - xhrDetails.props.response.value = {}; - xhrDetails.props.responseText.value = '{}'; - xhrDetails.headers['content-type'] = 'application/json'; - break; - default: { - if ( directive === '' ) { break; } - xhrText = generateContentFn(trusted, xhrDetails.directive); - if ( xhrText instanceof Promise ) { - xhrText = xhrText.then(text => { - xhrDetails.props.response.value = text; - xhrDetails.props.responseText.value = text; + let aborted = false; + const mustAbort = function(v) { + if ( trusted ) { return false; } + if ( aborted ) { return true; } + aborted = + (v !== undefined && v !== null) && + (normalValue !== undefined && normalValue !== null) && + (typeof v !== typeof normalValue); + if ( aborted ) { + safe.uboLog(logPrefix, `Aborted because value set to ${v}`); + } + return aborted; + }; + // https://github.com/uBlockOrigin/uBlock-issues/issues/156 + // Support multiple trappers for the same property. + const trapProp = function(owner, prop, configurable, handler) { + if ( handler.init(configurable ? owner[prop] : normalValue) === false ) { return; } + const odesc = safe.Object_getOwnPropertyDescriptor(owner, prop); + let prevGetter, prevSetter; + if ( odesc instanceof safe.Object ) { + owner[prop] = normalValue; + if ( odesc.get instanceof Function ) { + prevGetter = odesc.get; + } + if ( odesc.set instanceof Function ) { + prevSetter = odesc.set; + } + } + try { + safe.Object_defineProperty(owner, prop, { + configurable, + get() { + if ( prevGetter !== undefined ) { + prevGetter(); + } + return handler.getter(); + }, + set(a) { + if ( prevSetter !== undefined ) { + prevSetter(a); + } + handler.setter(a); + } }); - } else { - xhrDetails.props.response.value = xhrText; - xhrDetails.props.responseText.value = xhrText; - } - xhrDetails.headers['content-type'] = 'text/plain'; - break; - } - } - if ( xhrDetails.defer === false ) { - xhrDetails.headers['content-length'] = `${xhrDetails.props.response.value}`.length; - Object.defineProperties(xhrDetails.xhr, { - readyState: { value: 4 }, - responseURL: { value: xhrDetails.url }, - status: { value: 200 }, - statusText: { value: 'OK' }, - }); - Object.defineProperties(xhrDetails.xhr, xhrDetails.props); - return; - } - Promise.resolve(xhrText).then(( ) => xhrDetails).then(details => { - Object.defineProperties(details.xhr, { - readyState: { value: 1, configurable: true }, - responseURL: { value: xhrDetails.url }, - }); - safeDispatchEvent(details.xhr, 'readystatechange'); - return details; - }).then(details => { - xhrDetails.headers['content-length'] = `${details.props.response.value}`.length; - Object.defineProperties(details.xhr, { - readyState: { value: 2, configurable: true }, - status: { value: 200 }, - statusText: { value: 'OK' }, - }); - safeDispatchEvent(details.xhr, 'readystatechange'); - return details; - }).then(details => { - Object.defineProperties(details.xhr, { - readyState: { value: 3, configurable: true }, - }); - Object.defineProperties(details.xhr, details.props); - safeDispatchEvent(details.xhr, 'readystatechange'); - return details; - }).then(details => { - Object.defineProperties(details.xhr, { - readyState: { value: 4 }, - }); - safeDispatchEvent(details.xhr, 'readystatechange'); - safeDispatchEvent(details.xhr, 'load'); - safeDispatchEvent(details.xhr, 'loadend'); - safe.uboLog(logPrefix, `Prevented with response:\n${details.xhr.response}`); - }); - }); - proxyApplyFn('XMLHttpRequest.prototype.getResponseHeader', function(context) { - const { thisArg } = context; - const xhrDetails = xhrInstances.get(thisArg); - if ( xhrDetails === undefined || thisArg.readyState < thisArg.HEADERS_RECEIVED ) { - return context.reflect(); - } - const headerName = `${context.callArgs[0]}`; - const value = xhrDetails.headers[headerName.toLowerCase()]; - if ( value !== undefined && value !== '' ) { return value; } - return null; - }); - proxyApplyFn('XMLHttpRequest.prototype.getAllResponseHeaders', function(context) { - const { thisArg } = context; - const xhrDetails = xhrInstances.get(thisArg); - if ( xhrDetails === undefined || thisArg.readyState < thisArg.HEADERS_RECEIVED ) { - return context.reflect(); - } - const out = []; - for ( const [ name, value ] of Object.entries(xhrDetails.headers) ) { - if ( !value ) { continue; } - out.push(`${name}: ${value}`); - } - if ( out.length !== 0 ) { out.push(''); } - return out.join('\r\n'); - }); -} -function trustedPreventXhr(...args) { - preventXhrFn(true, ...args); -}; -trustedPreventXhr(...args); -}, -}; - - -scriptlets['set-constant.js'] = { -aliases: ["set.js"], - -requiresTrust: false, -func: function (scriptletGlobals = {}, ...args) { -function validateConstantFn(trusted, raw, extraArgs = {}) { - const safe = safeSelf(); - let value; - if ( raw === 'undefined' ) { - value = undefined; - } else if ( raw === 'false' ) { - value = false; - } else if ( raw === 'true' ) { - value = true; - } else if ( raw === 'null' ) { - value = null; - } else if ( raw === "''" || raw === '' ) { - value = ''; - } else if ( raw === '[]' || raw === 'emptyArr' ) { - value = []; - } else if ( raw === '{}' || raw === 'emptyObj' ) { - value = {}; - } else if ( raw === 'noopFunc' ) { - value = function(){}; - } else if ( raw === 'trueFunc' ) { - value = function(){ return true; }; - } else if ( raw === 'falseFunc' ) { - value = function(){ return false; }; - } else if ( raw === 'throwFunc' ) { - value = function(){ throw ''; }; - } else if ( /^-?\d+$/.test(raw) ) { - value = parseInt(raw); - if ( isNaN(raw) ) { return; } - if ( Math.abs(raw) > 0x7FFF ) { return; } - } else if ( trusted ) { - if ( raw.startsWith('json:') ) { - try { value = safe.JSON_parse(raw.slice(5)); } catch { return; } - } else if ( raw.startsWith('{') && raw.endsWith('}') ) { - try { value = safe.JSON_parse(raw).value; } catch { return; } - } - } else { - return; - } - if ( extraArgs.as !== undefined ) { - if ( extraArgs.as === 'function' ) { - return ( ) => value; - } else if ( extraArgs.as === 'callback' ) { - return ( ) => (( ) => value); - } else if ( extraArgs.as === 'resolved' ) { - return Promise.resolve(value); - } else if ( extraArgs.as === 'rejected' ) { - return Promise.reject(value); - } - } - return value; -} -function safeSelf() { - if ( safeSelf.safe ) { - return safeSelf.safe; - } - const self = globalThis; - const safe = { - 'Array_from': Array.from, - 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), - 'Math_floor': Math.floor, - 'Math_max': Math.max, - 'Math_min': Math.min, - 'Math_random': Math.random, - 'Object': Object, - 'Object_defineProperty': Object.defineProperty.bind(Object), - 'Object_defineProperties': Object.defineProperties.bind(Object), - 'Object_fromEntries': Object.fromEntries.bind(Object), - 'Object_getOwnPropertyDescriptor': Object.getOwnPropertyDescriptor.bind(Object), - 'Object_hasOwn': Object.hasOwn.bind(Object), - 'Object_toString': Object.prototype.toString, - 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, - 'RegExp_exec': self.RegExp.prototype.exec, - 'Request_clone': self.Request.prototype.clone, - 'String': self.String, - 'String_fromCharCode': String.fromCharCode, - 'String_split': String.prototype.split, - 'XMLHttpRequest': self.XMLHttpRequest, - 'addEventListener': self.EventTarget.prototype.addEventListener, - 'removeEventListener': self.EventTarget.prototype.removeEventListener, - 'fetch': self.fetch, - 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), - 'log': console.log.bind(console), - // Properties - logLevel: 0, - // Methods - makeLogPrefix(...args) { - return this.sendToLogger && `[${args.join(' \u205D ')}]` || ''; - }, - uboLog(...args) { - if ( this.sendToLogger === undefined ) { return; } - if ( args === undefined || args[0] === '' ) { return; } - return this.sendToLogger('info', ...args); - - }, - uboErr(...args) { - if ( this.sendToLogger === undefined ) { return; } - if ( args === undefined || args[0] === '' ) { return; } - return this.sendToLogger('error', ...args); - }, - escapeRegexChars(s) { - return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - }, - initPattern(pattern, options = {}) { - if ( pattern === '' ) { - return { matchAll: true, expect: true }; - } - const expect = (options.canNegate !== true || pattern.startsWith('!') === false); - if ( expect === false ) { - pattern = pattern.slice(1); - } - const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern); - if ( match !== null ) { - return { - re: new this.RegExp( - match[1], - match[2] || options.flags - ), - expect, - }; - } - if ( options.flags !== undefined ) { - return { - re: new this.RegExp(this.escapeRegexChars(pattern), - options.flags - ), - expect, - }; - } - return { pattern, expect }; - }, - testPattern(details, haystack) { - if ( details.matchAll ) { return true; } - if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; - } - return haystack.includes(details.pattern) === details.expect; - }, - patternToRegex(pattern, flags = undefined, verbatim = false) { - if ( pattern === '' ) { return /^/; } - const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern); - if ( match === null ) { - const reStr = this.escapeRegexChars(pattern); - return new RegExp(verbatim ? `^${reStr}$` : reStr, flags); - } - try { - return new RegExp(match[1], match[2] || undefined); - } - catch { - } - return /^/; - }, - parseVarargs(varargs) { - const entries = varargs.reduce((out, v, i, a) => { - if ( i & 1 ) { return out; } - const rawValue = a[i+1]; - const value = /^\d+$/.test(rawValue) - ? parseInt(rawValue, 10) - : rawValue; - out.push([ a[i], value ]); - return out; - }, []); - return this.Object_fromEntries(entries); - }, - }; - safeSelf.safe = safe; - if ( scriptletGlobals.bcSecret === undefined ) { return safe; } - // This is executed only when the logger is opened - safe.logLevel = scriptletGlobals.logLevel || 1; - let lastLogType = ''; - let lastLogText = ''; - let lastLogTime = 0; - safe.toLogText = (type, ...args) => { - if ( args.length === 0 ) { return; } - const text = `[${document.location.hostname || document.location.href}]${args.join(' ')}`; - if ( text === lastLogText && type === lastLogType ) { - if ( (Date.now() - lastLogTime) < 5000 ) { return; } - } - lastLogType = type; - lastLogText = text; - lastLogTime = Date.now(); - return text; - }; - try { - const bc = new self.BroadcastChannel(scriptletGlobals.bcSecret); - let bcBuffer = []; - safe.sendToLogger = (type, ...args) => { - const text = safe.toLogText(type, ...args); - if ( text === undefined ) { return; } - if ( bcBuffer === undefined ) { - return bc.postMessage({ what: 'messageToLogger', type, text }); - } - bcBuffer.push({ type, text }); - }; - bc.onmessage = ev => { - const msg = ev.data; - switch ( msg ) { - case 'iamready!': - if ( bcBuffer === undefined ) { break; } - bcBuffer.forEach(({ type, text }) => - bc.postMessage({ what: 'messageToLogger', type, text }) - ); - bcBuffer = undefined; - break; - case 'setScriptletLogLevelToOne': - safe.logLevel = 1; - break; - case 'setScriptletLogLevelToTwo': - safe.logLevel = 2; - break; - } - }; - bc.postMessage('areyouready?'); - } catch { - safe.sendToLogger = (type, ...args) => { - const text = safe.toLogText(type, ...args); - if ( text === undefined ) { return; } - safe.log(`uBO ${text}`); - }; - } - return safe; -} -function runAt(fn, when) { - const intFromReadyState = state => { - const targets = { - 'loading': 1, 'asap': 1, - 'interactive': 2, 'end': 2, '2': 2, - 'complete': 3, 'idle': 3, '3': 3, - }; - const tokens = Array.isArray(state) ? state : [ state ]; - for ( const token of tokens ) { - const prop = `${token}`; - if ( Object.hasOwn(targets, prop) === false ) { continue; } - return targets[prop]; - } - return 0; - }; - const runAt = intFromReadyState(when); - if ( intFromReadyState(document.readyState) >= runAt ) { - fn(); return; - } - const onStateChange = ( ) => { - if ( intFromReadyState(document.readyState) < runAt ) { return; } - fn(); - safe.removeEventListener.apply(document, args); - }; - const safe = safeSelf(); - const args = [ 'readystatechange', onStateChange, { capture: true } ]; - safe.addEventListener.apply(document, args); -} -function setConstantFn( - trusted = false, - chain = '', - rawValue = '', - ...varargs -) { - if ( chain === '' ) { return; } - const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('set-constant', chain, rawValue); - const extraArgs = safe.parseVarargs(varargs); - function setConstant(chain, rawValue) { - const trappedProp = (( ) => { - const pos = chain.lastIndexOf('.'); - if ( pos === -1 ) { return chain; } - return chain.slice(pos+1); - })(); - const cloakFunc = fn => { - safe.Object_defineProperty(fn, 'name', { value: trappedProp }); - return new Proxy(fn, { - defineProperty(target, prop) { - if ( prop !== 'toString' ) { - return Reflect.defineProperty(...arguments); - } - return true; - }, - deleteProperty(target, prop) { - if ( prop !== 'toString' ) { - return Reflect.deleteProperty(...arguments); - } - return true; - }, - get(target, prop) { - if ( prop === 'toString' ) { - return function() { - return `function ${trappedProp}() { [native code] }`; - }.bind(null); - } - return Reflect.get(...arguments); - }, - }); - }; - if ( trappedProp === '' ) { return; } - const thisScript = document.currentScript; - let normalValue = validateConstantFn(trusted, rawValue, extraArgs); - if ( rawValue === 'noopFunc' || rawValue === 'trueFunc' || rawValue === 'falseFunc' ) { - normalValue = cloakFunc(normalValue); - } - let aborted = false; - const mustAbort = function(v) { - if ( trusted ) { return false; } - if ( aborted ) { return true; } - aborted = - (v !== undefined && v !== null) && - (normalValue !== undefined && normalValue !== null) && - (typeof v !== typeof normalValue); - if ( aborted ) { - safe.uboLog(logPrefix, `Aborted because value set to ${v}`); - } - return aborted; - }; - // https://github.com/uBlockOrigin/uBlock-issues/issues/156 - // Support multiple trappers for the same property. - const trapProp = function(owner, prop, configurable, handler) { - if ( handler.init(configurable ? owner[prop] : normalValue) === false ) { return; } - const odesc = safe.Object_getOwnPropertyDescriptor(owner, prop); - let prevGetter, prevSetter; - if ( odesc instanceof safe.Object ) { - owner[prop] = normalValue; - if ( odesc.get instanceof Function ) { - prevGetter = odesc.get; - } - if ( odesc.set instanceof Function ) { - prevSetter = odesc.set; - } - } - try { - safe.Object_defineProperty(owner, prop, { - configurable, - get() { - if ( prevGetter !== undefined ) { - prevGetter(); - } - return handler.getter(); - }, - set(a) { - if ( prevSetter !== undefined ) { - prevSetter(a); - } - handler.setter(a); - } - }); - safe.uboLog(logPrefix, 'Trap installed'); - } catch(ex) { - safe.uboErr(logPrefix, ex); + safe.uboLog(logPrefix, 'Trap installed'); + } catch(ex) { + safe.uboErr(logPrefix, ex); } }; const trapChain = function(owner, chain) { @@ -33960,18 +33112,18 @@ function setConstantFn( setConstant(chain, rawValue); }, extraArgs.runAt); } -function setConstant( +function trustedSetConstant( ...args ) { - setConstantFn(false, ...args); + setConstantFn(true, ...args); }; -setConstant(...args); +trustedSetConstant(...args); }, }; -scriptlets['trusted-set-constant.js'] = { -aliases: ["trusted-set.js"], +scriptlets['trusted-replace-argument.js'] = { +aliases: [], requiresTrust: true, func: function (scriptletGlobals = {}, ...args) { @@ -34034,8 +33186,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -34048,7 +33199,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -34059,10 +33210,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -34115,7 +33264,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -34203,249 +33352,1285 @@ function safeSelf() { } return safe; } -function runAt(fn, when) { - const intFromReadyState = state => { - const targets = { - 'loading': 1, 'asap': 1, - 'interactive': 2, 'end': 2, '2': 2, - 'complete': 3, 'idle': 3, '3': 3, +function proxyApplyFn( + target = '', + handler = '', + options = {} +) { + let context = globalThis; + let prop = target; + 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); + } + const fn = context[prop]; + if ( typeof fn !== 'function' ) { return; } + if ( proxyApplyFn.CtorContext === undefined ) { + proxyApplyFn.ctorContexts = []; + proxyApplyFn.CtorContext = class { + constructor(...args) { + this.init(...args); + } + init(callFn, callArgs) { + this.callFn = callFn; + this.callArgs = callArgs; + return this; + } + reflect() { + const r = Reflect.construct(this.callFn, this.callArgs); + this.callFn = this.callArgs = this.private = undefined; + proxyApplyFn.ctorContexts.push(this); + return r; + } + static factory(...args) { + return proxyApplyFn.ctorContexts.length !== 0 + ? proxyApplyFn.ctorContexts.pop().init(...args) + : new proxyApplyFn.CtorContext(...args); + } }; - const tokens = Array.isArray(state) ? state : [ state ]; - for ( const token of tokens ) { - const prop = `${token}`; - if ( Object.hasOwn(targets, prop) === false ) { continue; } - return targets[prop]; + proxyApplyFn.applyContexts = []; + proxyApplyFn.ApplyContext = class { + constructor(...args) { + this.init(...args); + } + init(callFn, thisArg, callArgs) { + this.callFn = callFn; + this.thisArg = thisArg; + this.callArgs = callArgs; + return this; + } + reflect() { + const r = Reflect.apply(this.callFn, this.thisArg, this.callArgs); + this.callFn = this.thisArg = this.callArgs = this.private = undefined; + proxyApplyFn.applyContexts.push(this); + return r; + } + static factory(...args) { + return proxyApplyFn.applyContexts.length !== 0 + ? proxyApplyFn.applyContexts.pop().init(...args) + : new proxyApplyFn.ApplyContext(...args); + } + }; + proxyApplyFn.isCtor = new Map(); + proxyApplyFn.proxies = new WeakMap(); + if ( (options.skipToString || proxyApplyFn.skipToString) !== true ) { + proxyApplyFn.nativeToString = Function.prototype.toString; + const proxiedToString = new Proxy(Function.prototype.toString, { + apply(target, thisArg) { + let proxied = thisArg; + for(;;) { + const fn = proxyApplyFn.proxies.get(proxied); + if ( fn === undefined ) { break; } + proxied = fn; + } + return proxyApplyFn.nativeToString.call(proxied); + } + }); + proxyApplyFn.proxies.set(proxiedToString, proxyApplyFn.nativeToString); + Function.prototype.toString = proxiedToString; + } + } + if ( proxyApplyFn.isCtor.has(target) === false ) { + proxyApplyFn.isCtor.set(target, fn.prototype?.constructor === fn); + } + const proxyDetails = { + apply(target, thisArg, args) { + return handler(proxyApplyFn.ApplyContext.factory(target, thisArg, args)); } - return 0; }; - const runAt = intFromReadyState(when); - if ( intFromReadyState(document.readyState) >= runAt ) { - fn(); return; + if ( proxyApplyFn.isCtor.get(target) ) { + proxyDetails.construct = function(target, args) { + return handler(proxyApplyFn.CtorContext.factory(target, args)); + }; + } + const proxiedTarget = new Proxy(fn, proxyDetails); + proxyApplyFn.proxies.set(proxiedTarget, fn); + context[prop] = proxiedTarget; +} +class ArglistParser { + constructor(separatorChar = ',', mustQuote = false) { + this.separatorChar = this.actualSeparatorChar = separatorChar; + this.separatorCode = this.actualSeparatorCode = separatorChar.charCodeAt(0); + this.mustQuote = mustQuote; + this.quoteBeg = 0; this.quoteEnd = 0; + this.argBeg = 0; this.argEnd = 0; + this.separatorBeg = 0; this.separatorEnd = 0; + this.transform = false; + this.failed = false; + this.reWhitespaceStart = /^\s+/; + this.reWhitespaceEnd = /(?:^|\S)(\s+)$/; + this.reOddTrailingEscape = /(?:^|[^\\])(?:\\\\)*\\$/; + this.reTrailingEscapeChars = /\\+$/; + } + nextArg(pattern, beg = 0) { + const len = pattern.length; + this.quoteBeg = beg + this.leftWhitespaceCount(pattern.slice(beg)); + this.failed = false; + const qc = pattern.charCodeAt(this.quoteBeg); + if ( qc === 0x22 /* " */ || qc === 0x27 /* ' */ || qc === 0x60 /* ` */ ) { + this.indexOfNextArgSeparator(pattern, qc); + if ( this.argEnd !== len ) { + this.quoteEnd = this.argEnd + 1; + this.separatorBeg = this.separatorEnd = this.quoteEnd; + this.separatorEnd += this.leftWhitespaceCount(pattern.slice(this.quoteEnd)); + if ( this.separatorEnd === len ) { return this; } + if ( pattern.charCodeAt(this.separatorEnd) === this.separatorCode ) { + this.separatorEnd += 1; + return this; + } + } + } + this.indexOfNextArgSeparator(pattern, this.separatorCode); + this.separatorBeg = this.separatorEnd = this.argEnd; + if ( this.separatorBeg < len ) { + this.separatorEnd += 1; + } + this.argEnd -= this.rightWhitespaceCount(pattern.slice(0, this.separatorBeg)); + this.quoteEnd = this.argEnd; + if ( this.mustQuote ) { + this.failed = true; + } + return this; + } + normalizeArg(s, char = '') { + if ( char === '' ) { char = this.actualSeparatorChar; } + let out = ''; + let pos = 0; + while ( (pos = s.lastIndexOf(char)) !== -1 ) { + out = s.slice(pos) + out; + s = s.slice(0, pos); + const match = this.reTrailingEscapeChars.exec(s); + if ( match === null ) { continue; } + const tail = (match[0].length & 1) !== 0 + ? match[0].slice(0, -1) + : match[0]; + out = tail + out; + s = s.slice(0, -match[0].length); + } + if ( out === '' ) { return s; } + return s + out; + } + leftWhitespaceCount(s) { + const match = this.reWhitespaceStart.exec(s); + return match === null ? 0 : match[0].length; + } + rightWhitespaceCount(s) { + const match = this.reWhitespaceEnd.exec(s); + return match === null ? 0 : match[1].length; + } + indexOfNextArgSeparator(pattern, separatorCode) { + this.argBeg = this.argEnd = separatorCode !== this.separatorCode + ? this.quoteBeg + 1 + : this.quoteBeg; + this.transform = false; + if ( separatorCode !== this.actualSeparatorCode ) { + this.actualSeparatorCode = separatorCode; + this.actualSeparatorChar = String.fromCharCode(separatorCode); + } + while ( this.argEnd < pattern.length ) { + const pos = pattern.indexOf(this.actualSeparatorChar, this.argEnd); + if ( pos === -1 ) { + return (this.argEnd = pattern.length); + } + if ( this.reOddTrailingEscape.test(pattern.slice(0, pos)) === false ) { + return (this.argEnd = pos); + } + this.transform = true; + this.argEnd = pos + 1; + } + } +} +function parseReplaceFn(s) { + if ( s.charCodeAt(0) !== 0x2F /* / */ ) { return; } + const parser = new ArglistParser('/'); + parser.nextArg(s, 1); + let pattern = s.slice(parser.argBeg, parser.argEnd); + if ( parser.transform ) { + pattern = parser.normalizeArg(pattern); + } + if ( pattern === '' ) { return; } + parser.nextArg(s, parser.separatorEnd); + let replacement = s.slice(parser.argBeg, parser.argEnd); + if ( parser.separatorEnd === parser.separatorBeg ) { return; } + if ( parser.transform ) { + replacement = parser.normalizeArg(replacement); + } + const flags = s.slice(parser.separatorEnd); + try { + return { re: new RegExp(pattern, flags), replacement }; + } catch { + } +} +function trustedReplaceArgument( + propChain = '', + argposRaw = '', + argraw = '', + ...varargs +) { + if ( propChain === '' ) { return; } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('trusted-replace-argument', propChain, argposRaw, argraw); + const argoffset = parseInt(argposRaw, 10) || 0; + const extraArgs = safe.parseVarargs(varargs); + let replacer; + if ( argraw.startsWith('repl:/') ) { + const parsed = parseReplaceFn(argraw.slice(5)); + if ( parsed === undefined ) { return; } + replacer = arg => `${arg}`.replace(replacer.re, replacer.replacement); + Object.assign(replacer, parsed); + } else if ( argraw.startsWith('add:') ) { + const delta = parseFloat(argraw.slice(4)); + if ( isNaN(delta) ) { return; } + replacer = arg => Number(arg) + delta; + } else { + const value = validateConstantFn(true, argraw, extraArgs); + replacer = ( ) => value; + } + const reCondition = extraArgs.condition + ? safe.patternToRegex(`${extraArgs.condition}`) + : /^/; + const getArg = context => { + if ( argposRaw === 'this' ) { return context.thisArg; } + const { callArgs } = context; + const argpos = argoffset >= 0 ? argoffset : callArgs.length - argoffset; + if ( argpos < 0 || argpos >= callArgs.length ) { return; } + context.private = { argpos }; + return callArgs[argpos]; + }; + const setArg = (context, value) => { + if ( argposRaw === 'this' ) { + if ( value !== context.thisArg ) { + context.thisArg = value; + } + } else if ( context.private ) { + context.callArgs[context.private.argpos] = value; + } + }; + proxyApplyFn(propChain, function(context) { + if ( argposRaw === '' ) { + safe.uboLog(logPrefix, `Arguments:\n${context.callArgs.join('\n')}`); + return context.reflect(); + } + const argBefore = getArg(context); + if ( extraArgs.condition !== undefined ) { + if ( safe.RegExp_test(reCondition, argBefore) === false ) { + return context.reflect(); + } + } + const argAfter = replacer(argBefore); + if ( argAfter !== argBefore ) { + setArg(context, argAfter); + safe.uboLog(logPrefix, `Replaced argument:\nBefore: ${JSON.stringify(argBefore)}\nAfter: ${argAfter}`); + } + return context.reflect(); + }); +}; +trustedReplaceArgument(...args); +}, +}; + + +scriptlets['spoof-css.js'] = { +aliases: [], + +requiresTrust: false, +func: function (scriptletGlobals = {}, ...args) { +function safeSelf() { + if ( safeSelf.safe ) { + return safeSelf.safe; + } + const self = globalThis; + const safe = { + 'Array_from': Array.from, + 'Error': self.Error, + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), + 'Math_floor': Math.floor, + 'Math_max': Math.max, + 'Math_min': Math.min, + 'Math_random': Math.random, + 'Object': Object, + 'Object_defineProperty': Object.defineProperty.bind(Object), + 'Object_defineProperties': Object.defineProperties.bind(Object), + 'Object_fromEntries': Object.fromEntries.bind(Object), + 'Object_getOwnPropertyDescriptor': Object.getOwnPropertyDescriptor.bind(Object), + 'Object_hasOwn': Object.hasOwn.bind(Object), + 'Object_toString': Object.prototype.toString, + 'RegExp': self.RegExp, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), + 'RegExp_exec': self.RegExp.prototype.exec, + 'Request_clone': self.Request.prototype.clone, + 'String': self.String, + 'String_fromCharCode': String.fromCharCode, + 'String_split': String.prototype.split, + 'XMLHttpRequest': self.XMLHttpRequest, + 'addEventListener': self.EventTarget.prototype.addEventListener, + 'removeEventListener': self.EventTarget.prototype.removeEventListener, + 'fetch': self.fetch, + 'JSON': self.JSON, + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), + 'log': console.log.bind(console), + // Properties + logLevel: 0, + // Methods + makeLogPrefix(...args) { + return this.sendToLogger && `[${args.join(' \u205D ')}]` || ''; + }, + uboLog(...args) { + if ( this.sendToLogger === undefined ) { return; } + if ( args === undefined || args[0] === '' ) { return; } + return this.sendToLogger('info', ...args); + + }, + uboErr(...args) { + if ( this.sendToLogger === undefined ) { return; } + if ( args === undefined || args[0] === '' ) { return; } + return this.sendToLogger('error', ...args); + }, + escapeRegexChars(s) { + return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + }, + initPattern(pattern, options = {}) { + if ( pattern === '' ) { + return { matchAll: true, expect: true }; + } + const expect = (options.canNegate !== true || pattern.startsWith('!') === false); + if ( expect === false ) { + pattern = pattern.slice(1); + } + const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern); + if ( match !== null ) { + return { + re: new this.RegExp( + match[1], + match[2] || options.flags + ), + expect, + }; + } + if ( options.flags !== undefined ) { + return { + re: new this.RegExp(this.escapeRegexChars(pattern), + options.flags + ), + expect, + }; + } + return { pattern, expect }; + }, + testPattern(details, haystack) { + if ( details.matchAll ) { return true; } + if ( details.re ) { + return this.RegExp_test(details.re, haystack) === details.expect; + } + return haystack.includes(details.pattern) === details.expect; + }, + patternToRegex(pattern, flags = undefined, verbatim = false) { + if ( pattern === '' ) { return /^/; } + const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern); + if ( match === null ) { + const reStr = this.escapeRegexChars(pattern); + return new RegExp(verbatim ? `^${reStr}$` : reStr, flags); + } + try { + return new RegExp(match[1], match[2] || undefined); + } + catch { + } + return /^/; + }, + parseVarargs(varargs) { + const entries = varargs.reduce((out, v, i, a) => { + if ( i & 1 ) { return out; } + const rawValue = a[i+1]; + const value = /^\d+$/.test(rawValue) + ? parseInt(rawValue, 10) + : rawValue; + out.push([ a[i], value ]); + return out; + }, []); + return this.Object_fromEntries(entries); + }, + }; + safeSelf.safe = safe; + if ( scriptletGlobals.bcSecret === undefined ) { return safe; } + // This is executed only when the logger is opened + safe.logLevel = scriptletGlobals.logLevel || 1; + let lastLogType = ''; + let lastLogText = ''; + let lastLogTime = 0; + safe.toLogText = (type, ...args) => { + if ( args.length === 0 ) { return; } + const text = `[${document.location.hostname || document.location.href}]${args.join(' ')}`; + if ( text === lastLogText && type === lastLogType ) { + if ( (Date.now() - lastLogTime) < 5000 ) { return; } + } + lastLogType = type; + lastLogText = text; + lastLogTime = Date.now(); + return text; + }; + try { + const bc = new self.BroadcastChannel(scriptletGlobals.bcSecret); + let bcBuffer = []; + safe.sendToLogger = (type, ...args) => { + const text = safe.toLogText(type, ...args); + if ( text === undefined ) { return; } + if ( bcBuffer === undefined ) { + return bc.postMessage({ what: 'messageToLogger', type, text }); + } + bcBuffer.push({ type, text }); + }; + bc.onmessage = ev => { + const msg = ev.data; + switch ( msg ) { + case 'iamready!': + if ( bcBuffer === undefined ) { break; } + bcBuffer.forEach(({ type, text }) => + bc.postMessage({ what: 'messageToLogger', type, text }) + ); + bcBuffer = undefined; + break; + case 'setScriptletLogLevelToOne': + safe.logLevel = 1; + break; + case 'setScriptletLogLevelToTwo': + safe.logLevel = 2; + break; + } + }; + bc.postMessage('areyouready?'); + } catch { + safe.sendToLogger = (type, ...args) => { + const text = safe.toLogText(type, ...args); + if ( text === undefined ) { return; } + safe.log(`uBO ${text}`); + }; + } + return safe; +} +function spoofCSS( + selector, + ...args +) { + if ( typeof selector !== 'string' ) { return; } + if ( selector === '' ) { return; } + const toCamelCase = s => s.replace(/-[a-z]/g, s => s.charAt(1).toUpperCase()); + const propToValueMap = new Map(); + const privatePropToValueMap = new Map(); + for ( let i = 0; i < args.length; i += 2 ) { + const prop = toCamelCase(args[i+0]); + if ( prop === '' ) { break; } + const value = args[i+1]; + if ( typeof value !== 'string' ) { break; } + if ( prop.charCodeAt(0) === 0x5F /* _ */ ) { + privatePropToValueMap.set(prop, value); + } else { + propToValueMap.set(prop, value); + } + } + const safe = safeSelf(); + const logPrefix = safe.makeLogPrefix('spoof-css', selector, ...args); + const instanceProperties = [ 'cssText', 'length', 'parentRule' ]; + const spoofStyle = (prop, real) => { + const normalProp = toCamelCase(prop); + const shouldSpoof = propToValueMap.has(normalProp); + const value = shouldSpoof ? propToValueMap.get(normalProp) : real; + if ( shouldSpoof ) { + safe.uboLog(logPrefix, `Spoofing ${prop} to ${value}`); + } + return value; + }; + const cloackFunc = (fn, thisArg, name) => { + const trap = fn.bind(thisArg); + Object.defineProperty(trap, 'name', { value: name }); + Object.defineProperty(trap, 'toString', { + value: ( ) => `function ${name}() { [native code] }` + }); + return trap; + }; + self.getComputedStyle = new Proxy(self.getComputedStyle, { + apply: function(target, thisArg, args) { + // eslint-disable-next-line no-debugger + if ( privatePropToValueMap.has('_debug') ) { debugger; } + const style = Reflect.apply(target, thisArg, args); + const targetElements = new WeakSet(document.querySelectorAll(selector)); + if ( targetElements.has(args[0]) === false ) { return style; } + const proxiedStyle = new Proxy(style, { + get(target, prop) { + if ( typeof target[prop] === 'function' ) { + if ( prop === 'getPropertyValue' ) { + return cloackFunc(function getPropertyValue(prop) { + return spoofStyle(prop, target[prop]); + }, target, 'getPropertyValue'); + } + return cloackFunc(target[prop], target, prop); + } + if ( instanceProperties.includes(prop) ) { + return Reflect.get(target, prop); + } + return spoofStyle(prop, Reflect.get(target, prop)); + }, + getOwnPropertyDescriptor(target, prop) { + if ( propToValueMap.has(prop) ) { + return { + configurable: true, + enumerable: true, + value: propToValueMap.get(prop), + writable: true, + }; + } + return Reflect.getOwnPropertyDescriptor(target, prop); + }, + }); + return proxiedStyle; + }, + get(target, prop) { + if ( prop === 'toString' ) { + return target.toString.bind(target); + } + return Reflect.get(target, prop); + }, + }); + Element.prototype.getBoundingClientRect = new Proxy(Element.prototype.getBoundingClientRect, { + apply: function(target, thisArg, args) { + // eslint-disable-next-line no-debugger + if ( privatePropToValueMap.has('_debug') ) { debugger; } + const rect = Reflect.apply(target, thisArg, args); + const targetElements = new WeakSet(document.querySelectorAll(selector)); + if ( targetElements.has(thisArg) === false ) { return rect; } + let { x, y, height, width } = rect; + if ( privatePropToValueMap.has('_rectx') ) { + x = parseFloat(privatePropToValueMap.get('_rectx')); + } + if ( privatePropToValueMap.has('_recty') ) { + y = parseFloat(privatePropToValueMap.get('_recty')); + } + if ( privatePropToValueMap.has('_rectw') ) { + width = parseFloat(privatePropToValueMap.get('_rectw')); + } else if ( propToValueMap.has('width') ) { + width = parseFloat(propToValueMap.get('width')); + } + if ( privatePropToValueMap.has('_recth') ) { + height = parseFloat(privatePropToValueMap.get('_recth')); + } else if ( propToValueMap.has('height') ) { + height = parseFloat(propToValueMap.get('height')); + } + return new self.DOMRect(x, y, width, height); + }, + get(target, prop) { + if ( prop === 'toString' ) { + return target.toString.bind(target); + } + return Reflect.get(target, prop); + }, + }); +}; +spoofCSS(...args); +}, +}; + + +scriptlets['prevent-xhr.js'] = { +aliases: ["no-xhr-if.js"], + +requiresTrust: false, +func: function (scriptletGlobals = {}, ...args) { +function proxyApplyFn( + target = '', + handler = '', + options = {} +) { + let context = globalThis; + let prop = target; + 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); + } + const fn = context[prop]; + if ( typeof fn !== 'function' ) { return; } + if ( proxyApplyFn.CtorContext === undefined ) { + proxyApplyFn.ctorContexts = []; + proxyApplyFn.CtorContext = class { + constructor(...args) { + this.init(...args); + } + init(callFn, callArgs) { + this.callFn = callFn; + this.callArgs = callArgs; + return this; + } + reflect() { + const r = Reflect.construct(this.callFn, this.callArgs); + this.callFn = this.callArgs = this.private = undefined; + proxyApplyFn.ctorContexts.push(this); + return r; + } + static factory(...args) { + return proxyApplyFn.ctorContexts.length !== 0 + ? proxyApplyFn.ctorContexts.pop().init(...args) + : new proxyApplyFn.CtorContext(...args); + } + }; + proxyApplyFn.applyContexts = []; + proxyApplyFn.ApplyContext = class { + constructor(...args) { + this.init(...args); + } + init(callFn, thisArg, callArgs) { + this.callFn = callFn; + this.thisArg = thisArg; + this.callArgs = callArgs; + return this; + } + reflect() { + const r = Reflect.apply(this.callFn, this.thisArg, this.callArgs); + this.callFn = this.thisArg = this.callArgs = this.private = undefined; + proxyApplyFn.applyContexts.push(this); + return r; + } + static factory(...args) { + return proxyApplyFn.applyContexts.length !== 0 + ? proxyApplyFn.applyContexts.pop().init(...args) + : new proxyApplyFn.ApplyContext(...args); + } + }; + proxyApplyFn.isCtor = new Map(); + proxyApplyFn.proxies = new WeakMap(); + if ( (options.skipToString || proxyApplyFn.skipToString) !== true ) { + proxyApplyFn.nativeToString = Function.prototype.toString; + const proxiedToString = new Proxy(Function.prototype.toString, { + apply(target, thisArg) { + let proxied = thisArg; + for(;;) { + const fn = proxyApplyFn.proxies.get(proxied); + if ( fn === undefined ) { break; } + proxied = fn; + } + return proxyApplyFn.nativeToString.call(proxied); + } + }); + proxyApplyFn.proxies.set(proxiedToString, proxyApplyFn.nativeToString); + Function.prototype.toString = proxiedToString; + } + } + if ( proxyApplyFn.isCtor.has(target) === false ) { + proxyApplyFn.isCtor.set(target, fn.prototype?.constructor === fn); + } + const proxyDetails = { + apply(target, thisArg, args) { + return handler(proxyApplyFn.ApplyContext.factory(target, thisArg, args)); + } + }; + if ( proxyApplyFn.isCtor.get(target) ) { + proxyDetails.construct = function(target, args) { + return handler(proxyApplyFn.CtorContext.factory(target, args)); + }; + } + const proxiedTarget = new Proxy(fn, proxyDetails); + proxyApplyFn.proxies.set(proxiedTarget, fn); + context[prop] = proxiedTarget; +} +function parsePropertiesToMatchFn(propsToMatch, implicit = '') { + const safe = safeSelf(); + const needles = new Map(); + if ( propsToMatch === undefined || propsToMatch === '' ) { return needles; } + const options = { canNegate: true }; + for ( const needle of safe.String_split.call(propsToMatch, /\s+/) ) { + let [ prop, pattern ] = safe.String_split.call(needle, ':'); + if ( prop === '' ) { continue; } + if ( pattern !== undefined && /[^$\w -]/.test(prop) ) { + prop = `${prop}:${pattern}`; + pattern = undefined; + } + if ( pattern !== undefined ) { + needles.set(prop, safe.initPattern(pattern, options)); + } else if ( implicit !== '' ) { + needles.set(implicit, safe.initPattern(prop, options)); + } + } + return needles; +} +function matchObjectPropertiesFn(propNeedles, ...objs) { + const safe = safeSelf(); + const matched = []; + for ( const obj of objs ) { + if ( obj instanceof Object === false ) { continue; } + for ( const [ prop, details ] of propNeedles ) { + let value = obj[prop]; + if ( value === undefined ) { continue; } + if ( typeof value !== 'string' ) { + try { value = safe.JSON_stringify(value); } + catch { } + if ( typeof value !== 'string' ) { continue; } + } + if ( safe.testPattern(details, value) === false ) { return; } + matched.push(`${prop}: ${value}`); + } + } + return matched; +} +function safeSelf() { + if ( safeSelf.safe ) { + return safeSelf.safe; + } + const self = globalThis; + const safe = { + 'Array_from': Array.from, + 'Error': self.Error, + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), + 'Math_floor': Math.floor, + 'Math_max': Math.max, + 'Math_min': Math.min, + 'Math_random': Math.random, + 'Object': Object, + 'Object_defineProperty': Object.defineProperty.bind(Object), + 'Object_defineProperties': Object.defineProperties.bind(Object), + 'Object_fromEntries': Object.fromEntries.bind(Object), + 'Object_getOwnPropertyDescriptor': Object.getOwnPropertyDescriptor.bind(Object), + 'Object_hasOwn': Object.hasOwn.bind(Object), + 'Object_toString': Object.prototype.toString, + 'RegExp': self.RegExp, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), + 'RegExp_exec': self.RegExp.prototype.exec, + 'Request_clone': self.Request.prototype.clone, + 'String': self.String, + 'String_fromCharCode': String.fromCharCode, + 'String_split': String.prototype.split, + 'XMLHttpRequest': self.XMLHttpRequest, + 'addEventListener': self.EventTarget.prototype.addEventListener, + 'removeEventListener': self.EventTarget.prototype.removeEventListener, + 'fetch': self.fetch, + 'JSON': self.JSON, + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), + 'log': console.log.bind(console), + // Properties + logLevel: 0, + // Methods + makeLogPrefix(...args) { + return this.sendToLogger && `[${args.join(' \u205D ')}]` || ''; + }, + uboLog(...args) { + if ( this.sendToLogger === undefined ) { return; } + if ( args === undefined || args[0] === '' ) { return; } + return this.sendToLogger('info', ...args); + + }, + uboErr(...args) { + if ( this.sendToLogger === undefined ) { return; } + if ( args === undefined || args[0] === '' ) { return; } + return this.sendToLogger('error', ...args); + }, + escapeRegexChars(s) { + return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + }, + initPattern(pattern, options = {}) { + if ( pattern === '' ) { + return { matchAll: true, expect: true }; + } + const expect = (options.canNegate !== true || pattern.startsWith('!') === false); + if ( expect === false ) { + pattern = pattern.slice(1); + } + const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern); + if ( match !== null ) { + return { + re: new this.RegExp( + match[1], + match[2] || options.flags + ), + expect, + }; + } + if ( options.flags !== undefined ) { + return { + re: new this.RegExp(this.escapeRegexChars(pattern), + options.flags + ), + expect, + }; + } + return { pattern, expect }; + }, + testPattern(details, haystack) { + if ( details.matchAll ) { return true; } + if ( details.re ) { + return this.RegExp_test(details.re, haystack) === details.expect; + } + return haystack.includes(details.pattern) === details.expect; + }, + patternToRegex(pattern, flags = undefined, verbatim = false) { + if ( pattern === '' ) { return /^/; } + const match = /^\/(.+)\/([gimsu]*)$/.exec(pattern); + if ( match === null ) { + const reStr = this.escapeRegexChars(pattern); + return new RegExp(verbatim ? `^${reStr}$` : reStr, flags); + } + try { + return new RegExp(match[1], match[2] || undefined); + } + catch { + } + return /^/; + }, + parseVarargs(varargs) { + const entries = varargs.reduce((out, v, i, a) => { + if ( i & 1 ) { return out; } + const rawValue = a[i+1]; + const value = /^\d+$/.test(rawValue) + ? parseInt(rawValue, 10) + : rawValue; + out.push([ a[i], value ]); + return out; + }, []); + return this.Object_fromEntries(entries); + }, + }; + safeSelf.safe = safe; + if ( scriptletGlobals.bcSecret === undefined ) { return safe; } + // This is executed only when the logger is opened + safe.logLevel = scriptletGlobals.logLevel || 1; + let lastLogType = ''; + let lastLogText = ''; + let lastLogTime = 0; + safe.toLogText = (type, ...args) => { + if ( args.length === 0 ) { return; } + const text = `[${document.location.hostname || document.location.href}]${args.join(' ')}`; + if ( text === lastLogText && type === lastLogType ) { + if ( (Date.now() - lastLogTime) < 5000 ) { return; } + } + lastLogType = type; + lastLogText = text; + lastLogTime = Date.now(); + return text; + }; + try { + const bc = new self.BroadcastChannel(scriptletGlobals.bcSecret); + let bcBuffer = []; + safe.sendToLogger = (type, ...args) => { + const text = safe.toLogText(type, ...args); + if ( text === undefined ) { return; } + if ( bcBuffer === undefined ) { + return bc.postMessage({ what: 'messageToLogger', type, text }); + } + bcBuffer.push({ type, text }); + }; + bc.onmessage = ev => { + const msg = ev.data; + switch ( msg ) { + case 'iamready!': + if ( bcBuffer === undefined ) { break; } + bcBuffer.forEach(({ type, text }) => + bc.postMessage({ what: 'messageToLogger', type, text }) + ); + bcBuffer = undefined; + break; + case 'setScriptletLogLevelToOne': + safe.logLevel = 1; + break; + case 'setScriptletLogLevelToTwo': + safe.logLevel = 2; + break; + } + }; + bc.postMessage('areyouready?'); + } catch { + safe.sendToLogger = (type, ...args) => { + const text = safe.toLogText(type, ...args); + if ( text === undefined ) { return; } + safe.log(`uBO ${text}`); + }; + } + return safe; +} +function generateContentFn(trusted, directive) { + const safe = safeSelf(); + const randomize = len => { + const chunks = []; + let textSize = 0; + do { + const s = safe.Math_random().toString(36).slice(2); + chunks.push(s); + textSize += s.length; + } + while ( textSize < len ); + return chunks.join(' ').slice(0, len); + }; + if ( directive === 'true' ) { + return randomize(10); + } + if ( directive === 'emptyObj' ) { + return '{}'; + } + if ( directive === 'emptyArr' ) { + return '[]'; + } + if ( directive === 'emptyStr' ) { + return ''; } - const onStateChange = ( ) => { - if ( intFromReadyState(document.readyState) < runAt ) { return; } - fn(); - safe.removeEventListener.apply(document, args); - }; - const safe = safeSelf(); - const args = [ 'readystatechange', onStateChange, { capture: true } ]; - safe.addEventListener.apply(document, args); + if ( directive.startsWith('length:') ) { + const match = /^length:(\d+)(?:-(\d+))?$/.exec(directive); + if ( match === null ) { return ''; } + const min = parseInt(match[1], 10); + const extent = safe.Math_max(parseInt(match[2], 10) || 0, min) - min; + const len = safe.Math_min(min + extent * safe.Math_random(), 500000); + return randomize(len | 0); + } + if ( directive.startsWith('war:') ) { + if ( scriptletGlobals.warOrigin === undefined ) { return ''; } + return new Promise(resolve => { + const warOrigin = scriptletGlobals.warOrigin; + const warName = directive.slice(4); + const fullpath = [ warOrigin, '/', warName ]; + const warSecret = scriptletGlobals.warSecret; + if ( warSecret !== undefined ) { + fullpath.push('?secret=', warSecret); + } + const warXHR = new safe.XMLHttpRequest(); + warXHR.responseType = 'text'; + warXHR.onloadend = ev => { + resolve(ev.target.responseText || ''); + }; + warXHR.open('GET', fullpath.join('')); + warXHR.send(); + }).catch(( ) => ''); + } + if ( directive.startsWith('join:') ) { + const parts = directive.slice(7) + .split(directive.slice(5, 7)) + .map(a => generateContentFn(trusted, a)); + return parts.some(a => a instanceof Promise) + ? Promise.all(parts).then(parts => parts.join('')) + : parts.join(''); + } + if ( trusted ) { + return directive; + } + return ''; } -function setConstantFn( +function preventXhrFn( trusted = false, - chain = '', - rawValue = '', - ...varargs + propsToMatch = '', + directive = '' ) { - if ( chain === '' ) { return; } + if ( typeof propsToMatch !== 'string' ) { return; } const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('set-constant', chain, rawValue); - const extraArgs = safe.parseVarargs(varargs); - function setConstant(chain, rawValue) { - const trappedProp = (( ) => { - const pos = chain.lastIndexOf('.'); - if ( pos === -1 ) { return chain; } - return chain.slice(pos+1); - })(); - const cloakFunc = fn => { - safe.Object_defineProperty(fn, 'name', { value: trappedProp }); - return new Proxy(fn, { - defineProperty(target, prop) { - if ( prop !== 'toString' ) { - return Reflect.defineProperty(...arguments); - } - return true; - }, - deleteProperty(target, prop) { - if ( prop !== 'toString' ) { - return Reflect.deleteProperty(...arguments); - } - return true; + const scriptletName = trusted ? 'trusted-prevent-xhr' : 'prevent-xhr'; + const logPrefix = safe.makeLogPrefix(scriptletName, propsToMatch, directive); + const xhrInstances = new WeakMap(); + const propNeedles = parsePropertiesToMatchFn(propsToMatch, 'url'); + const warOrigin = scriptletGlobals.warOrigin; + const safeDispatchEvent = (xhr, type) => { + try { + xhr.dispatchEvent(new Event(type)); + } catch { + } + }; + proxyApplyFn('XMLHttpRequest.prototype.open', function(context) { + const { thisArg, callArgs } = context; + xhrInstances.delete(thisArg); + const [ method, url, ...args ] = callArgs; + if ( warOrigin !== undefined && url.startsWith(warOrigin) ) { + return context.reflect(); + } + const haystack = { method, url }; + if ( propsToMatch === '' && directive === '' ) { + safe.uboLog(logPrefix, `Called: ${safe.JSON_stringify(haystack, null, 2)}`); + return context.reflect(); + } + if ( matchObjectPropertiesFn(propNeedles, haystack) ) { + const xhrDetails = Object.assign(haystack, { + xhr: thisArg, + defer: args.length === 0 || !!args[0], + directive, + headers: { + 'date': '', + 'content-type': '', + 'content-length': '', }, - get(target, prop) { - if ( prop === 'toString' ) { - return function() { - return `function ${trappedProp}() { [native code] }`; - }.bind(null); - } - return Reflect.get(...arguments); + url: haystack.url, + props: { + response: { value: '' }, + responseText: { value: '' }, + responseXML: { value: null }, }, }); - }; - if ( trappedProp === '' ) { return; } - const thisScript = document.currentScript; - let normalValue = validateConstantFn(trusted, rawValue, extraArgs); - if ( rawValue === 'noopFunc' || rawValue === 'trueFunc' || rawValue === 'falseFunc' ) { - normalValue = cloakFunc(normalValue); + xhrInstances.set(thisArg, xhrDetails); } - let aborted = false; - const mustAbort = function(v) { - if ( trusted ) { return false; } - if ( aborted ) { return true; } - aborted = - (v !== undefined && v !== null) && - (normalValue !== undefined && normalValue !== null) && - (typeof v !== typeof normalValue); - if ( aborted ) { - safe.uboLog(logPrefix, `Aborted because value set to ${v}`); - } - return aborted; - }; - // https://github.com/uBlockOrigin/uBlock-issues/issues/156 - // Support multiple trappers for the same property. - const trapProp = function(owner, prop, configurable, handler) { - if ( handler.init(configurable ? owner[prop] : normalValue) === false ) { return; } - const odesc = safe.Object_getOwnPropertyDescriptor(owner, prop); - let prevGetter, prevSetter; - if ( odesc instanceof safe.Object ) { - owner[prop] = normalValue; - if ( odesc.get instanceof Function ) { - prevGetter = odesc.get; - } - if ( odesc.set instanceof Function ) { - prevSetter = odesc.set; - } - } - try { - safe.Object_defineProperty(owner, prop, { - configurable, - get() { - if ( prevGetter !== undefined ) { - prevGetter(); - } - return handler.getter(); - }, - set(a) { - if ( prevSetter !== undefined ) { - prevSetter(a); - } - handler.setter(a); - } - }); - safe.uboLog(logPrefix, 'Trap installed'); - } catch(ex) { - safe.uboErr(logPrefix, ex); - } - }; - const trapChain = function(owner, chain) { - const pos = chain.indexOf('.'); - if ( pos === -1 ) { - trapProp(owner, chain, false, { - v: undefined, - init: function(v) { - if ( mustAbort(v) ) { return false; } - this.v = v; - return true; - }, - getter: function() { - if ( document.currentScript === thisScript ) { - return this.v; - } - safe.uboLog(logPrefix, 'Property read'); - return normalValue; - }, - setter: function(a) { - if ( mustAbort(a) === false ) { return; } - normalValue = a; - } + return context.reflect(); + }); + proxyApplyFn('XMLHttpRequest.prototype.send', function(context) { + const { thisArg } = context; + const xhrDetails = xhrInstances.get(thisArg); + if ( xhrDetails === undefined ) { + return context.reflect(); + } + xhrDetails.headers['date'] = (new Date()).toUTCString(); + let xhrText = ''; + switch ( thisArg.responseType ) { + case 'arraybuffer': + xhrDetails.props.response.value = new ArrayBuffer(0); + xhrDetails.headers['content-type'] = 'application/octet-stream'; + break; + case 'blob': + xhrDetails.props.response.value = new Blob([]); + xhrDetails.headers['content-type'] = 'application/octet-stream'; + break; + case 'document': { + const parser = new DOMParser(); + const doc = parser.parseFromString('', 'text/html'); + xhrDetails.props.response.value = doc; + xhrDetails.props.responseXML.value = doc; + xhrDetails.headers['content-type'] = 'text/html'; + break; + } + case 'json': + xhrDetails.props.response.value = {}; + xhrDetails.props.responseText.value = '{}'; + xhrDetails.headers['content-type'] = 'application/json'; + break; + default: { + if ( directive === '' ) { break; } + xhrText = generateContentFn(trusted, xhrDetails.directive); + if ( xhrText instanceof Promise ) { + xhrText = xhrText.then(text => { + xhrDetails.props.response.value = text; + xhrDetails.props.responseText.value = text; }); - return; - } - const prop = chain.slice(0, pos); - const v = owner[prop]; - chain = chain.slice(pos + 1); - if ( v instanceof safe.Object || typeof v === 'object' && v !== null ) { - trapChain(v, chain); - return; + } else { + xhrDetails.props.response.value = xhrText; + xhrDetails.props.responseText.value = xhrText; } - trapProp(owner, prop, true, { - v: undefined, - init: function(v) { - this.v = v; - return true; - }, - getter: function() { - return this.v; - }, - setter: function(a) { - this.v = a; - if ( a instanceof safe.Object ) { - trapChain(a, chain); - } - } + xhrDetails.headers['content-type'] = 'text/plain'; + break; + } + } + if ( xhrDetails.defer === false ) { + xhrDetails.headers['content-length'] = `${xhrDetails.props.response.value}`.length; + Object.defineProperties(xhrDetails.xhr, { + readyState: { value: 4 }, + responseURL: { value: xhrDetails.url }, + status: { value: 200 }, + statusText: { value: 'OK' }, }); - }; - trapChain(window, chain); - } - runAt(( ) => { - setConstant(chain, rawValue); - }, extraArgs.runAt); + Object.defineProperties(xhrDetails.xhr, xhrDetails.props); + return; + } + Promise.resolve(xhrText).then(( ) => xhrDetails).then(details => { + Object.defineProperties(details.xhr, { + readyState: { value: 1, configurable: true }, + responseURL: { value: xhrDetails.url }, + }); + safeDispatchEvent(details.xhr, 'readystatechange'); + return details; + }).then(details => { + xhrDetails.headers['content-length'] = `${details.props.response.value}`.length; + Object.defineProperties(details.xhr, { + readyState: { value: 2, configurable: true }, + status: { value: 200 }, + statusText: { value: 'OK' }, + }); + safeDispatchEvent(details.xhr, 'readystatechange'); + return details; + }).then(details => { + Object.defineProperties(details.xhr, { + readyState: { value: 3, configurable: true }, + }); + Object.defineProperties(details.xhr, details.props); + safeDispatchEvent(details.xhr, 'readystatechange'); + return details; + }).then(details => { + Object.defineProperties(details.xhr, { + readyState: { value: 4 }, + }); + safeDispatchEvent(details.xhr, 'readystatechange'); + safeDispatchEvent(details.xhr, 'load'); + safeDispatchEvent(details.xhr, 'loadend'); + safe.uboLog(logPrefix, `Prevented with response:\n${details.xhr.response}`); + }); + }); + proxyApplyFn('XMLHttpRequest.prototype.getResponseHeader', function(context) { + const { thisArg } = context; + const xhrDetails = xhrInstances.get(thisArg); + if ( xhrDetails === undefined || thisArg.readyState < thisArg.HEADERS_RECEIVED ) { + return context.reflect(); + } + const headerName = `${context.callArgs[0]}`; + const value = xhrDetails.headers[headerName.toLowerCase()]; + if ( value !== undefined && value !== '' ) { return value; } + return null; + }); + proxyApplyFn('XMLHttpRequest.prototype.getAllResponseHeaders', function(context) { + const { thisArg } = context; + const xhrDetails = xhrInstances.get(thisArg); + if ( xhrDetails === undefined || thisArg.readyState < thisArg.HEADERS_RECEIVED ) { + return context.reflect(); + } + const out = []; + for ( const [ name, value ] of Object.entries(xhrDetails.headers) ) { + if ( !value ) { continue; } + out.push(`${name}: ${value}`); + } + if ( out.length !== 0 ) { out.push(''); } + return out.join('\r\n'); + }); } -function trustedSetConstant( - ...args -) { - setConstantFn(true, ...args); +function preventXhr(...args) { + preventXhrFn(false, ...args); }; -trustedSetConstant(...args); +preventXhr(...args); }, }; -scriptlets['trusted-replace-argument.js'] = { +scriptlets['trusted-prevent-xhr.js'] = { aliases: [], -requiresTrust: true, +requiresTrust: false, func: function (scriptletGlobals = {}, ...args) { -function validateConstantFn(trusted, raw, extraArgs = {}) { - const safe = safeSelf(); - let value; - if ( raw === 'undefined' ) { - value = undefined; - } else if ( raw === 'false' ) { - value = false; - } else if ( raw === 'true' ) { - value = true; - } else if ( raw === 'null' ) { - value = null; - } else if ( raw === "''" || raw === '' ) { - value = ''; - } else if ( raw === '[]' || raw === 'emptyArr' ) { - value = []; - } else if ( raw === '{}' || raw === 'emptyObj' ) { - value = {}; - } else if ( raw === 'noopFunc' ) { - value = function(){}; - } else if ( raw === 'trueFunc' ) { - value = function(){ return true; }; - } else if ( raw === 'falseFunc' ) { - value = function(){ return false; }; - } else if ( raw === 'throwFunc' ) { - value = function(){ throw ''; }; - } else if ( /^-?\d+$/.test(raw) ) { - value = parseInt(raw); - if ( isNaN(raw) ) { return; } - if ( Math.abs(raw) > 0x7FFF ) { return; } - } else if ( trusted ) { - if ( raw.startsWith('json:') ) { - try { value = safe.JSON_parse(raw.slice(5)); } catch { return; } - } else if ( raw.startsWith('{') && raw.endsWith('}') ) { - try { value = safe.JSON_parse(raw).value; } catch { return; } +function proxyApplyFn( + target = '', + handler = '', + options = {} +) { + let context = globalThis; + let prop = target; + 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); + } + const fn = context[prop]; + if ( typeof fn !== 'function' ) { return; } + if ( proxyApplyFn.CtorContext === undefined ) { + proxyApplyFn.ctorContexts = []; + proxyApplyFn.CtorContext = class { + constructor(...args) { + this.init(...args); + } + init(callFn, callArgs) { + this.callFn = callFn; + this.callArgs = callArgs; + return this; + } + reflect() { + const r = Reflect.construct(this.callFn, this.callArgs); + this.callFn = this.callArgs = this.private = undefined; + proxyApplyFn.ctorContexts.push(this); + return r; + } + static factory(...args) { + return proxyApplyFn.ctorContexts.length !== 0 + ? proxyApplyFn.ctorContexts.pop().init(...args) + : new proxyApplyFn.CtorContext(...args); + } + }; + proxyApplyFn.applyContexts = []; + proxyApplyFn.ApplyContext = class { + constructor(...args) { + this.init(...args); + } + init(callFn, thisArg, callArgs) { + this.callFn = callFn; + this.thisArg = thisArg; + this.callArgs = callArgs; + return this; + } + reflect() { + const r = Reflect.apply(this.callFn, this.thisArg, this.callArgs); + this.callFn = this.thisArg = this.callArgs = this.private = undefined; + proxyApplyFn.applyContexts.push(this); + return r; + } + static factory(...args) { + return proxyApplyFn.applyContexts.length !== 0 + ? proxyApplyFn.applyContexts.pop().init(...args) + : new proxyApplyFn.ApplyContext(...args); + } + }; + proxyApplyFn.isCtor = new Map(); + proxyApplyFn.proxies = new WeakMap(); + if ( (options.skipToString || proxyApplyFn.skipToString) !== true ) { + proxyApplyFn.nativeToString = Function.prototype.toString; + const proxiedToString = new Proxy(Function.prototype.toString, { + apply(target, thisArg) { + let proxied = thisArg; + for(;;) { + const fn = proxyApplyFn.proxies.get(proxied); + if ( fn === undefined ) { break; } + proxied = fn; + } + return proxyApplyFn.nativeToString.call(proxied); + } + }); + proxyApplyFn.proxies.set(proxiedToString, proxyApplyFn.nativeToString); + Function.prototype.toString = proxiedToString; } - } else { - return; } - if ( extraArgs.as !== undefined ) { - if ( extraArgs.as === 'function' ) { - return ( ) => value; - } else if ( extraArgs.as === 'callback' ) { - return ( ) => (( ) => value); - } else if ( extraArgs.as === 'resolved' ) { - return Promise.resolve(value); - } else if ( extraArgs.as === 'rejected' ) { - return Promise.reject(value); + if ( proxyApplyFn.isCtor.has(target) === false ) { + proxyApplyFn.isCtor.set(target, fn.prototype?.constructor === fn); + } + const proxyDetails = { + apply(target, thisArg, args) { + return handler(proxyApplyFn.ApplyContext.factory(target, thisArg, args)); + } + }; + if ( proxyApplyFn.isCtor.get(target) ) { + proxyDetails.construct = function(target, args) { + return handler(proxyApplyFn.CtorContext.factory(target, args)); + }; + } + const proxiedTarget = new Proxy(fn, proxyDetails); + proxyApplyFn.proxies.set(proxiedTarget, fn); + context[prop] = proxiedTarget; +} +function parsePropertiesToMatchFn(propsToMatch, implicit = '') { + const safe = safeSelf(); + const needles = new Map(); + if ( propsToMatch === undefined || propsToMatch === '' ) { return needles; } + const options = { canNegate: true }; + for ( const needle of safe.String_split.call(propsToMatch, /\s+/) ) { + let [ prop, pattern ] = safe.String_split.call(needle, ':'); + if ( prop === '' ) { continue; } + if ( pattern !== undefined && /[^$\w -]/.test(prop) ) { + prop = `${prop}:${pattern}`; + pattern = undefined; + } + if ( pattern !== undefined ) { + needles.set(prop, safe.initPattern(pattern, options)); + } else if ( implicit !== '' ) { + needles.set(implicit, safe.initPattern(prop, options)); } } - return value; + return needles; +} +function matchObjectPropertiesFn(propNeedles, ...objs) { + const safe = safeSelf(); + const matched = []; + for ( const obj of objs ) { + if ( obj instanceof Object === false ) { continue; } + for ( const [ prop, details ] of propNeedles ) { + let value = obj[prop]; + if ( value === undefined ) { continue; } + if ( typeof value !== 'string' ) { + try { value = safe.JSON_stringify(value); } + catch { } + if ( typeof value !== 'string' ) { continue; } + } + if ( safe.testPattern(details, value) === false ) { return; } + matched.push(`${prop}: ${value}`); + } + } + return matched; } function safeSelf() { if ( safeSelf.safe ) { @@ -34455,8 +34640,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -34469,7 +34653,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -34480,10 +34664,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -34536,7 +34718,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -34624,292 +34806,291 @@ function safeSelf() { } return safe; } -function proxyApplyFn( - target = '', - handler = '', - options = {} -) { - let context = globalThis; - let prop = target; - 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); - } - const fn = context[prop]; - if ( typeof fn !== 'function' ) { return; } - if ( proxyApplyFn.CtorContext === undefined ) { - proxyApplyFn.ctorContexts = []; - proxyApplyFn.CtorContext = class { - constructor(...args) { - this.init(...args); - } - init(callFn, callArgs) { - this.callFn = callFn; - this.callArgs = callArgs; - return this; - } - reflect() { - const r = Reflect.construct(this.callFn, this.callArgs); - this.callFn = this.callArgs = this.private = undefined; - proxyApplyFn.ctorContexts.push(this); - return r; - } - static factory(...args) { - return proxyApplyFn.ctorContexts.length !== 0 - ? proxyApplyFn.ctorContexts.pop().init(...args) - : new proxyApplyFn.CtorContext(...args); - } - }; - proxyApplyFn.applyContexts = []; - proxyApplyFn.ApplyContext = class { - constructor(...args) { - this.init(...args); - } - init(callFn, thisArg, callArgs) { - this.callFn = callFn; - this.thisArg = thisArg; - this.callArgs = callArgs; - return this; - } - reflect() { - const r = Reflect.apply(this.callFn, this.thisArg, this.callArgs); - this.callFn = this.thisArg = this.callArgs = this.private = undefined; - proxyApplyFn.applyContexts.push(this); - return r; - } - static factory(...args) { - return proxyApplyFn.applyContexts.length !== 0 - ? proxyApplyFn.applyContexts.pop().init(...args) - : new proxyApplyFn.ApplyContext(...args); - } - }; - proxyApplyFn.isCtor = new Map(); - proxyApplyFn.proxies = new WeakMap(); - if ( (options.skipToString || proxyApplyFn.skipToString) !== true ) { - proxyApplyFn.nativeToString = Function.prototype.toString; - const proxiedToString = new Proxy(Function.prototype.toString, { - apply(target, thisArg) { - let proxied = thisArg; - for(;;) { - const fn = proxyApplyFn.proxies.get(proxied); - if ( fn === undefined ) { break; } - proxied = fn; - } - return proxyApplyFn.nativeToString.call(proxied); - } - }); - proxyApplyFn.proxies.set(proxiedToString, proxyApplyFn.nativeToString); - Function.prototype.toString = proxiedToString; - } - } - if ( proxyApplyFn.isCtor.has(target) === false ) { - proxyApplyFn.isCtor.set(target, fn.prototype?.constructor === fn); - } - const proxyDetails = { - apply(target, thisArg, args) { - return handler(proxyApplyFn.ApplyContext.factory(target, thisArg, args)); +function generateContentFn(trusted, directive) { + const safe = safeSelf(); + const randomize = len => { + const chunks = []; + let textSize = 0; + do { + const s = safe.Math_random().toString(36).slice(2); + chunks.push(s); + textSize += s.length; } + while ( textSize < len ); + return chunks.join(' ').slice(0, len); }; - if ( proxyApplyFn.isCtor.get(target) ) { - proxyDetails.construct = function(target, args) { - return handler(proxyApplyFn.CtorContext.factory(target, args)); - }; - } - const proxiedTarget = new Proxy(fn, proxyDetails); - proxyApplyFn.proxies.set(proxiedTarget, fn); - context[prop] = proxiedTarget; -} -class ArglistParser { - constructor(separatorChar = ',', mustQuote = false) { - this.separatorChar = this.actualSeparatorChar = separatorChar; - this.separatorCode = this.actualSeparatorCode = separatorChar.charCodeAt(0); - this.mustQuote = mustQuote; - this.quoteBeg = 0; this.quoteEnd = 0; - this.argBeg = 0; this.argEnd = 0; - this.separatorBeg = 0; this.separatorEnd = 0; - this.transform = false; - this.failed = false; - this.reWhitespaceStart = /^\s+/; - this.reWhitespaceEnd = /(?:^|\S)(\s+)$/; - this.reOddTrailingEscape = /(?:^|[^\\])(?:\\\\)*\\$/; - this.reTrailingEscapeChars = /\\+$/; + if ( directive === 'true' ) { + return randomize(10); } - nextArg(pattern, beg = 0) { - const len = pattern.length; - this.quoteBeg = beg + this.leftWhitespaceCount(pattern.slice(beg)); - this.failed = false; - const qc = pattern.charCodeAt(this.quoteBeg); - if ( qc === 0x22 /* " */ || qc === 0x27 /* ' */ || qc === 0x60 /* ` */ ) { - this.indexOfNextArgSeparator(pattern, qc); - if ( this.argEnd !== len ) { - this.quoteEnd = this.argEnd + 1; - this.separatorBeg = this.separatorEnd = this.quoteEnd; - this.separatorEnd += this.leftWhitespaceCount(pattern.slice(this.quoteEnd)); - if ( this.separatorEnd === len ) { return this; } - if ( pattern.charCodeAt(this.separatorEnd) === this.separatorCode ) { - this.separatorEnd += 1; - return this; - } - } - } - this.indexOfNextArgSeparator(pattern, this.separatorCode); - this.separatorBeg = this.separatorEnd = this.argEnd; - if ( this.separatorBeg < len ) { - this.separatorEnd += 1; - } - this.argEnd -= this.rightWhitespaceCount(pattern.slice(0, this.separatorBeg)); - this.quoteEnd = this.argEnd; - if ( this.mustQuote ) { - this.failed = true; - } - return this; + if ( directive === 'emptyObj' ) { + return '{}'; } - normalizeArg(s, char = '') { - if ( char === '' ) { char = this.actualSeparatorChar; } - let out = ''; - let pos = 0; - while ( (pos = s.lastIndexOf(char)) !== -1 ) { - out = s.slice(pos) + out; - s = s.slice(0, pos); - const match = this.reTrailingEscapeChars.exec(s); - if ( match === null ) { continue; } - const tail = (match[0].length & 1) !== 0 - ? match[0].slice(0, -1) - : match[0]; - out = tail + out; - s = s.slice(0, -match[0].length); - } - if ( out === '' ) { return s; } - return s + out; + if ( directive === 'emptyArr' ) { + return '[]'; } - leftWhitespaceCount(s) { - const match = this.reWhitespaceStart.exec(s); - return match === null ? 0 : match[0].length; + if ( directive === 'emptyStr' ) { + return ''; } - rightWhitespaceCount(s) { - const match = this.reWhitespaceEnd.exec(s); - return match === null ? 0 : match[1].length; + if ( directive.startsWith('length:') ) { + const match = /^length:(\d+)(?:-(\d+))?$/.exec(directive); + if ( match === null ) { return ''; } + const min = parseInt(match[1], 10); + const extent = safe.Math_max(parseInt(match[2], 10) || 0, min) - min; + const len = safe.Math_min(min + extent * safe.Math_random(), 500000); + return randomize(len | 0); } - indexOfNextArgSeparator(pattern, separatorCode) { - this.argBeg = this.argEnd = separatorCode !== this.separatorCode - ? this.quoteBeg + 1 - : this.quoteBeg; - this.transform = false; - if ( separatorCode !== this.actualSeparatorCode ) { - this.actualSeparatorCode = separatorCode; - this.actualSeparatorChar = String.fromCharCode(separatorCode); - } - while ( this.argEnd < pattern.length ) { - const pos = pattern.indexOf(this.actualSeparatorChar, this.argEnd); - if ( pos === -1 ) { - return (this.argEnd = pattern.length); - } - if ( this.reOddTrailingEscape.test(pattern.slice(0, pos)) === false ) { - return (this.argEnd = pos); + if ( directive.startsWith('war:') ) { + if ( scriptletGlobals.warOrigin === undefined ) { return ''; } + return new Promise(resolve => { + const warOrigin = scriptletGlobals.warOrigin; + const warName = directive.slice(4); + const fullpath = [ warOrigin, '/', warName ]; + const warSecret = scriptletGlobals.warSecret; + if ( warSecret !== undefined ) { + fullpath.push('?secret=', warSecret); } - this.transform = true; - this.argEnd = pos + 1; - } - } -} -function parseReplaceFn(s) { - if ( s.charCodeAt(0) !== 0x2F /* / */ ) { return; } - const parser = new ArglistParser('/'); - parser.nextArg(s, 1); - let pattern = s.slice(parser.argBeg, parser.argEnd); - if ( parser.transform ) { - pattern = parser.normalizeArg(pattern); + const warXHR = new safe.XMLHttpRequest(); + warXHR.responseType = 'text'; + warXHR.onloadend = ev => { + resolve(ev.target.responseText || ''); + }; + warXHR.open('GET', fullpath.join('')); + warXHR.send(); + }).catch(( ) => ''); } - if ( pattern === '' ) { return; } - parser.nextArg(s, parser.separatorEnd); - let replacement = s.slice(parser.argBeg, parser.argEnd); - if ( parser.separatorEnd === parser.separatorBeg ) { return; } - if ( parser.transform ) { - replacement = parser.normalizeArg(replacement); + if ( directive.startsWith('join:') ) { + const parts = directive.slice(7) + .split(directive.slice(5, 7)) + .map(a => generateContentFn(trusted, a)); + return parts.some(a => a instanceof Promise) + ? Promise.all(parts).then(parts => parts.join('')) + : parts.join(''); } - const flags = s.slice(parser.separatorEnd); - try { - return { re: new RegExp(pattern, flags), replacement }; - } catch { + if ( trusted ) { + return directive; } + return ''; } -function trustedReplaceArgument( - propChain = '', - argposRaw = '', - argraw = '', - ...varargs +function preventXhrFn( + trusted = false, + propsToMatch = '', + directive = '' ) { - if ( propChain === '' ) { return; } + if ( typeof propsToMatch !== 'string' ) { return; } const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('trusted-replace-argument', propChain, argposRaw, argraw); - const argoffset = parseInt(argposRaw, 10) || 0; - const extraArgs = safe.parseVarargs(varargs); - let replacer; - if ( argraw.startsWith('repl:/') ) { - const parsed = parseReplaceFn(argraw.slice(5)); - if ( parsed === undefined ) { return; } - replacer = arg => `${arg}`.replace(replacer.re, replacer.replacement); - Object.assign(replacer, parsed); - } else if ( argraw.startsWith('add:') ) { - const delta = parseFloat(argraw.slice(4)); - if ( isNaN(delta) ) { return; } - replacer = arg => Number(arg) + delta; - } else { - const value = validateConstantFn(true, argraw, extraArgs); - replacer = ( ) => value; - } - const reCondition = extraArgs.condition - ? safe.patternToRegex(`${extraArgs.condition}`) - : /^/; - const getArg = context => { - if ( argposRaw === 'this' ) { return context.thisArg; } - const { callArgs } = context; - const argpos = argoffset >= 0 ? argoffset : callArgs.length - argoffset; - if ( argpos < 0 || argpos >= callArgs.length ) { return; } - context.private = { argpos }; - return callArgs[argpos]; - }; - const setArg = (context, value) => { - if ( argposRaw === 'this' ) { - if ( value !== context.thisArg ) { - context.thisArg = value; - } - } else if ( context.private ) { - context.callArgs[context.private.argpos] = value; + const scriptletName = trusted ? 'trusted-prevent-xhr' : 'prevent-xhr'; + const logPrefix = safe.makeLogPrefix(scriptletName, propsToMatch, directive); + const xhrInstances = new WeakMap(); + const propNeedles = parsePropertiesToMatchFn(propsToMatch, 'url'); + const warOrigin = scriptletGlobals.warOrigin; + const safeDispatchEvent = (xhr, type) => { + try { + xhr.dispatchEvent(new Event(type)); + } catch { } }; - proxyApplyFn(propChain, function(context) { - if ( argposRaw === '' ) { - safe.uboLog(logPrefix, `Arguments:\n${context.callArgs.join('\n')}`); + proxyApplyFn('XMLHttpRequest.prototype.open', function(context) { + const { thisArg, callArgs } = context; + xhrInstances.delete(thisArg); + const [ method, url, ...args ] = callArgs; + if ( warOrigin !== undefined && url.startsWith(warOrigin) ) { return context.reflect(); } - const argBefore = getArg(context); - if ( extraArgs.condition !== undefined ) { - if ( safe.RegExp_test.call(reCondition, argBefore) === false ) { - return context.reflect(); - } + const haystack = { method, url }; + if ( propsToMatch === '' && directive === '' ) { + safe.uboLog(logPrefix, `Called: ${safe.JSON_stringify(haystack, null, 2)}`); + return context.reflect(); } - const argAfter = replacer(argBefore); - if ( argAfter !== argBefore ) { - setArg(context, argAfter); - safe.uboLog(logPrefix, `Replaced argument:\nBefore: ${JSON.stringify(argBefore)}\nAfter: ${argAfter}`); + if ( matchObjectPropertiesFn(propNeedles, haystack) ) { + const xhrDetails = Object.assign(haystack, { + xhr: thisArg, + defer: args.length === 0 || !!args[0], + directive, + headers: { + 'date': '', + 'content-type': '', + 'content-length': '', + }, + url: haystack.url, + props: { + response: { value: '' }, + responseText: { value: '' }, + responseXML: { value: null }, + }, + }); + xhrInstances.set(thisArg, xhrDetails); } return context.reflect(); }); + proxyApplyFn('XMLHttpRequest.prototype.send', function(context) { + const { thisArg } = context; + const xhrDetails = xhrInstances.get(thisArg); + if ( xhrDetails === undefined ) { + return context.reflect(); + } + xhrDetails.headers['date'] = (new Date()).toUTCString(); + let xhrText = ''; + switch ( thisArg.responseType ) { + case 'arraybuffer': + xhrDetails.props.response.value = new ArrayBuffer(0); + xhrDetails.headers['content-type'] = 'application/octet-stream'; + break; + case 'blob': + xhrDetails.props.response.value = new Blob([]); + xhrDetails.headers['content-type'] = 'application/octet-stream'; + break; + case 'document': { + const parser = new DOMParser(); + const doc = parser.parseFromString('', 'text/html'); + xhrDetails.props.response.value = doc; + xhrDetails.props.responseXML.value = doc; + xhrDetails.headers['content-type'] = 'text/html'; + break; + } + case 'json': + xhrDetails.props.response.value = {}; + xhrDetails.props.responseText.value = '{}'; + xhrDetails.headers['content-type'] = 'application/json'; + break; + default: { + if ( directive === '' ) { break; } + xhrText = generateContentFn(trusted, xhrDetails.directive); + if ( xhrText instanceof Promise ) { + xhrText = xhrText.then(text => { + xhrDetails.props.response.value = text; + xhrDetails.props.responseText.value = text; + }); + } else { + xhrDetails.props.response.value = xhrText; + xhrDetails.props.responseText.value = xhrText; + } + xhrDetails.headers['content-type'] = 'text/plain'; + break; + } + } + if ( xhrDetails.defer === false ) { + xhrDetails.headers['content-length'] = `${xhrDetails.props.response.value}`.length; + Object.defineProperties(xhrDetails.xhr, { + readyState: { value: 4 }, + responseURL: { value: xhrDetails.url }, + status: { value: 200 }, + statusText: { value: 'OK' }, + }); + Object.defineProperties(xhrDetails.xhr, xhrDetails.props); + return; + } + Promise.resolve(xhrText).then(( ) => xhrDetails).then(details => { + Object.defineProperties(details.xhr, { + readyState: { value: 1, configurable: true }, + responseURL: { value: xhrDetails.url }, + }); + safeDispatchEvent(details.xhr, 'readystatechange'); + return details; + }).then(details => { + xhrDetails.headers['content-length'] = `${details.props.response.value}`.length; + Object.defineProperties(details.xhr, { + readyState: { value: 2, configurable: true }, + status: { value: 200 }, + statusText: { value: 'OK' }, + }); + safeDispatchEvent(details.xhr, 'readystatechange'); + return details; + }).then(details => { + Object.defineProperties(details.xhr, { + readyState: { value: 3, configurable: true }, + }); + Object.defineProperties(details.xhr, details.props); + safeDispatchEvent(details.xhr, 'readystatechange'); + return details; + }).then(details => { + Object.defineProperties(details.xhr, { + readyState: { value: 4 }, + }); + safeDispatchEvent(details.xhr, 'readystatechange'); + safeDispatchEvent(details.xhr, 'load'); + safeDispatchEvent(details.xhr, 'loadend'); + safe.uboLog(logPrefix, `Prevented with response:\n${details.xhr.response}`); + }); + }); + proxyApplyFn('XMLHttpRequest.prototype.getResponseHeader', function(context) { + const { thisArg } = context; + const xhrDetails = xhrInstances.get(thisArg); + if ( xhrDetails === undefined || thisArg.readyState < thisArg.HEADERS_RECEIVED ) { + return context.reflect(); + } + const headerName = `${context.callArgs[0]}`; + const value = xhrDetails.headers[headerName.toLowerCase()]; + if ( value !== undefined && value !== '' ) { return value; } + return null; + }); + proxyApplyFn('XMLHttpRequest.prototype.getAllResponseHeaders', function(context) { + const { thisArg } = context; + const xhrDetails = xhrInstances.get(thisArg); + if ( xhrDetails === undefined || thisArg.readyState < thisArg.HEADERS_RECEIVED ) { + return context.reflect(); + } + const out = []; + for ( const [ name, value ] of Object.entries(xhrDetails.headers) ) { + if ( !value ) { continue; } + out.push(`${name}: ${value}`); + } + if ( out.length !== 0 ) { out.push(''); } + return out.join('\r\n'); + }); +} +function trustedPreventXhr(...args) { + preventXhrFn(true, ...args); }; -trustedReplaceArgument(...args); +trustedPreventXhr(...args); }, }; -scriptlets['spoof-css.js'] = { +scriptlets['mpegdash-prune.js'] = { aliases: [], requiresTrust: false, func: function (scriptletGlobals = {}, ...args) { +function proxyToStringFn(proxiedFn, nativeFn) { + if ( proxyToStringFn.proxies === undefined ) { + proxyToStringFn.proxies = new WeakMap(); + proxyToStringFn.nativeToString = Function.prototype.toString; + const proxiedToString = new Proxy(Function.prototype.toString, { + apply(target, thisArg) { + let proxied = thisArg; + for(;;) { + const fn = proxyToStringFn.proxies.get(proxied); + if ( fn === undefined ) { break; } + proxied = fn; + } + return proxyToStringFn.nativeToString.call(proxied); + } + }); + proxyToStringFn.proxies.set(proxiedToString, proxyToStringFn.nativeToString); + Function.prototype.toString = proxiedToString; + } + proxyToStringFn.proxies.set(proxiedFn, nativeFn); +} +function parsePropertiesToMatchFn(propsToMatch, implicit = '') { + const safe = safeSelf(); + const needles = new Map(); + if ( propsToMatch === undefined || propsToMatch === '' ) { return needles; } + const options = { canNegate: true }; + for ( const needle of safe.String_split.call(propsToMatch, /\s+/) ) { + let [ prop, pattern ] = safe.String_split.call(needle, ':'); + if ( prop === '' ) { continue; } + if ( pattern !== undefined && /[^$\w -]/.test(prop) ) { + prop = `${prop}:${pattern}`; + pattern = undefined; + } + if ( pattern !== undefined ) { + needles.set(prop, safe.initPattern(pattern, options)); + } else if ( implicit !== '' ) { + needles.set(implicit, safe.initPattern(prop, options)); + } + } + return needles; +} function safeSelf() { if ( safeSelf.safe ) { return safeSelf.safe; @@ -34918,8 +35099,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -34932,7 +35112,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -34943,10 +35123,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -34999,7 +35177,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -35087,124 +35265,212 @@ function safeSelf() { } return safe; } -function spoofCSS( - selector, - ...args +function matchObjectPropertiesFn(propNeedles, ...objs) { + const safe = safeSelf(); + const matched = []; + for ( const obj of objs ) { + if ( obj instanceof Object === false ) { continue; } + for ( const [ prop, details ] of propNeedles ) { + let value = obj[prop]; + if ( value === undefined ) { continue; } + if ( typeof value !== 'string' ) { + try { value = safe.JSON_stringify(value); } + catch { } + if ( typeof value !== 'string' ) { continue; } + } + if ( safe.testPattern(details, value) === false ) { return; } + matched.push(`${prop}: ${value}`); + } + } + return matched; +} +function modifyXhrResponseFn( + propsToMatch = '', + modifierFn = '' +) { + if ( typeof propsToMatch !== 'string' ) { return; } + const safe = safeSelf(); + if ( modifyXhrResponseFn.xhrInstances === undefined ) { + modifyXhrResponseFn.xhrInstances = new WeakMap(); + } + const propNeedles = parsePropertiesToMatchFn(propsToMatch, 'url'); + const NativeXMLHttpRequest = self.XMLHttpRequest; + const TrappedXMLHttpRequest = class XMLHttpRequest extends NativeXMLHttpRequest { + open(method, url, ...args) { + const haystack = { method, url }; + if ( propsToMatch === '' ) { + safe.uboLog(`modifyXhrResponseFn() / Called: ${safe.JSON_stringify(haystack, null, 2)}`); + } else if ( matchObjectPropertiesFn(propNeedles, haystack) ) { + modifyXhrResponseFn.xhrInstances.set(this, modifierFn); + } + return super.open(method, url, ...args); + } + get response() { + const modifierFn = modifyXhrResponseFn.xhrInstances.get(this); + return modifierFn + ? modifierFn(this, super.response) + : super.response; + } + get responseText() { + const modifierFn = modifyXhrResponseFn.xhrInstances.get(this); + return modifierFn + ? modifierFn(this, super.responseText) + : super.responseText; + } + get responseXML() { + const modifierFn = modifyXhrResponseFn.xhrInstances.get(this); + return modifierFn + ? modifierFn(this, super.responseXML) + : super.responseXML; + } + }; + proxyToStringFn(TrappedXMLHttpRequest.prototype.open, NativeXMLHttpRequest.prototype.open); + proxyToStringFn(TrappedXMLHttpRequest, NativeXMLHttpRequest); + self.XMLHttpRequest = TrappedXMLHttpRequest; +} +function mpegdashPrune( + selector = '', + propsToMatch = '' ) { if ( typeof selector !== 'string' ) { return; } if ( selector === '' ) { return; } - const toCamelCase = s => s.replace(/-[a-z]/g, s => s.charAt(1).toUpperCase()); - const propToValueMap = new Map(); - const privatePropToValueMap = new Map(); - for ( let i = 0; i < args.length; i += 2 ) { - const prop = toCamelCase(args[i+0]); - if ( prop === '' ) { break; } - const value = args[i+1]; - if ( typeof value !== 'string' ) { break; } - if ( prop.charCodeAt(0) === 0x5F /* _ */ ) { - privatePropToValueMap.set(prop, value); - } else { - propToValueMap.set(prop, value); - } - } const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('spoof-css', selector, ...args); - const instanceProperties = [ 'cssText', 'length', 'parentRule' ]; - const spoofStyle = (prop, real) => { - const normalProp = toCamelCase(prop); - const shouldSpoof = propToValueMap.has(normalProp); - const value = shouldSpoof ? propToValueMap.get(normalProp) : real; - if ( shouldSpoof ) { - safe.uboLog(logPrefix, `Spoofing ${prop} to ${value}`); + const logPrefix = safe.makeLogPrefix('mpegdash-prune', selector, propsToMatch); + const queryAll = (xmlDoc, selector) => { + if ( selector.startsWith('xpath:') === false ) { + return Array.from(xmlDoc.querySelectorAll(selector)); } - return value; + const xpr = xmlDoc.evaluate( + selector.slice(6), + xmlDoc, + null, + XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, + null + ); + const out = []; + for ( let i = 0; i < xpr.snapshotLength; i++ ) { + const node = xpr.snapshotItem(i); + out.push(node); + } + return out; }; - const cloackFunc = (fn, thisArg, name) => { - const trap = fn.bind(thisArg); - Object.defineProperty(trap, 'name', { value: name }); - Object.defineProperty(trap, 'toString', { - value: ( ) => `function ${name}() { [native code] }` - }); - return trap; + const rePTparse = /^PT(\d+D)?(\d+H)?(\d+M)?([\d.]+S)?$/; + const secondsPerDay = 24 * 60 * 60; + const secondsPerHour = 60 * 60; + const secondsPerMinute = 60; + const secondsFromPT = pt => { + const match = rePTparse.exec(pt); + if ( match === null ) { return; } + let seconds = 0; + if ( match[1] ) { + const d = parseFloat(match[1].slice(0, -1)); + if ( isNaN(d) ) { return; } + seconds += d * secondsPerDay; + } + if ( match[2] ) { + const h = parseFloat(match[2].slice(0, -1)); + if ( isNaN(h) ) { return; } + seconds += h * secondsPerHour; + } + if ( match[3] ) { + const m = parseFloat(match[3].slice(0, -1)); + if ( isNaN(m) ) { return; } + seconds += m * secondsPerMinute; + } + if ( match[4] ) { + const s = parseFloat(match[4].slice(0, -1)); + if ( isNaN(s) ) { return; } + seconds += s; + } + return seconds; + }; + const ptFromSeconds = seconds => { + const parts = [ 'PT' ]; + const d = Math.floor(seconds / secondsPerDay); + if ( d ) { + parts.push(`${d}D`); + seconds -= d * secondsPerDay; + } + const h = Math.floor(seconds / secondsPerHour); + if ( h ) { + parts.push(`${h}H`); + seconds -= h * secondsPerHour; + } + const m = Math.floor(seconds / secondsPerMinute); + if ( m ) { + parts.push(`${m}M`); + seconds -= m * secondsPerMinute; + } + parts.push(`${seconds}S`); + return parts.join(''); }; - self.getComputedStyle = new Proxy(self.getComputedStyle, { - apply: function(target, thisArg, args) { - // eslint-disable-next-line no-debugger - if ( privatePropToValueMap.has('_debug') ) { debugger; } - const style = Reflect.apply(target, thisArg, args); - const targetElements = new WeakSet(document.querySelectorAll(selector)); - if ( targetElements.has(args[0]) === false ) { return style; } - const proxiedStyle = new Proxy(style, { - get(target, prop) { - if ( typeof target[prop] === 'function' ) { - if ( prop === 'getPropertyValue' ) { - return cloackFunc(function getPropertyValue(prop) { - return spoofStyle(prop, target[prop]); - }, target, 'getPropertyValue'); - } - return cloackFunc(target[prop], target, prop); - } - if ( instanceProperties.includes(prop) ) { - return Reflect.get(target, prop); - } - return spoofStyle(prop, Reflect.get(target, prop)); - }, - getOwnPropertyDescriptor(target, prop) { - if ( propToValueMap.has(prop) ) { - return { - configurable: true, - enumerable: true, - value: propToValueMap.get(prop), - writable: true, - }; - } - return Reflect.getOwnPropertyDescriptor(target, prop); - }, - }); - return proxiedStyle; - }, - get(target, prop) { - if ( prop === 'toString' ) { - return target.toString.bind(target); - } - return Reflect.get(target, prop); - }, - }); - Element.prototype.getBoundingClientRect = new Proxy(Element.prototype.getBoundingClientRect, { - apply: function(target, thisArg, args) { - // eslint-disable-next-line no-debugger - if ( privatePropToValueMap.has('_debug') ) { debugger; } - const rect = Reflect.apply(target, thisArg, args); - const targetElements = new WeakSet(document.querySelectorAll(selector)); - if ( targetElements.has(thisArg) === false ) { return rect; } - let { x, y, height, width } = rect; - if ( privatePropToValueMap.has('_rectx') ) { - x = parseFloat(privatePropToValueMap.get('_rectx')); - } - if ( privatePropToValueMap.has('_recty') ) { - y = parseFloat(privatePropToValueMap.get('_recty')); - } - if ( privatePropToValueMap.has('_rectw') ) { - width = parseFloat(privatePropToValueMap.get('_rectw')); - } else if ( propToValueMap.has('width') ) { - width = parseFloat(propToValueMap.get('width')); - } - if ( privatePropToValueMap.has('_recth') ) { - height = parseFloat(privatePropToValueMap.get('_recth')); - } else if ( propToValueMap.has('height') ) { - height = parseFloat(propToValueMap.get('height')); + const fixTimeAttributes = xmlDoc => { + try { + const periods = queryAll(xmlDoc, 'MPD > Period'); + if ( periods.length === 0 ) { return; } + let seconds = 0; + for ( const period of periods ) { + const startAttrBefore = period.getAttribute('start'); + const durAttr = period.getAttribute('duration'); + if ( startAttrBefore === null || durAttr === null ) { continue; } + const startAttrAfter = ptFromSeconds(seconds); + period.setAttribute('start', startAttrAfter); + if ( period.hasAttribute('id') ) { + const idAttr = period.getAttribute('id'); + period.setAttribute('id', idAttr.replace(startAttrBefore, startAttrAfter)); + } + seconds += secondsFromPT(durAttr); + } + const mpds = queryAll(xmlDoc, 'MPD[mediaPresentationDuration]'); + if ( mpds.length !== 1 ) { return; } + mpds[0].setAttribute('mediaPresentationDuration', ptFromSeconds(seconds)); + } catch { + } + }; + const pruneFromDoc = xmlDoc => { + try { + if ( selector === '' ) { + const serializer = new XMLSerializer(); + safe.uboLog(logPrefix, `Document is\n\t${serializer.serializeToString(xmlDoc)}`); } - return new self.DOMRect(x, y, width, height); - }, - get(target, prop) { - if ( prop === 'toString' ) { - return target.toString.bind(target); + const items = queryAll(xmlDoc, selector); + if ( items.length === 0 ) { return xmlDoc; } + safe.uboLog(logPrefix, `Patching ${items.length} items`); + for ( const item of items ) { + if ( item.nodeType !== 1 ) { continue; } + item.setAttribute('duration', 'PT0S'); } - return Reflect.get(target, prop); - }, + fixTimeAttributes(xmlDoc); + } catch(ex) { + safe.uboErr(logPrefix, `Error: ${ex}`); + } + return xmlDoc; + }; + const pruneFromText = text => { + if ( (/^\s*\s*$/.test(text)) === false ) { + return text; + } + try { + const xmlParser = new DOMParser(); + const xmlDoc = xmlParser.parseFromString(text, 'text/xml'); + pruneFromDoc(xmlDoc); + const serializer = new XMLSerializer(); + text = serializer.serializeToString(xmlDoc); + } catch { + } + return text; + }; + modifyXhrResponseFn(propsToMatch, (xhr, before) => { + if ( before instanceof XMLDocument ) { + return pruneFromDoc(before); + } + if ( typeof before === 'string' ) { + return pruneFromText(before); + } + return before; }); }; -spoofCSS(...args); +mpegdashPrune(...args); }, }; @@ -35299,8 +35565,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -35313,7 +35578,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -35324,10 +35589,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -35380,7 +35643,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -35492,6 +35755,8 @@ function getSafeCookieValuesFn() { 'decline', 'declined', 'closed', 'next', 'mandatory', 'disagree', 'agree', + 'set', 'unset', + 'given', ]; } function setCookie( @@ -35621,8 +35886,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -35635,7 +35899,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -35646,10 +35910,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -35702,7 +35964,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -35814,6 +36076,8 @@ function getSafeCookieValuesFn() { 'decline', 'declined', 'closed', 'next', 'mandatory', 'disagree', 'agree', + 'set', 'unset', + 'given', ]; } function setCookie( @@ -35946,8 +36210,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -35960,7 +36223,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -35971,10 +36234,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -36027,7 +36288,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -36259,8 +36520,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -36273,7 +36533,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -36284,10 +36544,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -36340,7 +36598,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -36498,8 +36756,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -36512,7 +36769,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -36523,10 +36780,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -36579,7 +36834,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -36773,6 +37028,8 @@ function getSafeCookieValuesFn() { 'decline', 'declined', 'closed', 'next', 'mandatory', 'disagree', 'agree', + 'set', 'unset', + 'given', ]; } function setLocalStorageItemFn( @@ -36860,8 +37117,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -36874,7 +37130,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -36885,10 +37141,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -36941,7 +37195,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -37068,6 +37322,8 @@ function getSafeCookieValuesFn() { 'decline', 'declined', 'closed', 'next', 'mandatory', 'disagree', 'agree', + 'set', 'unset', + 'given', ]; } function setLocalStorageItemFn( @@ -37155,8 +37411,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -37169,7 +37424,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -37180,10 +37435,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -37236,7 +37489,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -37363,6 +37616,8 @@ function getSafeCookieValuesFn() { 'decline', 'declined', 'closed', 'next', 'mandatory', 'disagree', 'agree', + 'set', 'unset', + 'given', ]; } function setLocalStorageItemFn( @@ -37450,8 +37705,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -37464,7 +37718,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -37475,10 +37729,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -37531,7 +37783,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -37658,6 +37910,8 @@ function getSafeCookieValuesFn() { 'decline', 'declined', 'closed', 'next', 'mandatory', 'disagree', 'agree', + 'set', 'unset', + 'given', ]; } function setLocalStorageItemFn( @@ -37745,8 +37999,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -37759,7 +38012,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -37770,10 +38023,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -37826,7 +38077,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -37937,8 +38188,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -37951,7 +38201,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -37962,10 +38212,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -38018,7 +38266,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -38186,8 +38434,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -38200,7 +38447,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -38211,10 +38458,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -38267,7 +38512,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -38413,8 +38658,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -38427,7 +38671,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -38438,10 +38682,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -38494,7 +38736,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -38627,8 +38869,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -38641,7 +38882,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -38652,10 +38893,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -38708,7 +38947,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -38841,8 +39080,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -38855,7 +39093,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -38866,10 +39104,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -38922,7 +39158,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -39053,8 +39289,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -39067,7 +39302,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -39078,10 +39313,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -39134,7 +39367,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -39336,8 +39569,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -39350,7 +39582,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -39361,10 +39593,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -39417,7 +39647,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -39581,8 +39811,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -39595,7 +39824,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -39606,10 +39835,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -39662,7 +39889,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -39951,8 +40178,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -39965,7 +40191,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -39976,10 +40202,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -40032,7 +40256,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -40317,6 +40541,46 @@ aliases: [], requiresTrust: false, func: function (scriptletGlobals = {}, ...args) { +function proxyToStringFn(proxiedFn, nativeFn) { + if ( proxyToStringFn.proxies === undefined ) { + proxyToStringFn.proxies = new WeakMap(); + proxyToStringFn.nativeToString = Function.prototype.toString; + const proxiedToString = new Proxy(Function.prototype.toString, { + apply(target, thisArg) { + let proxied = thisArg; + for(;;) { + const fn = proxyToStringFn.proxies.get(proxied); + if ( fn === undefined ) { break; } + proxied = fn; + } + return proxyToStringFn.nativeToString.call(proxied); + } + }); + proxyToStringFn.proxies.set(proxiedToString, proxyToStringFn.nativeToString); + Function.prototype.toString = proxiedToString; + } + proxyToStringFn.proxies.set(proxiedFn, nativeFn); +} +function parsePropertiesToMatchFn(propsToMatch, implicit = '') { + const safe = safeSelf(); + const needles = new Map(); + if ( propsToMatch === undefined || propsToMatch === '' ) { return needles; } + const options = { canNegate: true }; + for ( const needle of safe.String_split.call(propsToMatch, /\s+/) ) { + let [ prop, pattern ] = safe.String_split.call(needle, ':'); + if ( prop === '' ) { continue; } + if ( pattern !== undefined && /[^$\w -]/.test(prop) ) { + prop = `${prop}:${pattern}`; + pattern = undefined; + } + if ( pattern !== undefined ) { + needles.set(prop, safe.initPattern(pattern, options)); + } else if ( implicit !== '' ) { + needles.set(implicit, safe.initPattern(prop, options)); + } + } + return needles; +} function safeSelf() { if ( safeSelf.safe ) { return safeSelf.safe; @@ -40325,8 +40589,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -40339,7 +40602,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -40350,10 +40613,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -40406,7 +40667,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -40494,6 +40755,69 @@ function safeSelf() { } return safe; } +function matchObjectPropertiesFn(propNeedles, ...objs) { + const safe = safeSelf(); + const matched = []; + for ( const obj of objs ) { + if ( obj instanceof Object === false ) { continue; } + for ( const [ prop, details ] of propNeedles ) { + let value = obj[prop]; + if ( value === undefined ) { continue; } + if ( typeof value !== 'string' ) { + try { value = safe.JSON_stringify(value); } + catch { } + if ( typeof value !== 'string' ) { continue; } + } + if ( safe.testPattern(details, value) === false ) { return; } + matched.push(`${prop}: ${value}`); + } + } + return matched; +} +function modifyXhrResponseFn( + propsToMatch = '', + modifierFn = '' +) { + if ( typeof propsToMatch !== 'string' ) { return; } + const safe = safeSelf(); + if ( modifyXhrResponseFn.xhrInstances === undefined ) { + modifyXhrResponseFn.xhrInstances = new WeakMap(); + } + const propNeedles = parsePropertiesToMatchFn(propsToMatch, 'url'); + const NativeXMLHttpRequest = self.XMLHttpRequest; + const TrappedXMLHttpRequest = class XMLHttpRequest extends NativeXMLHttpRequest { + open(method, url, ...args) { + const haystack = { method, url }; + if ( propsToMatch === '' ) { + safe.uboLog(`modifyXhrResponseFn() / Called: ${safe.JSON_stringify(haystack, null, 2)}`); + } else if ( matchObjectPropertiesFn(propNeedles, haystack) ) { + modifyXhrResponseFn.xhrInstances.set(this, modifierFn); + } + return super.open(method, url, ...args); + } + get response() { + const modifierFn = modifyXhrResponseFn.xhrInstances.get(this); + return modifierFn + ? modifierFn(this, super.response) + : super.response; + } + get responseText() { + const modifierFn = modifyXhrResponseFn.xhrInstances.get(this); + return modifierFn + ? modifierFn(this, super.responseText) + : super.responseText; + } + get responseXML() { + const modifierFn = modifyXhrResponseFn.xhrInstances.get(this); + return modifierFn + ? modifierFn(this, super.responseXML) + : super.responseXML; + } + }; + proxyToStringFn(TrappedXMLHttpRequest.prototype.open, NativeXMLHttpRequest.prototype.open); + proxyToStringFn(TrappedXMLHttpRequest, NativeXMLHttpRequest); + self.XMLHttpRequest = TrappedXMLHttpRequest; +} function xmlPrune( selector = '', selectorCheck = '', @@ -40596,41 +40920,14 @@ function xmlPrune( }); } }); - self.XMLHttpRequest.prototype.open = new Proxy(self.XMLHttpRequest.prototype.open, { - apply: async (target, thisArg, args) => { - if ( reUrl.test(urlFromArg(args[1])) === false ) { - return Reflect.apply(target, thisArg, args); - } - thisArg.addEventListener('readystatechange', function() { - if ( thisArg.readyState !== 4 ) { return; } - const type = thisArg.responseType; - if ( - type === 'document' || - type === '' && thisArg.responseXML instanceof XMLDocument - ) { - pruneFromDoc(thisArg.responseXML); - const serializer = new XMLSerializer(); - const textout = serializer.serializeToString(thisArg.responseXML); - Object.defineProperty(thisArg, 'responseText', { value: textout }); - if ( typeof thisArg.response === 'string' ) { - Object.defineProperty(thisArg, 'response', { value: textout }); - } - return; - } - if ( - type === 'text' || - type === '' && typeof thisArg.responseText === 'string' - ) { - const textin = thisArg.responseText; - const textout = pruneFromText(textin); - if ( textout === textin ) { return; } - Object.defineProperty(thisArg, 'response', { value: textout }); - Object.defineProperty(thisArg, 'responseText', { value: textout }); - return; - } - }); - return Reflect.apply(target, thisArg, args); + modifyXhrResponseFn(urlPattern, (xhr, before) => { + if ( before instanceof XMLDocument ) { + return pruneFromDoc(before); + } + if ( typeof before === 'string' ) { + return pruneFromText(before); } + return before; }); }; xmlPrune(...args); @@ -40651,8 +40948,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -40665,7 +40961,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -40676,10 +40972,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -40732,7 +41026,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -41094,8 +41388,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -41108,7 +41401,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -41119,10 +41412,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -41175,7 +41466,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -41337,8 +41628,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -41351,7 +41641,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -41362,10 +41652,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -41418,7 +41706,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -41528,15 +41816,6 @@ function replaceNodeTextFn( const reExcludes = extraArgs.excludes ? safe.patternToRegex(extraArgs.excludes, 'ms') : null; - const stop = (takeRecord = true) => { - if ( takeRecord ) { - handleMutations(observer.takeRecords()); - } - observer.disconnect(); - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, 'Quitting'); - } - }; const textContentFactory = (( ) => { const out = { createScript: s => s }; const { trustedTypes: tt } = self; @@ -41549,19 +41828,19 @@ function replaceNodeTextFn( } return out; })(); - let sedCount = extraArgs.sedCount || 0; + let sedCount = extraArgs.sedCount ?? Number.MAX_SAFE_INTEGER; const handleNode = node => { const before = node.textContent; if ( reIncludes ) { reIncludes.lastIndex = 0; - if ( safe.RegExp_test.call(reIncludes, before) === false ) { return true; } + if ( safe.RegExp_test(reIncludes, before) === false ) { return; } } if ( reExcludes ) { reExcludes.lastIndex = 0; - if ( safe.RegExp_test.call(reExcludes, before) ) { return true; } + if ( safe.RegExp_test(reExcludes, before) ) { return; } } rePattern.lastIndex = 0; - if ( safe.RegExp_test.call(rePattern, before) === false ) { return true; } + if ( safe.RegExp_test(rePattern, before) === false ) { return; } rePattern.lastIndex = 0; const after = pattern !== '' ? before.replace(rePattern, replacement) @@ -41573,44 +41852,65 @@ function replaceNodeTextFn( safe.uboLog(logPrefix, `Text before:\n${before.trim()}`); } safe.uboLog(logPrefix, `Text after:\n${after.trim()}`); - return sedCount === 0 || (sedCount -= 1) !== 0; + sedCount -= 1; }; - const handleMutations = mutations => { - for ( const mutation of mutations ) { - for ( const node of mutation.addedNodes ) { - if ( reNodeName.test(node.nodeName) === false ) { continue; } - if ( handleNode(node) ) { continue; } - stop(false); return; - } - } - }; - const observer = new MutationObserver(handleMutations); - observer.observe(document, { childList: true, subtree: true }); - if ( document.documentElement ) { - const treeWalker = document.createTreeWalker( - document.documentElement, + const handleTree = root => { + const treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT ); + const { currentScript } = document; let count = 0; for (;;) { const node = treeWalker.nextNode(); - count += 1; if ( node === null ) { break; } - if ( reNodeName.test(node.nodeName) === false ) { continue; } - if ( node === document.currentScript ) { continue; } - if ( handleNode(node) ) { continue; } - stop(); break; + count += 1; + if ( node === currentScript ) { continue; } + if ( reNodeName.test(node.nodeName) ) { + handleNode(node); + } else if ( node.nodeName === 'TEMPLATE' ) { + count += handleTree(node.content); + } else { + continue; + } + if ( sedCount === 0 ) { break; } } + return count; + }; + if ( document.documentElement ) { + const count = handleTree(document.documentElement); safe.uboLog(logPrefix, `${count} nodes present before installing mutation observer`); } - if ( extraArgs.stay ) { return; } - runAt(( ) => { - const quitAfter = extraArgs.quitAfter || 0; - if ( quitAfter !== 0 ) { - setTimeout(( ) => { stop(); }, quitAfter); - } else { - stop(); + const stay = Boolean(extraArgs.stay); + if ( sedCount === 0 && stay === false ) { return; } + const stop = (takeRecord = true) => { + const mutations = takeRecord ? observer.takeRecords() : []; + observer.disconnect(); + handleMutations(mutations); + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, 'Quitting'); } + }; + const handleMutations = mutations => { + for ( const mutation of mutations ) { + for ( const node of mutation.addedNodes ) { + if ( reNodeName.test(node.nodeName) ) { + handleNode(node); + } else if ( node.nodeName === 'TEMPLATE' ) { + handleTree(node.content); + } else { + continue; + } + if ( sedCount === 0 ) { return stop(false); } + } + } + }; + const observer = new MutationObserver(handleMutations); + observer.observe(document, { childList: true, subtree: true }); + if ( stay ) { return; } + runAt(( ) => { + const quitAfter = extraArgs.quitAfter ?? 0; + if ( quitAfter === 0 ) { return stop(); } + setTimeout(( ) => { stop(); }, quitAfter); }, 'interactive'); } function removeNodeText( @@ -41638,8 +41938,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -41652,7 +41951,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -41663,10 +41962,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -41719,7 +42016,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -42006,8 +42303,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -42020,7 +42316,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -42031,10 +42327,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -42087,7 +42381,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -42197,15 +42491,6 @@ function replaceNodeTextFn( const reExcludes = extraArgs.excludes ? safe.patternToRegex(extraArgs.excludes, 'ms') : null; - const stop = (takeRecord = true) => { - if ( takeRecord ) { - handleMutations(observer.takeRecords()); - } - observer.disconnect(); - if ( safe.logLevel > 1 ) { - safe.uboLog(logPrefix, 'Quitting'); - } - }; const textContentFactory = (( ) => { const out = { createScript: s => s }; const { trustedTypes: tt } = self; @@ -42218,19 +42503,19 @@ function replaceNodeTextFn( } return out; })(); - let sedCount = extraArgs.sedCount || 0; + let sedCount = extraArgs.sedCount ?? Number.MAX_SAFE_INTEGER; const handleNode = node => { const before = node.textContent; if ( reIncludes ) { reIncludes.lastIndex = 0; - if ( safe.RegExp_test.call(reIncludes, before) === false ) { return true; } + if ( safe.RegExp_test(reIncludes, before) === false ) { return; } } if ( reExcludes ) { reExcludes.lastIndex = 0; - if ( safe.RegExp_test.call(reExcludes, before) ) { return true; } + if ( safe.RegExp_test(reExcludes, before) ) { return; } } rePattern.lastIndex = 0; - if ( safe.RegExp_test.call(rePattern, before) === false ) { return true; } + if ( safe.RegExp_test(rePattern, before) === false ) { return; } rePattern.lastIndex = 0; const after = pattern !== '' ? before.replace(rePattern, replacement) @@ -42242,44 +42527,65 @@ function replaceNodeTextFn( safe.uboLog(logPrefix, `Text before:\n${before.trim()}`); } safe.uboLog(logPrefix, `Text after:\n${after.trim()}`); - return sedCount === 0 || (sedCount -= 1) !== 0; - }; - const handleMutations = mutations => { - for ( const mutation of mutations ) { - for ( const node of mutation.addedNodes ) { - if ( reNodeName.test(node.nodeName) === false ) { continue; } - if ( handleNode(node) ) { continue; } - stop(false); return; - } - } + sedCount -= 1; }; - const observer = new MutationObserver(handleMutations); - observer.observe(document, { childList: true, subtree: true }); - if ( document.documentElement ) { - const treeWalker = document.createTreeWalker( - document.documentElement, + const handleTree = root => { + const treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT ); + const { currentScript } = document; let count = 0; for (;;) { const node = treeWalker.nextNode(); - count += 1; if ( node === null ) { break; } - if ( reNodeName.test(node.nodeName) === false ) { continue; } - if ( node === document.currentScript ) { continue; } - if ( handleNode(node) ) { continue; } - stop(); break; + count += 1; + if ( node === currentScript ) { continue; } + if ( reNodeName.test(node.nodeName) ) { + handleNode(node); + } else if ( node.nodeName === 'TEMPLATE' ) { + count += handleTree(node.content); + } else { + continue; + } + if ( sedCount === 0 ) { break; } } + return count; + }; + if ( document.documentElement ) { + const count = handleTree(document.documentElement); safe.uboLog(logPrefix, `${count} nodes present before installing mutation observer`); } - if ( extraArgs.stay ) { return; } - runAt(( ) => { - const quitAfter = extraArgs.quitAfter || 0; - if ( quitAfter !== 0 ) { - setTimeout(( ) => { stop(); }, quitAfter); - } else { - stop(); + const stay = Boolean(extraArgs.stay); + if ( sedCount === 0 && stay === false ) { return; } + const stop = (takeRecord = true) => { + const mutations = takeRecord ? observer.takeRecords() : []; + observer.disconnect(); + handleMutations(mutations); + if ( safe.logLevel > 1 ) { + safe.uboLog(logPrefix, 'Quitting'); + } + }; + const handleMutations = mutations => { + for ( const mutation of mutations ) { + for ( const node of mutation.addedNodes ) { + if ( reNodeName.test(node.nodeName) ) { + handleNode(node); + } else if ( node.nodeName === 'TEMPLATE' ) { + handleTree(node.content); + } else { + continue; + } + if ( sedCount === 0 ) { return stop(false); } + } } + }; + const observer = new MutationObserver(handleMutations); + observer.observe(document, { childList: true, subtree: true }); + if ( stay ) { return; } + runAt(( ) => { + const quitAfter = extraArgs.quitAfter ?? 0; + if ( quitAfter === 0 ) { return stop(); } + setTimeout(( ) => { stop(); }, quitAfter); }, 'interactive'); } function replaceNodeText( @@ -42347,8 +42653,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -42361,7 +42666,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -42372,10 +42677,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -42428,7 +42731,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -42650,8 +42953,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -42664,7 +42966,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -42675,10 +42977,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -42731,7 +43031,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -43047,8 +43347,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -43061,7 +43360,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -43072,10 +43371,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -43128,7 +43425,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -43362,8 +43659,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -43376,7 +43672,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -43387,10 +43683,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -43443,7 +43737,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -43637,7 +43931,7 @@ function trustedReplaceOutboundText( ) { if ( propChain === '' ) { return; } const safe = safeSelf(); - const logPrefix = safe.makeLogPrefix('trusted-replace-outbound-text', propChain, rawPattern, rawReplacement, ...args); + const logPrefix = safe.makeLogPrefix('trusted-replace-outbound-text', propChain, rawPattern, rawReplacement, ...varargs); const rePattern = safe.patternToRegex(rawPattern); const replacement = rawReplacement.startsWith('json:') ? safe.JSON_parse(rawReplacement.slice(5)) @@ -43786,8 +44080,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -43800,7 +44093,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -43811,10 +44104,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -43867,7 +44158,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -44061,7 +44352,7 @@ function trustedSuppressNativeMethod( } } if ( signatureArg.type === 'pattern' ) { - if ( safe.RegExp_test.call(signatureArg.re, targetArg) === false ) { + if ( safe.RegExp_test(signatureArg.re, targetArg) === false ) { return context.reflect(); } } @@ -44100,8 +44391,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -44114,7 +44404,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -44125,10 +44415,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -44181,7 +44469,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; }, @@ -44476,8 +44764,7 @@ function safeSelf() { const safe = { 'Array_from': Array.from, 'Error': self.Error, - 'Function_toStringFn': self.Function.prototype.toString, - 'Function_toString': thisArg => safe.Function_toStringFn.call(thisArg), + 'Function_toString': Function.prototype.call.bind(self.Function.prototype.toString), 'Math_floor': Math.floor, 'Math_max': Math.max, 'Math_min': Math.min, @@ -44490,7 +44777,7 @@ function safeSelf() { 'Object_hasOwn': Object.hasOwn.bind(Object), 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, - 'RegExp_test': self.RegExp.prototype.test, + 'RegExp_test': Function.prototype.call.bind(self.RegExp.prototype.test), 'RegExp_exec': self.RegExp.prototype.exec, 'Request_clone': self.Request.prototype.clone, 'String': self.String, @@ -44501,10 +44788,8 @@ function safeSelf() { 'removeEventListener': self.EventTarget.prototype.removeEventListener, 'fetch': self.fetch, 'JSON': self.JSON, - 'JSON_parseFn': self.JSON.parse, - 'JSON_stringifyFn': self.JSON.stringify, - 'JSON_parse': (...args) => safe.JSON_parseFn.call(safe.JSON, ...args), - 'JSON_stringify': (...args) => safe.JSON_stringifyFn.call(safe.JSON, ...args), + 'JSON_parse': Function.prototype.call.bind(self.JSON.parse, self.JSON), + 'JSON_stringify': Function.prototype.call.bind(self.JSON.stringify, self.JSON), 'log': console.log.bind(console), // Properties logLevel: 0, @@ -44557,7 +44842,7 @@ function safeSelf() { testPattern(details, haystack) { if ( details.matchAll ) { return true; } if ( details.re ) { - return this.RegExp_test.call(details.re, haystack) === details.expect; + return this.RegExp_test(details.re, haystack) === details.expect; } return haystack.includes(details.pattern) === details.expect; },