commit d27a43d5986ff72c28d1380a4622eab594395085
Author: Richard Pospesel <richard(a)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;