From 4b5e53fc8ae617247063eb2732f4db89234a5b3b Mon Sep 17 00:00:00 2001 From: Jonathan Kingston Date: Wed, 16 Oct 2024 17:10:59 +0100 Subject: [PATCH] Change tab URL calculation for contentblockerrules.js and surrogates.js (#1021) Please review the release process for BrowserServicesKit [here](https://app.asana.com/0/1200194497630846/1200837094583426). **Required**: Task/Issue URL: #1019 and https://app.asana.com/0/1200437802575119/1208550540369943/f iOS PR: TODO macOS PR: TODO What kind of version bump will this require?: Minor **Optional**: Tech Design URL: CC: **Description**: This PR changes the tab calculation for the page, currently it doesn't account for grand child frames at all. This code has mostly been cribbed from: https://github.com/duckduckgo/content-scope-scripts/blob/655d12d9e77f93cc36875142aa2ff3e06c52608d/injected/src/utils.js#L135-L157 Full disclosure: I tested this manually in the console rather than doing a full build, we should verify before releasing. Thanks to @alisha for spotting this problem in #1019, producing a well written explanation and PR! **Steps to test this PR**: For testing the blocking follow the steps in: https://github.com/duckduckgo/BrowserServicesKit/issues/1019 using the console. For surrogates the same should work for a tracker on the surrogate list: - replacing https://rtb.openx.net/openrtbb/prebidjs with https://google-analytics.com/gtm/js - validating that frame has the script executed: cframe.contentWindow.ga should be defined **OS Testing**: * [ ] iOS 14 * [ ] iOS 15 * [ ] iOS 16 * [ ] macOS 10.15 * [ ] macOS 11 * [ ] macOS 12 --- ###### Internal references: [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) --- .../UserScripts/contentblockerrules.js | 47 ++++++++++++------- .../ContentBlocking/UserScripts/surrogates.js | 41 +++++++++++----- 2 files changed, 60 insertions(+), 28 deletions(-) diff --git a/Sources/BrowserServicesKit/ContentBlocking/UserScripts/contentblockerrules.js b/Sources/BrowserServicesKit/ContentBlocking/UserScripts/contentblockerrules.js index 7ca771a6e..b85acb56f 100644 --- a/Sources/BrowserServicesKit/ContentBlocking/UserScripts/contentblockerrules.js +++ b/Sources/BrowserServicesKit/ContentBlocking/UserScripts/contentblockerrules.js @@ -19,7 +19,37 @@ // "use strict"; (function () { - const topLevelUrl = getTopLevelURL() + + + /** + * Best guess effort of the tabs hostname. Cribbed from getTabHostname in: https://github.com/duckduckgo/content-scope-scripts/ + * @returns {string|null} inferred tab hostname + */ + function getTabURL () { + let framingOrigin = null + try { + // @ts-expect-error - globalThis.top is possibly 'null' here + framingOrigin = globalThis.top.location.href + } catch { + framingOrigin = globalThis.document.referrer + } + + // Not supported in Firefox + if ('ancestorOrigins' in globalThis.location && globalThis.location.ancestorOrigins.length) { + // ancestorOrigins is reverse order, with the last item being the top frame + framingOrigin = globalThis.location.ancestorOrigins.item(globalThis.location.ancestorOrigins.length - 1) + } + + try { + // @ts-expect-error - framingOrigin is possibly 'null' here + framingOrigin = new URL(framingOrigin) + } catch { + framingOrigin = null + } + return framingOrigin + } + + const topLevelUrl = getTabURL() let unprotectedDomain = false const domainParts = topLevelUrl && topLevelUrl.host ? topLevelUrl.host.split('.') : [] @@ -133,21 +163,6 @@ return false } - // private - function getTopLevelURL () { - try { - // FROM: https://stackoverflow.com/a/7739035/73479 - // FIX: Better capturing of top level URL so that trackers in embedded documents are not considered first party - if (window.location !== window.parent.location) { - return new URL(window.location.href !== 'about:blank' ? document.referrer : window.parent.location.href) - } else { - return new URL(document.location.href) - } - } catch (error) { - return new URL(location.href) - } - } - if (!window.__firefox__) { Object.defineProperty(window, '__firefox__', { enumerable: false, diff --git a/Sources/BrowserServicesKit/ContentBlocking/UserScripts/surrogates.js b/Sources/BrowserServicesKit/ContentBlocking/UserScripts/surrogates.js index 9dd4fe34a..eb2f2d3e8 100644 --- a/Sources/BrowserServicesKit/ContentBlocking/UserScripts/surrogates.js +++ b/Sources/BrowserServicesKit/ContentBlocking/UserScripts/surrogates.js @@ -377,7 +377,35 @@ } ]) - const topLevelUrl = getTopLevelURL() + /** + * Best guess effort of the tabs hostname. Cribbed from getTabHostname in: https://github.com/duckduckgo/content-scope-scripts/ + * @returns {string|null} inferred tab hostname + */ + function getTabURL () { + let framingOrigin = null + try { + // @ts-expect-error - globalThis.top is possibly 'null' here + framingOrigin = globalThis.top.location.href + } catch { + framingOrigin = globalThis.document.referrer + } + + // Not supported in Firefox + if ('ancestorOrigins' in globalThis.location && globalThis.location.ancestorOrigins.length) { + // ancestorOrigins is reverse order, with the last item being the top frame + framingOrigin = globalThis.location.ancestorOrigins.item(globalThis.location.ancestorOrigins.length - 1) + } + + try { + // @ts-expect-error - framingOrigin is possibly 'null' here + framingOrigin = new URL(framingOrigin) + } catch { + framingOrigin = null + } + return framingOrigin + } + + const topLevelUrl = getTabURL() let unprotectedDomain = false const domainParts = topLevelUrl && topLevelUrl.host ? topLevelUrl.host.split('.') : [] @@ -466,17 +494,6 @@ return false } - // private - function getTopLevelURL () { - try { - // FROM: https://stackoverflow.com/a/7739035/73479 - // FIX: Better capturing of top level URL so that trackers in embedded documents are not considered first party - return new URL(window.location !== window.parent.location ? document.referrer : document.location.href) - } catch (error) { - return new URL(location.href) - } - } - // private function loadSurrogate (surrogatePattern) { trackers.surrogateList[surrogatePattern]()