[tor-commits] [tor-browser/tor-browser-78.0.1esr-10.0-1] fixup! Bug 28005: Implement .onion alias urlbar rewrites

sysrqb at torproject.org sysrqb at torproject.org
Fri Jul 31 15:39:07 UTC 2020


commit 90a93e6906657ed96a2f5918dbf18430ca5e50da
Author: Alex Catarineu <acat at torproject.org>
Date:   Mon Jul 20 21:27:16 2020 +0200

    fixup! Bug 28005: Implement .onion alias urlbar rewrites
---
 browser/actors/ClickHandlerChild.jsm               | 20 +++++++++
 browser/actors/ClickHandlerParent.jsm              |  1 +
 browser/actors/ContextMenuChild.jsm                |  4 ++
 browser/base/content/browser.js                    | 36 +++++++++++----
 browser/base/content/nsContextMenu.js              | 18 ++++++++
 browser/base/content/tabbrowser.js                 |  7 +++
 browser/base/content/utilityOverlay.js             | 12 +++++
 .../components/onionservices/OnionAliasStore.jsm   | 12 ++---
 docshell/base/nsDocShell.cpp                       | 52 ++++++++++++++++++++++
 docshell/base/nsDocShell.h                         |  6 +++
 docshell/base/nsDocShellLoadState.cpp              |  4 ++
 docshell/base/nsIDocShell.idl                      |  5 +++
 docshell/base/nsIWebNavigation.idl                 |  5 +++
 docshell/shistory/SessionHistoryEntry.cpp          | 14 ++++++
 docshell/shistory/SessionHistoryEntry.h            |  1 +
 docshell/shistory/nsISHEntry.idl                   |  5 +++
 docshell/shistory/nsSHEntry.cpp                    | 22 ++++++++-
 docshell/shistory/nsSHEntry.h                      |  1 +
 dom/interfaces/base/nsIBrowser.idl                 |  3 +-
 dom/ipc/BrowserChild.cpp                           |  2 +
 dom/ipc/BrowserParent.cpp                          |  3 +-
 dom/ipc/PBrowser.ipdl                              |  1 +
 modules/libpref/init/StaticPrefList.yaml           |  6 +++
 netwerk/ipc/DocumentLoadListener.cpp               | 10 +++++
 toolkit/content/widgets/browser-custom-element.js  | 13 +++++-
 toolkit/modules/sessionstore/SessionHistory.jsm    |  5 +++
 26 files changed, 249 insertions(+), 19 deletions(-)

diff --git a/browser/actors/ClickHandlerChild.jsm b/browser/actors/ClickHandlerChild.jsm
index 7dd060e83061..206a8fc97a4d 100644
--- a/browser/actors/ClickHandlerChild.jsm
+++ b/browser/actors/ClickHandlerChild.jsm
@@ -138,6 +138,26 @@ class ClickHandlerChild extends JSWindowActorChild {
       json.originStoragePrincipal = ownerDoc.effectiveStoragePrincipal;
       json.triggeringPrincipal = ownerDoc.nodePrincipal;
 
+      // Check if the link needs to be opened with .tor.onion urlbar rewrites
+      // allowed. Only when the owner doc has onionUrlbarRewritesAllowed = true
+      // and the same origin we should allow this.
+      json.onionUrlbarRewritesAllowed = false;
+      if (this.docShell.onionUrlbarRewritesAllowed) {
+        const sm = Services.scriptSecurityManager;
+        try {
+          let targetURI = Services.io.newURI(href);
+          let isPrivateWin =
+            ownerDoc.nodePrincipal.originAttributes.privateBrowsingId > 0;
+          sm.checkSameOriginURI(
+            docshell.currentDocumentChannel.URI,
+            targetURI,
+            false,
+            isPrivateWin
+          );
+          json.onionUrlbarRewritesAllowed = true;
+        } catch (e) {}
+      }
+
       // If a link element is clicked with middle button, user wants to open
       // the link somewhere rather than pasting clipboard content.  Therefore,
       // when it's clicked with middle button, we should prevent multiple
diff --git a/browser/actors/ClickHandlerParent.jsm b/browser/actors/ClickHandlerParent.jsm
index 454c0fe69b27..42ab7a0f6e2a 100644
--- a/browser/actors/ClickHandlerParent.jsm
+++ b/browser/actors/ClickHandlerParent.jsm
@@ -102,6 +102,7 @@ class ClickHandlerParent extends JSWindowActorParent {
       charset: browser.characterSet,
       referrerInfo: E10SUtils.deserializeReferrerInfo(data.referrerInfo),
       allowMixedContent: data.allowMixedContent,
+      onionUrlbarRewritesAllowed: data.onionUrlbarRewritesAllowed,
       isContentWindowPrivate: data.isContentWindowPrivate,
       originPrincipal: data.originPrincipal,
       originStoragePrincipal: data.originStoragePrincipal,
diff --git a/browser/actors/ContextMenuChild.jsm b/browser/actors/ContextMenuChild.jsm
index 16a3f8ecbc81..1a1b38aa6375 100644
--- a/browser/actors/ContextMenuChild.jsm
+++ b/browser/actors/ContextMenuChild.jsm
@@ -575,6 +575,9 @@ class ContextMenuChild extends JSWindowActorChild {
     // The same-origin check will be done in nsContextMenu.openLinkInTab.
     let parentAllowsMixedContent = !!this.docShell.mixedContentChannel;
 
+    let parentAllowsOnionUrlbarRewrites = this.docShell
+      .onionUrlbarRewritesAllowed;
+
     let disableSetDesktopBackground = null;
 
     // Media related cache info parent needs for saving
@@ -687,6 +690,7 @@ class ContextMenuChild extends JSWindowActorChild {
       frameBrowsingContextID,
       disableSetDesktopBackground,
       parentAllowsMixedContent,
+      parentAllowsOnionUrlbarRewrites,
     };
 
     if (context.inFrame && !context.inSrcdocFrame) {
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index ff4c30ca876e..5d99785d5ec0 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2248,6 +2248,7 @@ var gBrowserInit = {
         //                 [9]: allowInheritPrincipal (bool)
         //                 [10]: csp (nsIContentSecurityPolicy)
         //                 [11]: nsOpenWindowInfo
+        //                 [12]: onionUrlbarRewritesAllowed
         let userContextId =
           window.arguments[5] != undefined
             ? window.arguments[5]
@@ -2267,7 +2268,8 @@ var gBrowserInit = {
           // TODO fix allowInheritPrincipal to default to false.
           // Default to true unless explicitly set to false because of bug 1475201.
           window.arguments[9] !== false,
-          window.arguments[10]
+          window.arguments[10],
+          window.arguments[12]
         );
         window.focus();
       } else {
@@ -3153,7 +3155,8 @@ function loadURI(
   forceAboutBlankViewerInCurrent,
   triggeringPrincipal,
   allowInheritPrincipal = false,
-  csp = null
+  csp = null,
+  onionUrlbarRewritesAllowed = false
 ) {
   if (!triggeringPrincipal) {
     throw new Error("Must load with a triggering Principal");
@@ -3171,6 +3174,7 @@ function loadURI(
       csp,
       forceAboutBlankViewerInCurrent,
       allowInheritPrincipal,
+      onionUrlbarRewritesAllowed,
     });
   } catch (e) {
     Cu.reportError(e);
@@ -5282,16 +5286,14 @@ var XULBrowserWindow = {
         this.reloadCommand.removeAttribute("disabled");
       }
 
-      // The onion memorable alias needs to be used in URLBarSetURI, but also in
+      // The onion memorable alias needs to be used in gURLBar.setURI, but also in
       // other parts of the code (like the bookmarks UI), so we save it.
-      const onionRewritesDisabled = Services.prefs.getBoolPref(
-        "browser.urlbar.onionRewrites.disabled",
-        false
-      );
-      if (!onionRewritesDisabled) {
+      if (gBrowser.selectedBrowser.onionUrlbarRewritesAllowed) {
         gBrowser.selectedBrowser.currentOnionAliasURI = OnionAliasStore.getShortURI(
-          aLocationURI
+          gBrowser.selectedBrowser.currentURI
         );
+      } else {
+        gBrowser.selectedBrowser.currentOnionAliasURI = null;
       }
 
       // We want to update the popup visibility if we received this notification
@@ -6961,6 +6963,21 @@ function handleLinkClick(event, href, linkNode) {
     } catch (e) {}
   }
 
+  // Check if the link needs to be opened with .tor.onion urlbar rewrites
+  // allowed. Only when the owner doc has onionUrlbarRewritesAllowed = true
+  // and the same origin we should allow this.
+  let persistOnionUrlbarRewritesAllowedInChildTab = false;
+  if (where == "tab" && gBrowser.docShell.onionUrlbarRewritesAllowed) {
+    const sm = Services.scriptSecurityManager;
+    try {
+      let tURI = makeURI(href);
+      let isPrivateWin =
+        doc.nodePrincipal.originAttributes.privateBrowsingId > 0;
+      sm.checkSameOriginURI(doc.documentURIObject, tURI, false, isPrivateWin);
+      persistOnionUrlbarRewritesAllowedInChildTab = true;
+    } catch (e) {}
+  }
+
   let frameOuterWindowID = WebNavigationFrames.getFrameId(doc.defaultView);
 
   urlSecurityCheck(href, doc.nodePrincipal);
@@ -6973,6 +6990,7 @@ function handleLinkClick(event, href, linkNode) {
     triggeringPrincipal: doc.nodePrincipal,
     csp: doc.csp,
     frameOuterWindowID,
+    onionUrlbarRewritesAllowed: persistOnionUrlbarRewritesAllowedInChildTab,
   };
 
   // The new tab/window must use the same userContextId
diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js
index 314f7a1364da..80a8379ab35b 100644
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -57,6 +57,7 @@ function openContextMenu(aMessage, aBrowser, aActor) {
     disableSetDesktopBackground: data.disableSetDesktopBackground,
     loginFillInfo: data.loginFillInfo,
     parentAllowsMixedContent: data.parentAllowsMixedContent,
+    parentAllowsOnionUrlbarRewrites: data.parentAllowsOnionUrlbarRewrites,
     userContextId: data.userContextId,
     webExtContextData: data.webExtContextData,
   };
@@ -1049,6 +1050,7 @@ class nsContextMenu {
       triggeringPrincipal: this.principal,
       csp: this.csp,
       frameOuterWindowID: this.contentData.frameOuterWindowID,
+      onionUrlbarRewritesAllowed: false,
     };
     for (let p in extra) {
       params[p] = extra[p];
@@ -1072,6 +1074,22 @@ class nsContextMenu {
     }
 
     params.referrerInfo = referrerInfo;
+
+    // Check if the link needs to be opened with .tor.onion urlbar rewrites
+    // allowed. Only when parent has onionUrlbarRewritesAllowed = true
+    // and the same origin we should allow this.
+    if (this.contentData.parentAllowsOnionUrlbarRewrites) {
+      let referrerURI = this.contentData.documentURIObject;
+      const sm = Services.scriptSecurityManager;
+      try {
+        let targetURI = this.linkURI;
+        let isPrivateWin =
+          this.browser.contentPrincipal.originAttributes.privateBrowsingId > 0;
+        sm.checkSameOriginURI(referrerURI, targetURI, false, isPrivateWin);
+        params.onionUrlbarRewritesAllowed = true;
+      } catch (e) {}
+    }
+
     return params;
   }
 
diff --git a/browser/base/content/tabbrowser.js b/browser/base/content/tabbrowser.js
index 22c7fafef72b..573b114d7813 100644
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -1547,6 +1547,7 @@
       var aRelatedToCurrent;
       var aAllowInheritPrincipal;
       var aAllowMixedContent;
+      var aOnionUrlbarRewritesAllowed;
       var aSkipAnimation;
       var aForceNotRemote;
       var aPreferredRemoteType;
@@ -1577,6 +1578,7 @@
         aRelatedToCurrent = params.relatedToCurrent;
         aAllowInheritPrincipal = !!params.allowInheritPrincipal;
         aAllowMixedContent = params.allowMixedContent;
+        aOnionUrlbarRewritesAllowed = params.onionUrlbarRewritesAllowed;
         aSkipAnimation = params.skipAnimation;
         aForceNotRemote = params.forceNotRemote;
         aPreferredRemoteType = params.preferredRemoteType;
@@ -1618,6 +1620,7 @@
         relatedToCurrent: aRelatedToCurrent,
         skipAnimation: aSkipAnimation,
         allowMixedContent: aAllowMixedContent,
+        onionUrlbarRewritesAllowed: aOnionUrlbarRewritesAllowed,
         forceNotRemote: aForceNotRemote,
         createLazyBrowser: aCreateLazyBrowser,
         preferredRemoteType: aPreferredRemoteType,
@@ -2504,6 +2507,7 @@
       {
         allowInheritPrincipal,
         allowMixedContent,
+        onionUrlbarRewritesAllowed,
         allowThirdPartyFixup,
         bulkOrderedOpen,
         charset,
@@ -2833,6 +2837,9 @@
           if (allowMixedContent) {
             flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_MIXED_CONTENT;
           }
+          if (onionUrlbarRewritesAllowed) {
+            flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES;
+          }
           if (!allowInheritPrincipal) {
             flags |= Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL;
           }
diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js
index a23d6f05e6a7..eb13d5a3435c 100644
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -367,6 +367,7 @@ function openLinkIn(url, where, params) {
   var aRelatedToCurrent = params.relatedToCurrent;
   var aAllowInheritPrincipal = !!params.allowInheritPrincipal;
   var aAllowMixedContent = params.allowMixedContent;
+  var aOnionUrlbarRewritesAllowed = params.onionUrlbarRewritesAllowed;
   var aForceAllowDataURI = params.forceAllowDataURI;
   var aInBackground = params.inBackground;
   var aInitiatingDoc = params.initiatingDoc;
@@ -482,6 +483,11 @@ function openLinkIn(url, where, params) {
     ].createInstance(Ci.nsISupportsPRBool);
     allowThirdPartyFixupSupports.data = aAllowThirdPartyFixup;
 
+    var onionUrlbarRewritesAllowed = Cc[
+      "@mozilla.org/supports-PRBool;1"
+    ].createInstance(Ci.nsISupportsPRBool);
+    onionUrlbarRewritesAllowed.data = aOnionUrlbarRewritesAllowed;
+
     var userContextIdSupports = Cc[
       "@mozilla.org/supports-PRUint32;1"
     ].createInstance(Ci.nsISupportsPRUint32);
@@ -498,6 +504,8 @@ function openLinkIn(url, where, params) {
     sa.appendElement(aTriggeringPrincipal);
     sa.appendElement(null); // allowInheritPrincipal
     sa.appendElement(aCsp);
+    sa.appendElement(null); // nsOpenWindowInfo
+    sa.appendElement(onionUrlbarRewritesAllowed);
 
     const sourceWindow = w || window;
     let win;
@@ -614,6 +622,9 @@ function openLinkIn(url, where, params) {
       if (aForceAllowDataURI) {
         flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
       }
+      if (aOnionUrlbarRewritesAllowed) {
+        flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES;
+      }
 
       let { URI_INHERITS_SECURITY_CONTEXT } = Ci.nsIProtocolHandler;
       if (
@@ -661,6 +672,7 @@ function openLinkIn(url, where, params) {
         relatedToCurrent: aRelatedToCurrent,
         skipAnimation: aSkipTabAnimation,
         allowMixedContent: aAllowMixedContent,
+        onionUrlbarRewritesAllowed: aOnionUrlbarRewritesAllowed,
         userContextId: aUserContextId,
         originPrincipal: aPrincipal,
         originStoragePrincipal: aStoragePrincipal,
diff --git a/browser/components/onionservices/OnionAliasStore.jsm b/browser/components/onionservices/OnionAliasStore.jsm
index 7e006e59490b..66cf569227bf 100644
--- a/browser/components/onionservices/OnionAliasStore.jsm
+++ b/browser/components/onionservices/OnionAliasStore.jsm
@@ -65,6 +65,7 @@ class _OnionAliasStore {
     this._removeObserver = () => {};
     this._canLoadRules = false;
     this._rulesetTimestamp = null;
+    this._updateChannelInstalled = false;
   }
 
   async _periodicRulesetCheck() {
@@ -99,24 +100,25 @@ class _OnionAliasStore {
   async init() {
     this.httpsEverywhereControl = new HttpsEverywhereControl();
 
-    // Install update channel
-    await this.httpsEverywhereControl.installTorOnionUpdateChannel();
-
     // Setup .tor.onion rule loading.
     // The http observer is a fallback, and is removed in _loadRules() as soon as we are able
     // to load some rules from HTTPS Everywhere.
     this._loadHttpObserver();
     try {
+      await this.httpsEverywhereControl.installTorOnionUpdateChannel();
+      this._updateChannelInstalled = true;
       await this.httpsEverywhereControl.getTorOnionRules();
       this._canLoadRules = true;
     } catch (e) {
       // Loading rules did not work, probably because "get_simple_rules_ending_with" is not yet
       // working in https-everywhere. Use an http observer as a fallback for learning the rules.
-      log.debug("Could not load rules, using http observer as fallback");
+      log.debug(`Could not load rules: ${e.message}`);
     }
 
     // Setup checker for https-everywhere ruleset updates
-    this._periodicRulesetCheck();
+    if (this._updateChannelInstalled) {
+      this._periodicRulesetCheck();
+    }
   }
 
   /**
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index 675ee0592847..01a4daf5bc00 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -5651,6 +5651,10 @@ void nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
     return;
   }
 
+  if (!mOnionUrlbarRewritesAllowed && IsTorOnionRedirect(oldURI, newURI)) {
+    mOnionUrlbarRewritesAllowed = true;
+  }
+
   // DocumentChannel adds redirect chain to global history in the parent
   // process. The redirect chain can't be queried from the content process, so
   // there's no need to update global history here.
@@ -8675,6 +8679,20 @@ nsresult nsDocShell::HandleSameDocumentNavigation(
   return NS_OK;
 }
 
+/* static */
+bool nsDocShell::IsTorOnionRedirect(nsIURI* aOldURI, nsIURI* aNewURI) {
+    nsAutoCString oldHost;
+    nsAutoCString newHost;
+    if (aOldURI && aNewURI && NS_SUCCEEDED(aOldURI->GetHost(oldHost)) &&
+        StringEndsWith(oldHost, NS_LITERAL_CSTRING(".tor.onion")) &&
+        NS_SUCCEEDED(aNewURI->GetHost(newHost)) &&
+        StringEndsWith(newHost, NS_LITERAL_CSTRING(".onion")) &&
+        !StringEndsWith(newHost, NS_LITERAL_CSTRING(".tor.onion"))) {
+      return true;
+    }
+    return false;
+  }
+
 nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
                                   nsIDocShell** aDocShell,
                                   nsIRequest** aRequest) {
@@ -8826,6 +8844,30 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState,
 
   mAllowKeywordFixup =
       aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP);
+
+  if (mOnionUrlbarRewritesAllowed) {
+    mOnionUrlbarRewritesAllowed = false;
+    nsCOMPtr<nsIURI> referrer;
+    nsIReferrerInfo* referrerInfo = aLoadState->GetReferrerInfo();
+    if (referrerInfo) {
+      referrerInfo->GetOriginalReferrer(getter_AddRefs(referrer));
+      bool isPrivateWin = false;
+      Document* doc = GetDocument();
+      if (doc) {
+        isPrivateWin =
+            doc->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId > 0;
+        nsCOMPtr<nsIScriptSecurityManager> secMan =
+            do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
+        mOnionUrlbarRewritesAllowed =
+            secMan && NS_SUCCEEDED(secMan->CheckSameOriginURI(
+                          aLoadState->URI(), referrer, false, isPrivateWin));
+      }
+    }
+  }
+  mOnionUrlbarRewritesAllowed =
+      mOnionUrlbarRewritesAllowed ||
+      aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES);
+
   mURIResultedInDocument = false;  // reset the clock...
 
   // See if this is actually a load between two history entries for the same
@@ -10971,6 +11013,7 @@ nsresult nsDocShell::AddToSessionHistory(
                 mDynamicallyCreated, originalURI, resultPrincipalURI,
                 loadReplace, referrerInfo, srcdoc, srcdocEntry, baseURI,
                 saveLayoutState, expired);
+  entry->SetOnionUrlbarRewritesAllowed(mOnionUrlbarRewritesAllowed);
 
   if (root == static_cast<nsIDocShellTreeItem*>(this) && GetSessionHistory()) {
     bool shouldPersist = ShouldAddToSessionHistory(aURI, aChannel);
@@ -12768,3 +12811,12 @@ bool nsDocShell::GetIsAttemptingToNavigate() {
 
   return false;
 }
+
+NS_IMETHODIMP
+nsDocShell::GetOnionUrlbarRewritesAllowed(bool* aOnionUrlbarRewritesAllowed) {
+  NS_ENSURE_ARG(aOnionUrlbarRewritesAllowed);
+  *aOnionUrlbarRewritesAllowed =
+      StaticPrefs::browser_urlbar_onionRewrites_enabled() &&
+      mOnionUrlbarRewritesAllowed;
+  return NS_OK;
+}
diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h
index dcffed8e5537..d403a06f4c9f 100644
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -152,6 +152,9 @@ class nsDocShell final : public nsDocLoader,
 
     // Whether the load should go through LoadURIDelegate.
     INTERNAL_LOAD_FLAGS_BYPASS_LOAD_URI_DELEGATE = 0x2000,
+
+    // Whether rewriting the urlbar to a short .onion alias is allowed.
+    INTERNAL_LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES = 0x4000,
   };
 
   // Event type dispatched by RestorePresentation
@@ -582,6 +585,8 @@ class nsDocShell final : public nsDocLoader,
 
   virtual void DestroyChildren() override;
 
+  static bool IsTorOnionRedirect(nsIURI* aOldURI, nsIURI* aNewURI);
+
   // Overridden from nsDocLoader, this provides more information than the
   // normal OnStateChange with flags STATE_REDIRECTING
   virtual void OnRedirectStateChange(nsIChannel* aOldChannel,
@@ -1264,6 +1269,7 @@ class nsDocShell final : public nsDocLoader,
   bool mCSSErrorReportingEnabled : 1;
   bool mAllowAuth : 1;
   bool mAllowKeywordFixup : 1;
+  bool mOnionUrlbarRewritesAllowed : 1;
   bool mIsOffScreenBrowser : 1;
   bool mDisableMetaRefreshWhenInactive : 1;
   bool mIsAppTab : 1;
diff --git a/docshell/base/nsDocShellLoadState.cpp b/docshell/base/nsDocShellLoadState.cpp
index 9f9b8f406fd4..053773df6319 100644
--- a/docshell/base/nsDocShellLoadState.cpp
+++ b/docshell/base/nsDocShellLoadState.cpp
@@ -728,6 +728,10 @@ void nsDocShellLoadState::CalculateLoadURIFlags() {
     mLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
   }
 
+  if (oldLoadFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES) {
+    mLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES;
+  }
+
   if (oldLoadFlags & nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD) {
     mLoadFlags |= nsDocShell::INTERNAL_LOAD_FLAGS_FIRST_LOAD;
   }
diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl
index 01dc4734eb19..305acfd3a98f 100644
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -1019,4 +1019,9 @@ interface nsIDocShell : nsIDocShellTreeItem
    * until session history state is moved into the parent process.
    */
   void persistLayoutHistoryState();
+
+  /**
+   * Whether rewriting the urlbar to a short .onion alias is allowed.
+   */
+  [infallible] readonly attribute boolean onionUrlbarRewritesAllowed;
 };
diff --git a/docshell/base/nsIWebNavigation.idl b/docshell/base/nsIWebNavigation.idl
index bbc3eb7583a2..a4cceb52b2a0 100644
--- a/docshell/base/nsIWebNavigation.idl
+++ b/docshell/base/nsIWebNavigation.idl
@@ -237,6 +237,11 @@ interface nsIWebNavigation : nsISupports
    */
   const unsigned long LOAD_FLAGS_BYPASS_LOAD_URI_DELEGATE = 0x4000000;
 
+  /**
+   * Allow rewriting the urlbar to a short .onion alias.
+   */
+  const unsigned long LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES = 0x8000000;
+
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing this interface.  If it can't be loaded here
diff --git a/docshell/shistory/SessionHistoryEntry.cpp b/docshell/shistory/SessionHistoryEntry.cpp
index 07a28d1291c9..566b7d68fae5 100644
--- a/docshell/shistory/SessionHistoryEntry.cpp
+++ b/docshell/shistory/SessionHistoryEntry.cpp
@@ -490,6 +490,20 @@ SessionHistoryEntry::SetPersist(bool aPersist) {
   return NS_OK;
 }
 
+NS_IMETHODIMP
+SessionHistoryEntry::GetOnionUrlbarRewritesAllowed(
+    bool* aOnionUrlbarRewritesAllowed) {
+  *aOnionUrlbarRewritesAllowed = mInfo->mOnionUrlbarRewritesAllowed;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+SessionHistoryEntry::SetOnionUrlbarRewritesAllowed(
+    bool aOnionUrlbarRewritesAllowed) {
+  mInfo->mOnionUrlbarRewritesAllowed = aOnionUrlbarRewritesAllowed;
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 SessionHistoryEntry::GetScrollPosition(int32_t* aX, int32_t* aY) {
   *aX = mInfo->mScrollPositionX;
diff --git a/docshell/shistory/SessionHistoryEntry.h b/docshell/shistory/SessionHistoryEntry.h
index fa6108952688..c51682a65b0a 100644
--- a/docshell/shistory/SessionHistoryEntry.h
+++ b/docshell/shistory/SessionHistoryEntry.h
@@ -58,6 +58,7 @@ class SessionHistoryInfo {
   bool mIsSrcdocEntry = false;
   bool mScrollRestorationIsManual = false;
   bool mPersist = false;
+  bool mOnionUrlbarRewritesAllowed = false;
 };
 
 // XXX Not sure that the id shouldn't just live in SessionHistoryInfo.
diff --git a/docshell/shistory/nsISHEntry.idl b/docshell/shistory/nsISHEntry.idl
index 8bbf2a68687c..bf410bfcc05a 100644
--- a/docshell/shistory/nsISHEntry.idl
+++ b/docshell/shistory/nsISHEntry.idl
@@ -242,6 +242,11 @@ interface nsISHEntry : nsISupports
      */
     [infallible] attribute boolean persist;
 
+    /**
+     * Whether rewriting the urlbar to a short .onion alias is allowed.
+     */
+    [infallible] attribute boolean onionUrlbarRewritesAllowed;
+
     /**
      * Set/Get the visual viewport scroll position if session history is
      * changed through anchor navigation or pushState.
diff --git a/docshell/shistory/nsSHEntry.cpp b/docshell/shistory/nsSHEntry.cpp
index 229b15eff25d..12d38f4c55fe 100644
--- a/docshell/shistory/nsSHEntry.cpp
+++ b/docshell/shistory/nsSHEntry.cpp
@@ -44,7 +44,8 @@ nsSHEntry::nsSHEntry(nsISHistory* aSHistory)
       mIsSrcdocEntry(false),
       mScrollRestorationIsManual(false),
       mLoadedInThisProcess(false),
-      mPersist(true) {}
+      mPersist(true),
+      mOnionUrlbarRewritesAllowed(false) {}
 
 nsSHEntry::nsSHEntry(const nsSHEntry& aOther)
     : mShared(aOther.mShared),
@@ -70,7 +71,8 @@ nsSHEntry::nsSHEntry(const nsSHEntry& aOther)
       mIsSrcdocEntry(aOther.mIsSrcdocEntry),
       mScrollRestorationIsManual(false),
       mLoadedInThisProcess(aOther.mLoadedInThisProcess),
-      mPersist(aOther.mPersist) {}
+      mPersist(aOther.mPersist),
+      mOnionUrlbarRewritesAllowed(aOther.mOnionUrlbarRewritesAllowed) {}
 
 nsSHEntry::~nsSHEntry() {
   // Null out the mParent pointers on all our kids.
@@ -824,6 +826,18 @@ nsSHEntry::SetPersist(bool aPersist) {
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsSHEntry::GetOnionUrlbarRewritesAllowed(bool* aOnionUrlbarRewritesAllowed) {
+  *aOnionUrlbarRewritesAllowed = mOnionUrlbarRewritesAllowed;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSHEntry::SetOnionUrlbarRewritesAllowed(bool aOnionUrlbarRewritesAllowed) {
+  mOnionUrlbarRewritesAllowed = aOnionUrlbarRewritesAllowed;
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 nsSHEntry::CreateLoadInfo(nsDocShellLoadState** aLoadState) {
   nsCOMPtr<nsIURI> uri = GetURI();
@@ -873,6 +887,10 @@ nsSHEntry::CreateLoadInfo(nsDocShellLoadState** aLoadState) {
   } else {
     srcdoc = VoidString();
   }
+  if (GetOnionUrlbarRewritesAllowed()) {
+    flags |= nsDocShell::InternalLoad::
+        INTERNAL_LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES;
+  }
   loadState->SetSrcdocData(srcdoc);
   loadState->SetBaseURI(baseURI);
   loadState->SetLoadFlags(flags);
diff --git a/docshell/shistory/nsSHEntry.h b/docshell/shistory/nsSHEntry.h
index 351f6f200a33..6bc9de521437 100644
--- a/docshell/shistory/nsSHEntry.h
+++ b/docshell/shistory/nsSHEntry.h
@@ -63,6 +63,7 @@ class nsSHEntry : public nsISHEntry {
   bool mScrollRestorationIsManual;
   bool mLoadedInThisProcess;
   bool mPersist;
+  bool mOnionUrlbarRewritesAllowed;
 };
 
 #endif /* nsSHEntry_h */
diff --git a/dom/interfaces/base/nsIBrowser.idl b/dom/interfaces/base/nsIBrowser.idl
index 300b09e13824..a9ff00e964b7 100644
--- a/dom/interfaces/base/nsIBrowser.idl
+++ b/dom/interfaces/base/nsIBrowser.idl
@@ -158,7 +158,8 @@ interface nsIBrowser : nsISupports
                                in uint64_t aInnerWindowID,
                                in boolean aHasRequestContextID,
                                in uint64_t aRequestContextID,
-                               in AString aContentType);
+                               in AString aContentType,
+                               in boolean aOnionUrlbarRewritesAllowed);
 
   /**
    * Called by Gecko when it wants to change the process which is currently
diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp
index 2b17323d8a93..f72aa8faa11d 100644
--- a/dom/ipc/BrowserChild.cpp
+++ b/dom/ipc/BrowserChild.cpp
@@ -3645,6 +3645,8 @@ NS_IMETHODIMP BrowserChild::OnLocationChange(nsIWebProgress* aWebProgress,
         docShell->GetMayEnableCharacterEncodingMenu();
     locationChangeData->charsetAutodetected() =
         docShell->GetCharsetAutodetected();
+    locationChangeData->onionUrlbarRewritesAllowed() =
+        docShell->GetOnionUrlbarRewritesAllowed();
 
     locationChangeData->contentPrincipal() = document->NodePrincipal();
     locationChangeData->contentStoragePrincipal() =
diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp
index 35d095f167c0..a5d9e08a3a7a 100644
--- a/dom/ipc/BrowserParent.cpp
+++ b/dom/ipc/BrowserParent.cpp
@@ -2698,7 +2698,8 @@ mozilla::ipc::IPCResult BrowserParent::RecvOnLocationChange(
         aWebProgressData->innerDOMWindowID(),
         aLocationChangeData->requestContextID().isSome(),
         aLocationChangeData->requestContextID().valueOr(0),
-        aLocationChangeData->contentType());
+        aLocationChangeData->contentType(),
+        aLocationChangeData->onionUrlbarRewritesAllowed());
   }
 
   Unused << managerAsListener->OnLocationChange(webProgress, request, aLocation,
diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl
index 6a854fb6450a..51f89165ed71 100644
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -142,6 +142,7 @@ struct WebProgressLocationChangeData
   bool isSyntheticDocument;
   bool mayEnableCharacterEncodingMenu;
   bool charsetAutodetected;
+  bool onionUrlbarRewritesAllowed;
   nsString contentType;
   nsString title;
   nsString charset;
diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml
index a821d80b6aa2..9e4e04360063 100644
--- a/modules/libpref/init/StaticPrefList.yaml
+++ b/modules/libpref/init/StaticPrefList.yaml
@@ -1077,6 +1077,12 @@
   value: true
   mirror: always
 
+  # Whether rewriting the urlbar to a short .onion alias is allowed.
+- name: browser.urlbar.onionRewrites.enabled
+  type: RelaxedAtomicBool
+  value: true
+  mirror: always
+
 - name: browser.viewport.desktopWidth
   type: RelaxedAtomicInt32
   value: 980
diff --git a/netwerk/ipc/DocumentLoadListener.cpp b/netwerk/ipc/DocumentLoadListener.cpp
index 901ce11b57ca..988ec94a82d4 100644
--- a/netwerk/ipc/DocumentLoadListener.cpp
+++ b/netwerk/ipc/DocumentLoadListener.cpp
@@ -1856,6 +1856,16 @@ DocumentLoadListener::AsyncOnChannelRedirect(
         mLoadStateLoadType, nsIWebNavigation::LOAD_FLAGS_ALLOW_MIXED_CONTENT));
   }
 
+  // Like the code above for allowing mixed content, we need to check this here
+  // in case the redirect is not handled in the docshell.
+  nsCOMPtr<nsIURI> oldURI, newURI;
+  aOldChannel->GetURI(getter_AddRefs(oldURI));
+  aNewChannel->GetURI(getter_AddRefs(newURI));
+  if (nsDocShell::IsTorOnionRedirect(oldURI, newURI)) {
+     mLoadStateLoadFlags |=
+      nsDocShell::INTERNAL_LOAD_FLAGS_ALLOW_ONION_URLBAR_REWRITES;
+  }
+
   // We need the original URI of the current channel to use to open the real
   // channel in the content process. Unfortunately we overwrite the original
   // uri of the new channel with the original pre-redirect URI, so grab
diff --git a/toolkit/content/widgets/browser-custom-element.js b/toolkit/content/widgets/browser-custom-element.js
index 62a1ab1d6796..67fa1e5645c0 100644
--- a/toolkit/content/widgets/browser-custom-element.js
+++ b/toolkit/content/widgets/browser-custom-element.js
@@ -261,6 +261,8 @@
 
       this._mayEnableCharacterEncodingMenu = null;
 
+      this._onionUrlbarRewritesAllowed = false;
+
       this._charsetAutodetected = false;
 
       this._contentPrincipal = null;
@@ -686,6 +688,12 @@
       }
     }
 
+    get onionUrlbarRewritesAllowed() {
+      return this.isRemoteBrowser
+        ? this._onionUrlbarRewritesAllowed
+        : this.docShell.onionUrlbarRewritesAllowed;
+    }
+
     get charsetAutodetected() {
       return this.isRemoteBrowser
         ? this._charsetAutodetected
@@ -1292,7 +1300,8 @@
       aInnerWindowID,
       aHaveRequestContextID,
       aRequestContextID,
-      aContentType
+      aContentType,
+      aOnionUrlbarRewritesAllowed
     ) {
       if (this.isRemoteBrowser && this.messageManager) {
         if (aCharset != null) {
@@ -1316,6 +1325,7 @@
         this._contentRequestContextID = aHaveRequestContextID
           ? aRequestContextID
           : null;
+        this._onionUrlbarRewritesAllowed = aOnionUrlbarRewritesAllowed;
       }
     }
 
@@ -1708,6 +1718,7 @@
             "_contentStoragePrincipal",
             "_isSyntheticDocument",
             "_innerWindowID",
+            "_onionUrlbarRewritesAllowed",
           ]
         );
       }
diff --git a/toolkit/modules/sessionstore/SessionHistory.jsm b/toolkit/modules/sessionstore/SessionHistory.jsm
index 6c16ac331659..cc47f437824f 100644
--- a/toolkit/modules/sessionstore/SessionHistory.jsm
+++ b/toolkit/modules/sessionstore/SessionHistory.jsm
@@ -318,6 +318,7 @@ var SessionHistoryInternal = {
     }
 
     entry.persist = shEntry.persist;
+    entry.onionUrlbarRewritesAllowed = shEntry.onionUrlbarRewritesAllowed;
 
     return entry;
   },
@@ -601,6 +602,10 @@ var SessionHistoryInternal = {
       }
     }
 
+    if (entry.onionUrlbarRewritesAllowed) {
+      shEntry.onionUrlbarRewritesAllowed = entry.onionUrlbarRewritesAllowed;
+    }
+
     return shEntry;
   },
 





More information about the tor-commits mailing list