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