[Git][tpo/applications/tor-browser][tor-browser-154.0a1-17.0-2] fixup! TB 21952: Implement Onion-Location
Pier Angelo Vendrame pushed to branch tor-browser-154.0a1-17.0-2 at The Tor Project / Applications / Tor Browser Commits: 8154acd5 by soni at 2026-10-15T01:09:18+02:00 fixup! TB 21952: Implement Onion-Location - - - - - 6 changed files: - browser/components/BrowserComponents.manifest - browser/components/DesktopActorRegistry.sys.mjs - browser/components/onionservices/OnionLocationChild.sys.mjs - browser/components/onionservices/OnionLocationParent.sys.mjs - + browser/components/onionservices/OnionLocationWatch.sys.mjs - browser/components/onionservices/moz.build Changes: ===================================== browser/components/BrowserComponents.manifest ===================================== @@ -172,6 +172,7 @@ category browser-first-window-ready moz-src:///browser/modules/SecurityLevelNoti category browser-first-window-ready moz-src:///toolkit/modules/DragDropFilter.sys.mjs DragDropFilter.init category browser-first-window-ready moz-src:///browser/modules/TorSettingsNotification.sys.mjs TorSettingsNotification.ready category browser-first-window-ready moz-src:///browser/components/onionservices/OnionAliasStore.sys.mjs OnionAliasStore.init +category browser-first-window-ready moz-src:///browser/components/onionservices/OnionLocationWatch.sys.mjs OnionLocationWatch.init category browser-idle-startup moz-src:///browser/components/places/PlacesUIUtils.sys.mjs PlacesUIUtils.unblockToolbars category browser-idle-startup resource:///modules/BuiltInThemes.sys.mjs BuiltInThemes.ensureBuiltInThemes @@ -220,5 +221,6 @@ category browser-quit-application-granted resource://gre/modules/UpdateListener. #endif category browser-quit-application-granted moz-src:///browser/components/urlbar/UrlbarSearchTermsPersistence.sys.mjs UrlbarSearchTermsPersistence.uninit category browser-quit-application-granted moz-src:///browser/components/onionservices/OnionAliasStore.sys.mjs OnionAliasStore.uninit +category browser-quit-application-granted moz-src:///browser/components/onionservices/OnionLocationWatch.sys.mjs OnionLocationWatch.uninit category browser-newtab-external-component moz-src:///browser/components/search/SearchUIUtils.sys.mjs SearchNewTabComponentsRegistrant ===================================== browser/components/DesktopActorRegistry.sys.mjs ===================================== @@ -656,6 +656,7 @@ let JSWINDOWACTORS = { }, }, messageManagerGroups: ["browsers"], + safeForUntrustedWebProcess: true, }, PageAssist: { ===================================== browser/components/onionservices/OnionLocationChild.sys.mjs ===================================== @@ -14,32 +14,9 @@ export class OnionLocationChild extends JSWindowActorChild { } const onionLocationURI = this.document.onionLocationURI; if (onionLocationURI) { - this.sendAsyncMessage("OnionLocation:Set"); - } - } - - receiveMessage(aMessage) { - if (aMessage.name == "OnionLocation:Refresh") { - const doc = this.document; - const docShell = this.docShell; - let onionLocationURI = doc.onionLocationURI; - const refreshURI = docShell.QueryInterface(Ci.nsIRefreshURI); - if (onionLocationURI && refreshURI) { - const docUrl = URL.parse(doc.URL); - let onionUrl = URL.parse(onionLocationURI.asciiSpec); - // Keep consistent with Location - if (!onionUrl?.hash && docUrl?.hash) { - onionUrl.hash = docUrl.hash; - onionLocationURI = Services.io.newURI(onionUrl?.toString() || ""); - } - refreshURI.refreshURI( - onionLocationURI, - doc.nodePrincipal, - 0, - false, - true - ); - } + this.sendAsyncMessage("OnionLocation:Set", { + uri: onionLocationURI.asciiSpec, + }); } } } ===================================== browser/components/onionservices/OnionLocationParent.sys.mjs ===================================== @@ -2,6 +2,8 @@ import { TorStrings } from "moz-src:///toolkit/modules/TorStrings.sys.mjs"; +import { BrowserUtils } from "resource://gre/modules/BrowserUtils.sys.mjs"; + // Prefs // We keep the "prioritizeonions" name, even if obsolete, in order to @@ -36,36 +38,71 @@ export class OnionLocationParent extends JSWindowActorParent { switch (aMsg.name) { case "OnionLocation:Set": { let browser = this.browsingContext.embedderElement; - OnionLocationParent.setOnionLocation(browser); + OnionLocationParent.setOnionLocationFallback(browser, aMsg); + + // tor-browser #40100 + // Wait for the page to fully load before showing the notification. + // This prevents redirects that occur before onPageShow from causing it to disappear. + // This could be handled more elegantly by changing the notification's "appear once and never again behaviour". + // Sites that redirect after the onPageShow event are not affected and will therefore cause the notification to disappear. + // https://gitlab.torproject.org/tpo/applications/tor-browser/-/merge_requests/... + OnionLocationParent.showNotification(browser); break; } } } + // Maintains compatibility with <meta http-equiv="onion-location"> + static setOnionLocationFallback(browser, aMsg) { + let onionLocation; + try { + onionLocation = new URL(aMsg.data.uri); + } catch (e) { + return; + } + + if ( + browser && + !browser._onionLocation && + OnionLocationParent.validateOnionV3(onionLocation) + ) { + OnionLocationParent.setOnionLocation(browser, onionLocation); + } + } + static init(document) { document .getElementById(ONIONLOCATION_BOX_ID) - .addEventListener("click", event => this.buttonClick(event)); + .addEventListener("click", event => this.openOnionLink(event)); } - static buttonClick(event) { - if (event.button !== 0) { - return; - } + static openOnionLink(event) { const win = event.target.documentGlobal; - if (win.gBrowser) { - const browser = win.gBrowser.selectedBrowser; - OnionLocationParent.redirect(browser); + const browser = win.gBrowser?.selectedBrowser; + + if (!browser?._onionLocation || event.button > 1) { + return; } - } - static redirect(browser) { - let windowGlobal = browser.browsingContext.currentWindowGlobal; - let actor = windowGlobal.getActor("OnionLocation"); - if (actor) { - actor.sendAsyncMessage("OnionLocation:Refresh", {}); + const where = BrowserUtils.whereToOpenLink(event); + const triggeringPrincipal = + Services.scriptSecurityManager.getSystemPrincipal(); + + if (where == "current") { + browser.webNavigation.stop(Ci.nsIWebNavigation.STOP_ALL); OnionLocationParent.setDisabled(browser); } + + const onionUrl = browser._onionLocation; + const docUrl = new URL(browser.browsingContext.currentURI.asciiSpec); + + if (docUrl.hash && docUrl.hash != onionUrl.hash) { + onionUrl.hash = docUrl.hash; + } + + win.openLinkIn(onionUrl.href, where, { + triggeringPrincipal, + }); } static onStateChange(browser) { @@ -73,8 +110,8 @@ export class OnionLocationParent extends JSWindowActorParent { OnionLocationParent.hideNotification(browser); } - static setOnionLocation(browser) { - browser._onionLocation = true; + static setOnionLocation(browser, onionLocation) { + browser._onionLocation = onionLocation; let tabBrowser = browser.getTabBrowser(); if (tabBrowser && browser === tabBrowser.selectedBrowser) { OnionLocationParent.updateOnionLocationBadge(browser); @@ -90,7 +127,7 @@ export class OnionLocationParent extends JSWindowActorParent { static showNotification(browser) { const mustShow = Services.prefs.getBoolPref(NOTIFICATION_PREF, true); - if (!mustShow) { + if (!mustShow || !browser._onionLocation) { return; } @@ -100,8 +137,8 @@ export class OnionLocationParent extends JSWindowActorParent { const mainAction = { label: NOTIFICATION_OK_LABEL, accessKey: NOTIFICATION_OK_ACCESSKEY, - callback() { - OnionLocationParent.redirect(browser); + callback(obj) { + OnionLocationParent.openOnionLink(obj.event); }, }; @@ -164,9 +201,15 @@ export class OnionLocationParent extends JSWindowActorParent { static updateOnionLocationBadge(browser) { if (browser._onionLocation) { OnionLocationParent.setEnabled(browser); - OnionLocationParent.showNotification(browser); } else { OnionLocationParent.setDisabled(browser); } } + + static validateOnionV3(url) { + if (!["http:", "https:"].includes(url.protocol)) { + return false; + } + return /(^|\.)[a-z2-7]{56}\.onion$/i.test(url.hostname); + } } ===================================== browser/components/onionservices/OnionLocationWatch.sys.mjs ===================================== @@ -0,0 +1,91 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { OnionLocationParent } from "moz-src:///browser/components/onionservices/OnionLocationParent.sys.mjs"; + +const log = console.createInstance({ + prefix: "OnionLocationWatch", +}); + +/** + * This request observer listens to http-on-examine-responses to know early if a clearnet site has an onion alternative. + */ +class _OnionLocationWatch { + init() { + Services.obs.addObserver(this, "http-on-examine-response"); + Services.obs.addObserver(this, "http-on-examine-cached-response"); + Services.obs.addObserver(this, "http-on-examine-merged-response"); + log.debug("Started"); + } + + uninit() { + Services.obs.removeObserver(this, "http-on-examine-response"); + Services.obs.removeObserver(this, "http-on-examine-cached-response"); + Services.obs.removeObserver(this, "http-on-examine-merged-response"); + log.debug("Stopped"); + } + + // nsIObserver implementation + observe(subject, topic) { + try { + let channel = ChannelWrapper.get( + subject.QueryInterface(Ci.nsIHttpChannel) + ); + switch (topic) { + case "http-on-examine-cached-response": + case "http-on-examine-merged-response": + case "http-on-examine-response": + this.onResponse(channel); + break; + } + } catch (e) { + log.error(e); + } + } + + onResponse(channel) { + this.checkResponseForOnionLocation(channel); + } + + checkResponseForOnionLocation(channel) { + const browser = channel.browserElement; + const uri = channel.finalURI; + + if (!browser || uri?.scheme != "https") { + return; + } + + const isTopLevelDoc = + channel.channel.loadInfo.isTopLevelLoad && channel.channel.isDocument; + const isOnion = uri.host?.toLowerCase().endsWith(".onion"); + + if (isTopLevelDoc && !isOnion && !browser._onionLocation) { + const onionLocation = this.getOnionLocation(channel); + if (onionLocation) { + OnionLocationParent.setOnionLocation(browser, onionLocation); + } + } + } + + getOnionLocation(channel) { + let onionLocation = channel + .getResponseHeaders() + .find(el => el.name.toLowerCase() == "onion-location")?.value; + + if (onionLocation) { + try { + onionLocation = new URL(onionLocation); + } catch (e) { + return null; + } + + if (OnionLocationParent.validateOnionV3(onionLocation)) { + return onionLocation; + } + } + return null; + } +} + +export const OnionLocationWatch = new _OnionLocationWatch(); ===================================== browser/components/onionservices/moz.build ===================================== @@ -4,5 +4,6 @@ MOZ_SRC_FILES += [ "OnionAliasStore.sys.mjs", "OnionLocationChild.sys.mjs", "OnionLocationParent.sys.mjs", + "OnionLocationWatch.sys.mjs", "TorRequestWatch.sys.mjs", ] View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/8154acd5... -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/8154acd5... You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help
participants (1)
-
Pier Angelo Vendrame (@pierov)