From b27e4dd6a579c4d3d4c5532e6c0848ede7129d53 Mon Sep 17 00:00:00 2001 From: Brandon-T Date: Tue, 21 Feb 2023 22:27:56 -0500 Subject: [PATCH] Fix brave/brave-ios#6888: Do not override `toString`for XMLHTTPRequest (brave/brave-ios#6986) --- .../Scripts/Paged/RequestBlockingScript.js | 6 ++-- .../Scripts/Paged/RewardsReportingScript.js | 6 ++-- .../Scripts/Paged/TrackingProtectionStats.js | 4 +-- .../UserContent/UserScripts/__firefox__.js | 35 ++++++++++++++----- 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/RequestBlockingScript.js b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/RequestBlockingScript.js index 60a29efd08c4..3384486de409 100644 --- a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/RequestBlockingScript.js +++ b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/RequestBlockingScript.js @@ -45,7 +45,7 @@ window.__firefox__.execute(function($) { return originalFetch.apply(this, arguments) } }) - }); + }, /*overrideToString=*/false); const originalOpen = XMLHttpRequest.prototype.open XMLHttpRequest.prototype.open = $(function() { @@ -60,7 +60,7 @@ window.__firefox__.execute(function($) { // Store only primitive types not things like URL objects this._url = arguments[1] return originalOpen.apply(this, arguments) - }); + }, /*overrideToString=*/false); const originalSend = XMLHttpRequest.prototype.send XMLHttpRequest.prototype.send = $(function () { @@ -92,5 +92,5 @@ window.__firefox__.execute(function($) { originalSend.apply(this, arguments) } }) - }); + }, /*overrideToString=*/false); }); diff --git a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/RewardsReportingScript.js b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/RewardsReportingScript.js index b9c202571daa..7aa1cb898d3f 100644 --- a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/RewardsReportingScript.js +++ b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/RewardsReportingScript.js @@ -41,7 +41,7 @@ window.__firefox__.includeOnce("RewardsReporting", function($) { this.addEventListener('load', listener, true); this.addEventListener('error', listener, true); return originalOpen.apply(this, arguments); - }); + }, /*overrideToString=*/false); XMLHttpRequest.prototype.send = $(function(body) { this._ref = null; @@ -51,7 +51,7 @@ window.__firefox__.includeOnce("RewardsReporting", function($) { this._data = null; } return originalSend.apply(this, arguments); - }); + }, /*overrideToString=*/false); window.fetch = $(function(resource, options) { const args = arguments @@ -71,7 +71,7 @@ window.__firefox__.includeOnce("RewardsReporting", function($) { reject(error); }) })); - }); + }, /*overrideToString=*/false); navigator.sendBeacon = $(function(url, data) { sendMessage("POST", url, data); diff --git a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/TrackingProtectionStats.js b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/TrackingProtectionStats.js index 140b637089c3..f25bde4c953b 100644 --- a/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/TrackingProtectionStats.js +++ b/Sources/Brave/Frontend/UserContent/UserScripts/Scripts_Dynamic/Scripts/Paged/TrackingProtectionStats.js @@ -78,7 +78,7 @@ window.__firefox__.execute(function($) { this._shouldTrack = arguments[2] !== undefined && !arguments[2] this._url = url; return originalOpen.apply(this, arguments); - }); + }, /*overrideToString=*/false); xhrProto.send = $(function(body) { if (this._url === undefined || !this._shouldTrack) { @@ -96,7 +96,7 @@ window.__firefox__.execute(function($) { this.addEventListener("error", this._tpErrorHandler); } return originalSend.apply(this, arguments); - }); + }, /*overrideToString=*/false); // ------------------------------------------------- // Detect when new sources get set on Image and send them to the host application diff --git a/Sources/Brave/Frontend/UserContent/UserScripts/__firefox__.js b/Sources/Brave/Frontend/UserContent/UserScripts/__firefox__.js index 4b73067db92b..dee4556d489e 100644 --- a/Sources/Brave/Frontend/UserContent/UserScripts/__firefox__.js +++ b/Sources/Brave/Frontend/UserContent/UserScripts/__firefox__.js @@ -69,19 +69,26 @@ if (!window.__firefox__) { /* * Secures an object's attributes */ - let $ = function(value) { + let $ = function(value, overrideToString = true) { if ($Object.isExtensible(value)) { const description = (typeof value === 'function') ? - `function () {\n\t[native code]\n}` : + `function ${ typeof value.name !== 'undefined' ? value.name : "" }() {\n [native code]\n}` : '[object Object]'; const toString = function() { return description; }; - const overrides = { + Object.defineProperty(toString, 'name', { + enumerable: false, + configurable: true, + writable: false, + value: 'toString' + }); + + const overrides = overrideToString ? { 'toString': toString - }; + } : {}; if (typeof value === 'function') { const functionOverrides = { @@ -147,7 +154,7 @@ if (!window.__firefox__) { // Object.prototype.toString != Object.toString // They are two different functions, so we should check for both before overriding them let descriptor = $Object.getOwnPropertyDescriptor(value, name); - if (descriptor && descriptor.value !== Object.prototype.toString && descriptor.value !== Object.toString) { + if (descriptor && descriptor.value && descriptor.value !== Object.prototype.toString && descriptor.value !== Object.toString) { // Secure the existing custom toString function // Do NOT deepFreeze existing toString functions // on custom objects we don't own. We secure it, @@ -160,6 +167,18 @@ if (!window.__firefox__) { } continue; } + + // Object.prototype.toString != Object.toString + // They are two different functions, so we should check for both before overriding them + if (typeof value.toString !== 'undefined') { + if (value.toString !== Object.prototype.toString && value.toString !== Object.toString) { + if (value.toString !== toString) { + secureToString(value.toString); + } + + continue; + } + } } // Override all of the functions in the overrides array @@ -167,8 +186,8 @@ if (!window.__firefox__) { if (!descriptor || descriptor.configurable) { $Object.defineProperty(value, name, { enumerable: false, - configurable: false, - writable: false, + configurable: name == 'toString', + writable: name == 'toString', value: property }); } @@ -263,7 +282,7 @@ if (!window.__firefox__) { } return isIgnoredClass(obj) ? $(obj) : $Object.freeze($(obj)); - } else if (obj.constructor && (obj.constructor.name == "Function" || obj.constructor.name == "AsyncFunction")) { + } else if (obj.constructor && (obj.constructor.name == "Function" || obj.constructor.name == "AsyncFunction" || obj.constructor.name == "GeneratorFunction")) { return $Object.freeze($(obj)); } else { let prototype = $Object.getPrototypeOf(obj);