[tor-commits] [tor-browser/tor-browser-78.11.0esr-10.5-1] fixup! Bug 27476: Implement about:torconnect captive portal within Tor Browser

sysrqb at torproject.org sysrqb at torproject.org
Fri Jun 18 00:28:38 UTC 2021


commit d27a43d5986ff72c28d1380a4622eab594395085
Author: Richard Pospesel <richard at torproject.org>
Date:   Fri Jun 11 15:46:34 2021 +0200

    fixup! Bug 27476: Implement about:torconnect captive portal within Tor Browser
---
 browser/base/content/aboutNetError.js              |  7 +-
 browser/components/torconnect/TorConnectParent.jsm | 11 +++
 .../torconnect/content/aboutTorConnect.css         | 73 ++++++++++------
 .../torconnect/content/aboutTorConnect.js          | 96 +++++++++++-----------
 .../torconnect/content/aboutTorConnect.xhtml       | 13 +--
 .../torconnect/content/torconnect-urlbar.css       | 12 ++-
 .../components/torpreferences/content/torPane.js   |  3 +-
 browser/components/urlbar/UrlbarInput.jsm          | 31 +++++++
 toolkit/modules/RemotePageAccessManager.jsm        |  3 +
 toolkit/xre/nsAppRunner.cpp                        |  7 +-
 10 files changed, 178 insertions(+), 78 deletions(-)

diff --git a/browser/base/content/aboutNetError.js b/browser/base/content/aboutNetError.js
index 238b4930461c..b85ba74217cb 100644
--- a/browser/base/content/aboutNetError.js
+++ b/browser/base/content/aboutNetError.js
@@ -196,8 +196,13 @@ async function setErrorPageStrings(err) {
 
 async function initPage() {
   var err = getErrorCode();
+
+  // proxyConnectFailure because no-tor running daemon would return this error
+  // netOffline because we do not want to show the offline page (where users can disable offline-mode)
+  //   when we are 'offline' (offline mode is disabled after successful bootstrapping in
+  //   TorConnectParent)
   if (
-    err === "proxyConnectFailure" &&
+    (err === "proxyConnectFailure" || err === "netOffline") &&
     (await RPMSendQuery("ShouldShowTorConnect"))
   ) {
     document.location.replace("about:torconnect");
diff --git a/browser/components/torconnect/TorConnectParent.jsm b/browser/components/torconnect/TorConnectParent.jsm
index f775507a744f..cd574ada4da1 100644
--- a/browser/components/torconnect/TorConnectParent.jsm
+++ b/browser/components/torconnect/TorConnectParent.jsm
@@ -45,6 +45,17 @@ class TorConnectParent extends JSWindowActorParent {
           obj.handled = true;
         }
         self.sendAsyncMessage(aTopic, obj);
+
+        // we need to tell the IOService that we are not online
+        // setting offline to false will make the io service send out
+        // 'network:offline-status-changed' message to observers
+        // the app updater (among other things) listens for this message
+        // and will attempt to check for updates when receiving this message
+        // to recover from a previously failed attempt
+        if (aTopic === kTorBootstrapStatusTopic &&
+            obj.PROGRESS === 100) {
+          Services.io.offline = false;
+        }
       },
     };
 
diff --git a/browser/components/torconnect/content/aboutTorConnect.css b/browser/components/torconnect/content/aboutTorConnect.css
index 2081d4f6c4b8..eff767205266 100644
--- a/browser/components/torconnect/content/aboutTorConnect.css
+++ b/browser/components/torconnect/content/aboutTorConnect.css
@@ -43,42 +43,69 @@
   position: relative;
 }
 
-#copyLogTooltip {
-  visibility: hidden;
-  display: inline-block;
-  width: 100%;
+/* mirrors p element spacing */
+#copyLogContainer {
+  margin:  1em 0;
+  height:  1.2em;
+  min-height:  1.2em;
+}
 
-  position: absolute;
-  z-index: 1;
-  left: 0px;
-  bottom: calc(100% + 6px);
+#copyLogLink {
+  position:  relative;
+  display:  inline-block;
+  color:  var(--in-content-link-color);
 }
 
-#copyLogTooltip::after {
-  content: "";
-  position: absolute;
-  top: 100%;
-  left: 50%;
-  margin-left: -4px;
-  border-width: 4px;
-  border-style: solid;
-  border-color: #30E60B transparent transparent transparent;
+/* hidden apparently only works if no display is set; who knew? */
+#copyLogLink[hidden="true"] {
+  display:  none;
 }
 
+#copyLogLink:hover {
+  cursor:pointer;
+}
+
+/* This div:
+   - is centered over its parent
+   - centers its child
+   - has z-index above parent
+   - ignores mouse events from parent
+*/
+#copyLogTooltip {
+  pointer-events: none;
+  visibility: hidden;
+  display:  flex;
+  justify-content: center;
+  white-space: nowrap;
+  width: 0;
+  position:  absolute;
+
+  z-index:  1;
+  left: 50%;
+  bottom:  calc(100% + 0.25em);
+}
 
+/* tooltip content (any content could go here) */
 #copyLogTooltipText {
-  display: inline-block;
   background-color: #30E60B;
   color: #003706;
   border-radius: 2px;
-  text-align: center;
+  padding: 4px;
   line-height: 13px;
-  font: 11px Regular;
+  font: 11px sans-serif;
   font-weight: 400;
+}
 
-  margin-left: auto;
-  margin-right: auto;
-  padding: 4px;
+/* our speech bubble tail */
+#copyLogTooltipText::after {
+  content: "";
+  position: absolute;
+  top: 100%;
+  left: 50%;
+  margin-left: -4px;
+  border-width: 4px;
+  border-style: solid;
+  border-color: #30E60B transparent transparent transparent;
 }
 
 body {
diff --git a/browser/components/torconnect/content/aboutTorConnect.js b/browser/components/torconnect/content/aboutTorConnect.js
index 5089bbc9363b..a88a887c7878 100644
--- a/browser/components/torconnect/content/aboutTorConnect.js
+++ b/browser/components/torconnect/content/aboutTorConnect.js
@@ -15,6 +15,10 @@ const TorLauncherPrefs = {
   prompt_at_startup: "extensions.torlauncher.prompt_at_startup",
 }
 
+const BrowserPrefs = {
+  homepage: "browser.startup.homepage",
+}
+
 class AboutTorConnect {
   log(...args) {
     console.log(...args);
@@ -40,6 +44,15 @@ class AboutTorConnect {
   get elemProgressMeter() {
     return this.getElem("progressBackground");
   }
+  get elemCopyLogLink() {
+    return this.getElem("copyLogLink");
+  }
+  get elemCopyLogTooltip() {
+    return this.getElem("copyLogTooltip");
+  }
+  get elemCopyLogTooltipText() {
+    return this.getElem("copyLogTooltipText");
+  }
   get elemQuickstartCheckbox() {
     return this.getElem("quickstartCheckbox");
   }
@@ -49,15 +62,6 @@ class AboutTorConnect {
   get elemConnectButton() {
     return this.getElem("connectButton");
   }
-  get elemCopyLogButton() {
-    return this.getElem("copyLogButton");
-  }
-  get elemCopyLogTooltip() {
-    return this.getElem("copyLogTooltip");
-  }
-  get elemCopyLogTooltipText() {
-    return this.getElem("copyLogTooltipText");
-  }
   get elemAdvancedButton() {
     return this.getElem("advancedButton");
   }
@@ -97,7 +101,7 @@ class AboutTorConnect {
       this.torStrings.settings.quickstartDescription;
     this.showElem(this.elemConnectButton);
     this.showElem(this.elemAdvancedButton);
-    this.hideElem(this.elemCopyLogButton);
+    this.hideElem(this.elemCopyLogLink);
     this.hideElem(this.elemCancelButton);
     this.hideElem(this.elemProgressContent);
     this.hideElem(this.elemProgressMeter);
@@ -108,7 +112,7 @@ class AboutTorConnect {
     this.setTitle(this.torStrings.torConnect.torConnecting);
     this.hideElem(this.elemConnectButton);
     this.hideElem(this.elemAdvancedButton);
-    this.hideElem(this.elemCopyLogButton);
+    this.hideElem(this.elemCopyLogLink);
     this.showElem(this.elemCancelButton);
     this.showElem(this.elemProgressContent);
     this.showElem(this.elemProgressMeter);
@@ -124,13 +128,14 @@ class AboutTorConnect {
     this.showElem(this.elemProgressContent);
     this.hideElem(this.elemProgressMeter);
     this.elemTitle.classList.add("error");
-
-    this.elem
   }
 
   goToBrowserHome() {
     this.hideElem(this.elemCancelButton);
-    RPMSendAsyncMessage("GoToBrowserHome");
+
+    // redirect this about:torconnect to browser homepage
+    const homepage = RPMGetStringPref(BrowserPrefs.homepage);
+    window.location.replace(homepage);
   }
 
   set state(state) {
@@ -163,10 +168,7 @@ class AboutTorConnect {
       }
     }
 
-    let haveErrorOrWarning =
-      (await RPMSendQuery("TorBootstrapErrorOccurred")) ||
-      (await RPMSendQuery("TorLogHasWarnOrErr"));
-    this.showCopyLogButton(haveErrorOrWarning);
+    this.showCopyLog();
     this.showElem(this.elemConnectButton);
   }
 
@@ -179,6 +181,11 @@ class AboutTorConnect {
   }
 
   async connect() {
+    // reset the text to original quickstart description
+    // in case we are trying again after an error (clears out error text)
+    this.elemProgressDesc.textContent =
+      this.torStrings.settings.quickstartDescription;
+
     this.state = AboutTorConnect.STATE_BOOTSTRAPPING;
     const error = await RPMSendQuery("TorConnect");
     if (error) {
@@ -189,12 +196,8 @@ class AboutTorConnect {
     }
   }
 
-  restoreCopyLogVisibility() {
-    this.elemCopyLogButton.setAttribute("hidden", true);
-  }
-
-  showCopyLogButton() {
-    this.elemCopyLogButton.removeAttribute("hidden");
+  showCopyLog() {
+    this.elemCopyLogLink.removeAttribute("hidden");
   }
 
   async updateBootstrapProgress(status) {
@@ -241,28 +244,10 @@ class AboutTorConnect {
       RPMSendAsyncMessage("OpenTorAdvancedPreferences");
     });
 
-    this.elemQuickstartLabel.textContent = this.torStrings.settings.quickstartCheckbox;
-    this.elemQuickstartCheckbox.addEventListener("change", () => {
-      const quickstart = this.elemQuickstartCheckbox.checked;
-      RPMSetBoolPref(TorLauncherPrefs.quickstart, quickstart);
-    });
-    this.elemQuickstartCheckbox.checked = await RPMGetBoolPref(TorLauncherPrefs.quickstart);
-
-    this.elemConnectButton.textContent =
-      this.torStrings.torConnect.torConnectButton;
-    this.elemConnectButton.addEventListener("click", () => {
-      this.connect();
-    });
-
-    this.elemCancelButton.textContent = this.torStrings.torConnect.cancel;
-    this.elemCancelButton.addEventListener("click", () => {
-      this.stopTorBootstrap();
-    });
-
     // sets the text content while keping the child elements intact
-    this.elemCopyLogButton.childNodes[0].nodeValue =
+    this.elemCopyLogLink.childNodes[0].nodeValue =
       this.torStrings.torConnect.copyLog;
-    this.elemCopyLogButton.addEventListener("click", async () => {
+    this.elemCopyLogLink.addEventListener("click", async (event) => {
       const copiedMessage = await RPMSendQuery("TorCopyLog");
       aboutTorConnect.elemCopyLogTooltipText.textContent = copiedMessage;
       aboutTorConnect.elemCopyLogTooltip.style.visibility = "visible";
@@ -279,16 +264,35 @@ class AboutTorConnect {
         aboutTorConnect.copyLogTimeoutId = 0;
       }, TOOLTIP_TIMEOUT);
     });
+
+
+    this.elemQuickstartLabel.textContent = this.torStrings.settings.quickstartCheckbox;
+    this.elemQuickstartCheckbox.addEventListener("change", () => {
+      const quickstart = this.elemQuickstartCheckbox.checked;
+      RPMSetBoolPref(TorLauncherPrefs.quickstart, quickstart);
+    });
+    this.elemQuickstartCheckbox.checked = await RPMGetBoolPref(TorLauncherPrefs.quickstart);
+
+    this.elemConnectButton.textContent =
+      this.torStrings.torConnect.torConnectButton;
+    this.elemConnectButton.addEventListener("click", () => {
+      this.connect();
+    });
+
+    this.elemCancelButton.textContent = this.torStrings.torConnect.cancel;
+    this.elemCancelButton.addEventListener("click", () => {
+      this.stopTorBootstrap();
+    });
   }
 
   initObservers() {
     RPMAddMessageListener(kTorBootstrapErrorTopic, ({ data }) => {
-      this.showCopyLogButton(true);
+      this.showCopyLog();
       this.stopTorBootstrap();
       this.showErrorMessage(data);
     });
     RPMAddMessageListener(kTorLogHasWarnOrErrTopic, () => {
-      this.showCopyLogButton(true);
+      this.showCopyLog();
     });
     RPMAddMessageListener(kTorProcessDidNotStartTopic, ({ data }) => {
       this.showErrorMessage(data);
diff --git a/browser/components/torconnect/content/aboutTorConnect.xhtml b/browser/components/torconnect/content/aboutTorConnect.xhtml
index d12c896c8959..0a0721afb7db 100644
--- a/browser/components/torconnect/content/aboutTorConnect.xhtml
+++ b/browser/components/torconnect/content/aboutTorConnect.xhtml
@@ -28,6 +28,14 @@
           </div>
         </div>
 
+        <div id="copyLogContainer">
+          <span id="copyLogLink" hidden="true">
+            <div id="copyLogTooltip">
+              <span id="copyLogTooltipText"/>
+            </div>
+          </span>
+        </div>
+
         <div id="quickstartContainer">
           <input id="quickstartCheckbox" type="checkbox" />
           <label id="quickstartCheckboxLabel" for="quickstartCheckbox"/>
@@ -35,11 +43,6 @@
 
         <div id="connectButtonContainer" class="button-container">
           <button id="advancedButton" hidden="true"></button>
-          <button id="copyLogButton" hidden="true">
-            <div id="copyLogTooltip">
-              <div id="copyLogTooltipText"></div>
-            </div>
-          </button>
           <button id="cancelButton" hidden="true"></button>
           <button id="connectButton" class="primary try-again" hidden="true"></button>
         </div>
diff --git a/browser/components/torconnect/content/torconnect-urlbar.css b/browser/components/torconnect/content/torconnect-urlbar.css
index 7331f3cd48df..db2f1069b22b 100644
--- a/browser/components/torconnect/content/torconnect-urlbar.css
+++ b/browser/components/torconnect/content/torconnect-urlbar.css
@@ -3,6 +3,7 @@
 */
 hbox.urlbar-page-action#torconnect-box {
     display: -moz-inline-box!important;
+    margin: 0 6px;
     height: 28px;
 }
 /* disable the button-like default css */
@@ -13,13 +14,14 @@ hbox.urlbar-page-action#torconnect-box:active {
 
 label#torconnect-label {
     line-height: 28px;
-    margin: 0 0.1em;
+    margin: 0;
     opacity: 0.6;
 }
 
 /* set appropriate sizes for the non-standard ui densities */
 :root[uidensity=compact] {
     hbox.urlbar-page-action#torconnect-box {
+        margin: 0 4px;
         height: 24px;
     }
     label#torconnect-label {
@@ -28,6 +30,7 @@ label#torconnect-label {
 }
 :root[uidensity=touch] {
     hbox.urlbar-page-action#torconnect-box {
+        margin: 0 7px;
         height: 30px;
     }
     label#torconnect-label {
@@ -53,3 +56,10 @@ hbox#urlbar-input-container[torconnect="offline"] + vbox.urlbarView,
 hbox#urlbar-input-container[torconnect="connecting"] + vbox.urlbarView {
     display: none!important;
 }
+
+/* hide search icon when we are not connected to tor */
+hbox#urlbar-input-container[torconnect="offline"] > #identity-box[pageproxystate="invalid"] > #identity-icon,
+hbox#urlbar-input-container[torconnect="connecting"] > #identity-box[pageproxystate="invalid"] > #identity-icon
+{
+    display: none!important;
+}
diff --git a/browser/components/torpreferences/content/torPane.js b/browser/components/torpreferences/content/torPane.js
index 63db876a7ccd..d63b31c4c6f6 100644
--- a/browser/components/torpreferences/content/torPane.js
+++ b/browser/components/torpreferences/content/torPane.js
@@ -189,7 +189,8 @@ const gTorPane = (function() {
       this._messageBoxButton.addEventListener("click", () => {
         TorProtocolService.connect();
         let win = Services.wm.getMostRecentWindow("navigator:browser");
-        win.switchToTabHavingURI("about:torconnect");
+        // switch to existing about:torconnect tab or create a new one
+        win.switchToTabHavingURI("about:torconnect", true);
       });
 
       let populateMessagebox = () => {
diff --git a/browser/components/urlbar/UrlbarInput.jsm b/browser/components/urlbar/UrlbarInput.jsm
index 13b1279105f2..f727c386701c 100644
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -10,6 +10,33 @@ const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 
+const { TorProtocolService } = ChromeUtils.import(
+  "resource:///modules/TorProtocolService.jsm"
+);
+
+// in certain scenarios we want user input uris to open in a new tab if they do so from the
+// about:torconnect tab 
+function maybeUpdateOpenLocationForTorConnect(openUILinkWhere, currentURI, destinationURI) {
+  try {
+    // only open in new tab if:
+    if (// user is navigating away from about:torconnect
+        currentURI === "about:torconnect" &&
+        // we are trying to open in same tab
+        openUILinkWhere === "current" &&
+        // only if user still has not bootstrapped
+        TorProtocolService.shouldShowTorConnect() &&
+        // and user is not just navigating to about:torconnect
+        destinationURI !== "about:torconnect") {
+      return "tab";
+    }
+  } catch (e) {
+    // swallow exception and fall through returning original so we don't accidentally break
+    // anything if an exception is thrown
+  }
+
+  return openUILinkWhere;
+};
+
 XPCOMUtils.defineLazyModuleGetters(this, {
   AppConstants: "resource://gre/modules/AppConstants.jsm",
   BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
@@ -1832,6 +1859,10 @@ class UrlbarInput {
     // area when the current tab is re-selected.
     browser.focus();
 
+    openUILinkWhere = maybeUpdateOpenLocationForTorConnect(
+                        openUILinkWhere,
+                        this.window.gBrowser.currentURI.asciiSpec,
+                        url);
     if (openUILinkWhere != "current") {
       this.handleRevert();
     }
diff --git a/toolkit/modules/RemotePageAccessManager.jsm b/toolkit/modules/RemotePageAccessManager.jsm
index ee21aa7a750f..0c001e707096 100644
--- a/toolkit/modules/RemotePageAccessManager.jsm
+++ b/toolkit/modules/RemotePageAccessManager.jsm
@@ -205,6 +205,9 @@ let RemotePageAccessManager = {
       RPMSetBoolPref: [
         "extensions.torlauncher.quickstart",
       ],
+      RPMGetStringPref: [
+        "browser.startup.homepage",
+      ],
     },
   },
 
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
index 195b3637ca78..6c8105939fcb 100644
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -2984,7 +2984,7 @@ bool fire_glxtest_process();
 class XREMain {
  public:
   XREMain()
-      : mStartOffline(false),
+      : mStartOffline(true),
         mShuttingDown(false)
 #ifdef MOZ_HAS_REMOTE
         ,
@@ -3588,6 +3588,11 @@ int XREMain::XRE_mainInit(bool* aExitFlag) {
   CheckArg("new-instance");
 #endif
 
+  // revert to start online behaviour when using the legacy tor launcher
+  if (EnvHasValue("TOR_USE_LEGACY_LAUNCHER")) {
+    mStartOffline = false;
+  }
+
   ar = CheckArg("offline");
   if (ar || EnvHasValue("XRE_START_OFFLINE")) {
     mStartOffline = true;





More information about the tor-commits mailing list