lists.torproject.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

tbb-commits

Thread Start a new thread
Download
Threads by month
  • ----- 2025 -----
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2021 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2020 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2019 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2018 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2017 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2016 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2015 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2014 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
tbb-commits@lists.torproject.org

September 2021

  • 3 participants
  • 399 discussions
[tor-browser/tor-browser-78.14.0esr-10.5-1] Bug 40416: Add v2 Onion deprecation warnings
by sysrqb@torproject.org 04 Sep '21

04 Sep '21
commit bce42cd48208e2e85c803b0fc316c47228ade5f2 Author: Richard Pospesel <richard(a)torproject.org> Date: Fri May 21 22:18:23 2021 +0200 Bug 40416: Add v2 Onion deprecation warnings - adds new v2 deprecated warning page (js and styling) that piggy-backs off of the existing added onion service errors - updates identity-icon to onionWarning.svg when visiting a v2 onion site adds warning tooltip; this warning supersedes all other identity states (including mixed-content error) - we determine whether to show the warning page in nsDocShell::DoURILoad() - a new synchonous IPC method is added to ContentChild/ContentParent to determine if the session has loaded the warning page already; worst case scenario, each child process will need to wait on this method to return only once when visiting a v2 onion; nothing is permanently cached with regards to this change - an exception for the new sync method is added to sync-messages.ini (generally, in practice adding new blocking methods is probably bad, but the minimial overhead and frequency this method is called is worth the simpler code) --- browser/base/content/aboutNetError.xhtml | 3 ++ browser/base/content/browser-siteIdentity.js | 12 +++++ browser/base/jar.mn | 2 +- .../content/netError/onionNetError.js | 6 +++ .../content/netError/v2Deprecated.css | 25 +++++++++ .../onionservices/content/netError/v2Deprecated.js | 50 ++++++++++++++++++ browser/components/onionservices/jar.mn | 8 ++- browser/modules/TorStrings.jsm | 8 +++ .../shared/identity-block/identity-block.inc.css | 3 +- browser/themes/shared/onionPattern.inc.xhtml | 4 +- docshell/base/nsDocShell.cpp | 61 ++++++++++++++++++++++ dom/ipc/ContentParent.cpp | 11 ++++ dom/ipc/ContentParent.h | 2 + dom/ipc/PContent.ipdl | 3 ++ ipc/ipdl/sync-messages.ini | 3 ++ js/xpconnect/src/xpc.msg | 1 + xpcom/base/ErrorList.py | 2 + 17 files changed, 200 insertions(+), 4 deletions(-) diff --git a/browser/base/content/aboutNetError.xhtml b/browser/base/content/aboutNetError.xhtml index 957b6f15a0be..4572eb2024f1 100644 --- a/browser/base/content/aboutNetError.xhtml +++ b/browser/base/content/aboutNetError.xhtml @@ -207,7 +207,10 @@ </div> </div> </div> +<!-- The onion pattern is disabled by default unless the onionPattern.css is also included; we include onionPattern.css programmatically in the v2Deprecation error page, so the onion pattern will not be visible in all error pages --> +#include ../../themes/shared/onionPattern.inc.xhtml </body> + <script src="chrome://browser/content/onionservices/netError/v2Deprecated.js"/> <script src="chrome://browser/content/onionservices/netError/onionNetError.js"/> <script src="chrome://browser/content/aboutNetError.js"/> </html> diff --git a/browser/base/content/browser-siteIdentity.js b/browser/base/content/browser-siteIdentity.js index 2a3431172886..27fee74cba5b 100644 --- a/browser/base/content/browser-siteIdentity.js +++ b/browser/base/content/browser-siteIdentity.js @@ -135,6 +135,15 @@ var gIdentityHandler = { return this._uriHasHost ? this._uri.host.toLowerCase().endsWith(".onion") : false; }, + get _uriIsDeprecatedOnionHost() { + const hostIsV2Onion = function(host) { + // matches on v2 onion domains with any number of subdomains + const pattern = /^(.*\.)*[a-z2-7]{16}\.onion/i; + return pattern.test(host); + }; + + return this._uriHasHost ? hostIsV2Onion(this._uri.host) : false; + }, // smart getters get _identityPopup() { delete this._identityPopup; @@ -685,6 +694,9 @@ var gIdentityHandler = { "identity.extension.label", [extensionName] ); + } else if (this._uriIsDeprecatedOnionHost) { + this._identityBox.className = "onionServiceDeprecated"; + tooltip = TorStrings.onionServices.v2Deprecated.tooltip; } else if (this._uriHasHost && this._isSecureConnection && this._secInfo) { // This is a secure connection. // _isSecureConnection implicitly includes onion services, which may not have an SSL certificate diff --git a/browser/base/jar.mn b/browser/base/jar.mn index df65349796b5..21b07ad9511b 100644 --- a/browser/base/jar.mn +++ b/browser/base/jar.mn @@ -22,7 +22,7 @@ browser.jar: content/browser/logos/send.svg (content/logos/send.svg) content/browser/logos/tracking-protection.svg (content/logos/tracking-protection.svg) content/browser/logos/tracking-protection-dark-theme.svg (content/logos/tracking-protection-dark-theme.svg) - content/browser/aboutNetError.xhtml (content/aboutNetError.xhtml) +* content/browser/aboutNetError.xhtml (content/aboutNetError.xhtml) content/browser/aboutNetError.js (content/aboutNetError.js) content/browser/aboutRobots-icon.png (content/aboutRobots-icon.png) content/browser/aboutFrameCrashed.html (content/aboutFrameCrashed.html) diff --git a/browser/components/onionservices/content/netError/onionNetError.js b/browser/components/onionservices/content/netError/onionNetError.js index 8fabb3f38eb7..254e50bab4a3 100644 --- a/browser/components/onionservices/content/netError/onionNetError.js +++ b/browser/components/onionservices/content/netError/onionNetError.js @@ -38,6 +38,12 @@ var OnionServicesAboutNetError = { const errPrefix = "onionServices."; const errName = err.substring(errPrefix.length); + // tor-browser#40416 - remove this page and updated onionNetErrors with new error once v2 no longer works at all + if (errName === "v2Deprecated") { + V2DeprecatedAboutNetError.initPage(aDoc); + return; + } + this._strings = RPMGetTorStrings(); const stringsObj = this._strings[errName]; diff --git a/browser/components/onionservices/content/netError/v2Deprecated.css b/browser/components/onionservices/content/netError/v2Deprecated.css new file mode 100644 index 000000000000..890468d09761 --- /dev/null +++ b/browser/components/onionservices/content/netError/v2Deprecated.css @@ -0,0 +1,25 @@ +%include ../../../../themes/shared/onionPattern.css + +:root { + --onion-opacity: 1; + --onion-color: var(--card-outline-color); + --onion-radius: 50px; +} + +body { + border: 1.5em solid #FED916; + justify-content: space-between; +} + +div.title { + background-image: url("chrome://browser/skin/onion-warning.svg"); +} + +div#errorPageContainer { + padding-top: 20vh; + width: 66%; +} + +div#learnMoreContainer { + display: block; +} \ No newline at end of file diff --git a/browser/components/onionservices/content/netError/v2Deprecated.js b/browser/components/onionservices/content/netError/v2Deprecated.js new file mode 100644 index 000000000000..195bc187791c --- /dev/null +++ b/browser/components/onionservices/content/netError/v2Deprecated.js @@ -0,0 +1,50 @@ +// Copyright (c) 2021, The Tor Project, Inc. + +"use strict"; + +/* eslint-env mozilla/frame-script */ + +var V2DeprecatedAboutNetError = { + + _selector: { + header: ".title-text", + longDesc: "#errorLongDesc", + learnMoreLink: "#learnMoreLink", + contentContainer: "#errorLongContent", + tryAgainButton: "div#netErrorButtonContainer button.try-again", + }, + + initPage(aDoc) { + this._insertStylesheet(aDoc); + this._populateStrings(aDoc); + }, + + _populateStrings(aDoc) { + // populate strings + const TorStrings = RPMGetTorStrings(); + + aDoc.title = TorStrings.v2Deprecated.pageTitle; + + let headerElem = aDoc.querySelector(this._selector.header); + headerElem.textContent = TorStrings.v2Deprecated.header; + + let longDescriptionElem = aDoc.querySelector(this._selector.longDesc); + longDescriptionElem.textContent = TorStrings.v2Deprecated.longDescription; + + let learnMoreElem = aDoc.querySelector(this._selector.learnMoreLink); + learnMoreElem.setAttribute("href", TorStrings.v2Deprecated.learnMoreURL); + + let tryAgainElem = aDoc.querySelector(this._selector.tryAgainButton); + tryAgainElem.textContent = TorStrings.v2Deprecated.tryAgain; + }, + + _insertStylesheet(aDoc) { + const url = + "chrome://browser/content/onionservices/netError/v2Deprecated.css"; + let linkElem = aDoc.createElement("link"); + linkElem.rel = "stylesheet"; + linkElem.href = url; + linkElem.type = "text/css"; + aDoc.head.appendChild(linkElem); + }, +}; diff --git a/browser/components/onionservices/jar.mn b/browser/components/onionservices/jar.mn index f45b16dc5d29..73258bd9c501 100644 --- a/browser/components/onionservices/jar.mn +++ b/browser/components/onionservices/jar.mn @@ -3,7 +3,13 @@ browser.jar: content/browser/onionservices/authPreferences.js (content/authPreferences.js) content/browser/onionservices/authPrompt.js (content/authPrompt.js) content/browser/onionservices/authUtil.jsm (content/authUtil.jsm) - content/browser/onionservices/netError/ (content/netError/*) + content/browser/onionservices/netError/browser.svg (content/netError/browser.svg) + content/browser/onionservices/netError/network.svg (content/netError/network.svg) + content/browser/onionservices/netError/onionNetError.css (content/netError/onionNetError.css) + content/browser/onionservices/netError/onionNetError.js (content/netError/onionNetError.js) + content/browser/onionservices/netError/onionsite.svg (content/netError/onionsite.svg) +* content/browser/onionservices/netError/v2Deprecated.css (content/netError/v2Deprecated.css) + content/browser/onionservices/netError/v2Deprecated.js (content/netError/v2Deprecated.js) content/browser/onionservices/onionservices.css (content/onionservices.css) content/browser/onionservices/savedKeysDialog.js (content/savedKeysDialog.js) content/browser/onionservices/savedKeysDialog.xhtml (content/savedKeysDialog.xhtml) diff --git a/browser/modules/TorStrings.jsm b/browser/modules/TorStrings.jsm index c086d0fe3117..6eeb2ea06a04 100644 --- a/browser/modules/TorStrings.jsm +++ b/browser/modules/TorStrings.jsm @@ -502,6 +502,14 @@ var TorStrings = { header: getString("introTimedOut.header", "Onionsite Circuit Creation Timed Out"), longDescription: getString("introTimedOut.longDescription", kLongDescFallback), }, + v2Deprecated: { // Deprecation page for v2 Onions + pageTitle: getString("v2Deprecated.pageTitle", "V2 Onion Site Deprecation Warning"), + header: getString("v2Deprecated.header", "Version 2 Onion Sites will be deprecated soon"), + longDescription: getString("v2Deprecated.longDescription", "Tor is ending its support for version 2 onion services beginning in July 2021, and this onion site will no longer be reachable at this address. If you are the site administrator, upgrade to a version 3 onion service soon."), + learnMoreURL: `https://support.torproject.org/${getLocale()}/onionservices/#v2-deprecation`, + tryAgain: getString("v2Deprecated.tryAgain", "Got it"), + tooltip: getString("v2Deprecated.tooltip", "This onion site will not be reachable soon"), + }, authPrompt: { description: getString("authPrompt.description2", "%S is requesting that you authenticate."), diff --git a/browser/themes/shared/identity-block/identity-block.inc.css b/browser/themes/shared/identity-block/identity-block.inc.css index 011fb9f3081c..936ab00d2080 100644 --- a/browser/themes/shared/identity-block/identity-block.inc.css +++ b/browser/themes/shared/identity-block/identity-block.inc.css @@ -181,7 +181,8 @@ toolbar[brighttext] #identity-box[pageproxystate="valid"].chromeUI > #identity-i #identity-box[pageproxystate="valid"].onionMixedDisplayContent > #identity-icon, #identity-box[pageproxystate="valid"].onionMixedDisplayContentLoadedActiveBlocked > #identity-icon, -#identity-box[pageproxystate="valid"].onionCertUserOverridden > #identity-icon { +#identity-box[pageproxystate="valid"].onionCertUserOverridden > #identity-icon, +#identity-box[pageproxystate="valid"].onionServiceDeprecated > #identity-icon { list-style-image: url(chrome://browser/skin/onion-warning.svg); visibility: visible; } diff --git a/browser/themes/shared/onionPattern.inc.xhtml b/browser/themes/shared/onionPattern.inc.xhtml index 6bbde93684a2..0b6b8b072f9a 100644 --- a/browser/themes/shared/onionPattern.inc.xhtml +++ b/browser/themes/shared/onionPattern.inc.xhtml @@ -9,9 +9,11 @@ - most browser windows, typically the two rows of onions will fill the - bottom of the page. On really wide pages, the onions are centered at - the bottom of the page. + - The root onion-pattern-container div is hidden by default, and can be + - enabled by including onionPattern.css --> -<div class="onion-pattern-container"> +<div class="onion-pattern-container" style="display: none"> <!-- for some reason, these two elements are focusable, seems related to - flex css somehow; disable their tabindex to fix --> diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index bf9639c82612..0f315f2f87b4 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -7,6 +7,7 @@ #include "nsDocShell.h" #include <algorithm> +#include <regex> #ifdef XP_WIN # include <process.h> @@ -3645,6 +3646,9 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI, case NS_ERROR_TOR_ONION_SVC_INTRO_TIMEDOUT: error = "onionServices.introTimedOut"; break; + case NS_ERROR_TOR_ONION_SVC_V2_DEPRECATED: + error = "onionServices.v2Deprecated"; + break; default: break; } @@ -9596,6 +9600,63 @@ nsresult nsDocShell::DoURILoad(nsDocShellLoadState* aLoadState, return NS_OK; } + // tor-browser#40416 + // we only ever want to show the warning page once per session + const auto shouldShouldShowV2DeprecationPage = []() -> bool { + bool retval = false; + if (XRE_IsContentProcess()) { + auto* cc = ContentChild::GetSingleton(); + cc->SendShouldShowV2DeprecationPage(&retval); + } + return retval; + }; + + const auto uriIsV2Onion = [](nsIURI* uri) -> bool { + if (uri) { + nsAutoCString hostString; + uri->GetHost(hostString); + + const std::string_view host(hostString.BeginReading(), hostString.Length()); + + // matches v2 onions with any number of subdomains + const static std::regex v2OnionPattern{ + "^(.*\\.)*[a-z2-7]{16}\\.onion", + std::regex::icase | std::regex::optimize + }; + + // see if the uri refers to v2 onion host + return std::regex_match( + host.begin(), + host.end(), + v2OnionPattern); + } + return false; + }; + + // only dip in here if this process thinks onion warning page has not been shown + static bool v2DeprecationPageShown = false; + if (!v2DeprecationPageShown) { + // now only advance if the URI we are dealing with + // is a v2 onion address + auto uri = aLoadState->URI(); + if (uriIsV2Onion(uri)) { + // Ok, so we are dealing with a v2 onion, now make + // sure the v2 deprecation page has not been shown in + // in another content process + // + // This is a synchrynous call, so we are blocking until + // we hear back from from the parent process. Each child + // process will need to perform this wait at most once, + // since we are locally caching in v2DeprecationPageShown. + v2DeprecationPageShown = true; + if (shouldShouldShowV2DeprecationPage()) { + DisplayLoadError(NS_ERROR_TOR_ONION_SVC_V2_DEPRECATED, uri, nullptr, nullptr); + return NS_ERROR_LOAD_SHOWED_ERRORPAGE; + } + } + } + + nsCOMPtr<nsIURILoader> uriLoader = components::URILoader::Service(); if (NS_WARN_IF(!uriLoader)) { return NS_ERROR_UNEXPECTED; diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 4269016ec5d5..9c1c1fddf9e9 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -6515,6 +6515,17 @@ NS_IMETHODIMP ContentParent::GetActor(const nsACString& aName, return NS_OK; } +mozilla::ipc::IPCResult ContentParent::RecvShouldShowV2DeprecationPage(bool* showPage) { + static bool v2DeprecationPageShown = false; + if (v2DeprecationPageShown) { + *showPage = false; + } else { + *showPage = true; + v2DeprecationPageShown = true; + } + return IPC_OK(); +} + } // namespace dom } // namespace mozilla diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 4f10832d8e23..83f9caa1dc6c 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -1280,6 +1280,8 @@ class ContentParent final const MaybeDiscarded<BrowsingContext>& aContext, int32_t aOffset, HistoryGoResolver&& aResolveRequestedIndex); + mozilla::ipc::IPCResult RecvShouldShowV2DeprecationPage(bool* showPage); + // Notify the ContentChild to enable the input event prioritization when // initializing. void MaybeEnableRemoteInputEventQueue(); diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index c4dd750e47a4..09d053c69738 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -1678,6 +1678,9 @@ child: // WindowContext is managed using the PWindowGlobal actor's lifecycle. async CreateWindowContext(WindowContextInitializer aInit); async DiscardWindowContext(uint64_t aContextId) returns (bool unused); + +parent: + sync ShouldShowV2DeprecationPage() returns (bool showPage); }; } diff --git a/ipc/ipdl/sync-messages.ini b/ipc/ipdl/sync-messages.ini index 88ad49d169e8..df2acb04c750 100644 --- a/ipc/ipdl/sync-messages.ini +++ b/ipc/ipdl/sync-messages.ini @@ -1040,6 +1040,9 @@ description = Initialization of WebGL contexts is synchronous by spec. description = Synchronous RPC to allow WebGL to run graphics commands in compositor process and return results to be used in JS return values. [PSocketProcess::GetTLSClientCert] description = Synchronously get client certificate and key from parent process. Once bug 696976 has been fixed, this can be removed. +[PContent::ShouldShowV2DeprecationPage] +description = Synchronously determine whether a client process has already displayed the v2 onion deprecation warning page + ############################################################# # AVOID ADDING NEW MESSAGES TO THIS FILE # diff --git a/js/xpconnect/src/xpc.msg b/js/xpconnect/src/xpc.msg index 31e5e75ba35c..7c8cc9ef181c 100644 --- a/js/xpconnect/src/xpc.msg +++ b/js/xpconnect/src/xpc.msg @@ -262,6 +262,7 @@ XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_MISSING_CLIENT_AUTH, "Tor onion service missi XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_BAD_CLIENT_AUTH , "Tor onion service wrong client authorization") XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_BAD_ADDRESS , "Tor onion service bad address") XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_INTRO_TIMEDOUT , "Tor onion service introduction timed out") +XPC_MSG_DEF(NS_ERROR_TOR_ONION_SVC_V2_DEPRECATED , "Tor v2 onion services are deprecated") /* Profile manager error codes */ XPC_MSG_DEF(NS_ERROR_DATABASE_CHANGED , "Flushing the profiles to disk would have overwritten changes made elsewhere.") diff --git a/xpcom/base/ErrorList.py b/xpcom/base/ErrorList.py index 5f35cf7771f9..6bcd65f9bca9 100755 --- a/xpcom/base/ErrorList.py +++ b/xpcom/base/ErrorList.py @@ -1200,6 +1200,8 @@ with modules["TOR"]: errors["NS_ERROR_TOR_ONION_SVC_BAD_ADDRESS"] = FAILURE(7) # Tor onion service introduction timed out. errors["NS_ERROR_TOR_ONION_SVC_INTRO_TIMEDOUT"] = FAILURE(8) + # Tor v2 onion services are deprecated + errors["NS_ERROR_TOR_ONION_SVC_V2_DEPRECATED"] = FAILURE(9) # ======================================================================= # 51: NS_ERROR_MODULE_GENERAL
1 0
0 0
[tor-browser/tor-browser-78.14.0esr-10.5-1] Bug 1719146 - Use size_t in breakpad's Linux exception handler. r=gsvelto
by sysrqb@torproject.org 04 Sep '21

04 Sep '21
commit 2876765509423fd9499567bc920e102ceeb07279 Author: Emilio Cobos Álvarez <emilio(a)crisal.io> Date: Mon Jul 5 11:59:34 2021 +0000 Bug 1719146 - Use size_t in breakpad's Linux exception handler. r=gsvelto Differential Revision: https://phabricator.services.mozilla.com/D119083 --- .../crashreporter/breakpad-client/linux/handler/exception_handler.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.cc b/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.cc index c8509c2d5363..1365935ba51c 100644 --- a/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.cc +++ b/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.cc @@ -145,7 +145,7 @@ void InstallAlternateStackLocked() { // SIGSTKSZ may be too small to prevent the signal handlers from overrunning // the alternative stack. Ensure that the size of the alternative stack is // large enough. - static const unsigned kSigStackSize = std::max(16384, SIGSTKSZ); + static const size_t kSigStackSize = std::max(size_t(16384), size_t(SIGSTKSZ)); // Only set an alternative stack if there isn't already one, or if the current // one is too small.
1 0
0 0
[tor-browser/tor-browser-78.14.0esr-10.5-1] Bug 27476: Implement about:torconnect captive portal within Tor Browser
by sysrqb@torproject.org 04 Sep '21

04 Sep '21
commit 89eda798a60a55bb2d64a9011f0b03415470c5bb Author: Richard Pospesel <richard(a)torproject.org> Date: Wed Apr 28 23:09:34 2021 -0500 Bug 27476: Implement about:torconnect captive portal within Tor Browser - implements new about:torconnect page as tor-launcher replacement - adds tor connection status to url bar and tweaks UX when not online - adds new torconnect component to browser - tor process management functionality remains implemented in tor-launcher through the TorProtocolService module - the onion pattern from about:tor migrated to an .inc.xhtml file now used by both about:tor and about:torconnect - various design tweaks and resusability fixes to onion pattern - adds warning/error box to about:preferences#tor when not connected to tor - explicitly allows about:torconnect URIs to ignore Resist Fingerprinting (RFP) - various tweaks to info-pages.inc.css for about:torconnect (also affects other firefox info pages) --- browser/actors/NetErrorParent.jsm | 8 + browser/base/content/aboutNetError.js | 10 +- browser/base/content/browser-siteIdentity.js | 2 +- browser/base/content/browser.js | 10 + browser/base/content/browser.xhtml | 2 + browser/components/BrowserGlue.jsm | 59 +++- browser/components/about/AboutRedirector.cpp | 4 + browser/components/about/components.conf | 1 + browser/components/moz.build | 1 + .../onionservices/HttpsEverywhereControl.jsm | 17 +- browser/components/sessionstore/SessionStore.jsm | 16 + browser/components/torconnect/TorConnectChild.jsm | 9 + browser/components/torconnect/TorConnectParent.jsm | 126 ++++++++ .../torconnect/content/aboutTorConnect.css | 151 +++++++++ .../torconnect/content/aboutTorConnect.js | 339 +++++++++++++++++++++ .../torconnect/content/aboutTorConnect.xhtml | 54 ++++ .../components/torconnect/content/onion-slash.svg | 7 + browser/components/torconnect/content/onion.svg | 3 + .../torconnect/content/torBootstrapUrlbar.js | 136 +++++++++ .../torconnect/content/torconnect-urlbar.css | 65 ++++ .../torconnect/content/torconnect-urlbar.inc.xhtml | 11 + browser/components/torconnect/jar.mn | 7 + browser/components/torconnect/moz.build | 6 + .../components/torpreferences/content/torPane.js | 86 ++++++ .../torpreferences/content/torPane.xhtml | 34 +++ .../torpreferences/content/torPreferences.css | 121 ++++++++ browser/components/urlbar/UrlbarInput.jsm | 31 ++ browser/modules/TorConnect.jsm | 62 ++++ browser/modules/TorProcessService.jsm | 12 + browser/modules/TorProtocolService.jsm | 124 +++++++- browser/modules/TorStrings.jsm | 75 +++++ browser/modules/moz.build | 2 + browser/themes/shared/jar.inc.mn | 1 + browser/themes/shared/onionPattern.css | 124 ++++++++ browser/themes/shared/onionPattern.inc.xhtml | 210 +++++++++++++ browser/themes/shared/urlbar-searchbar.inc.css | 2 + dom/base/Document.cpp | 51 +++- dom/base/nsGlobalWindowOuter.cpp | 2 + toolkit/modules/AsyncPrefs.jsm | 2 + toolkit/modules/RemotePageAccessManager.jsm | 26 ++ toolkit/mozapps/update/UpdateService.jsm | 68 ++++- .../themes/shared/in-content/info-pages.inc.css | 15 +- .../lib/environments/browser-window.js | 4 + 43 files changed, 2080 insertions(+), 16 deletions(-) diff --git a/browser/actors/NetErrorParent.jsm b/browser/actors/NetErrorParent.jsm index 035195391554..fa3cbf23fcb7 100644 --- a/browser/actors/NetErrorParent.jsm +++ b/browser/actors/NetErrorParent.jsm @@ -17,6 +17,10 @@ const { SessionStore } = ChromeUtils.import( ); const { HomePage } = ChromeUtils.import("resource:///modules/HomePage.jsm"); +const { TorProtocolService } = ChromeUtils.import( + "resource:///modules/TorProtocolService.jsm" +); + const PREF_SSL_IMPACT_ROOTS = [ "security.tls.version.", "security.ssl3.", @@ -318,6 +322,10 @@ class NetErrorParent extends JSWindowActorParent { break; } } + break; + case "ShouldShowTorConnect": + return TorProtocolService.shouldShowTorConnect(); } + return undefined; } } diff --git a/browser/base/content/aboutNetError.js b/browser/base/content/aboutNetError.js index 60db17f46eb9..6844154e16e3 100644 --- a/browser/base/content/aboutNetError.js +++ b/browser/base/content/aboutNetError.js @@ -194,8 +194,16 @@ async function setErrorPageStrings(err) { document.l10n.setAttributes(titleElement, title); } -function initPage() { +async function initPage() { var err = getErrorCode(); + + // proxyConnectFailure because no-tor running daemon would return this error + if ( + (err === "proxyConnectFailure") && + (await RPMSendQuery("ShouldShowTorConnect")) + ) { + document.location.replace("about:torconnect"); + } // List of error pages with an illustration. let illustratedErrors = [ "malformedURI", diff --git a/browser/base/content/browser-siteIdentity.js b/browser/base/content/browser-siteIdentity.js index 539d6d4056a3..2a3431172886 100644 --- a/browser/base/content/browser-siteIdentity.js +++ b/browser/base/content/browser-siteIdentity.js @@ -57,7 +57,7 @@ var gIdentityHandler = { * RegExp used to decide if an about url should be shown as being part of * the browser UI. */ - _secureInternalUIWhitelist: (AppConstants.TOR_BROWSER_UPDATE ? /^(?:accounts|addons|cache|certificate|config|crashes|downloads|license|logins|preferences|protections|rights|sessionrestore|support|welcomeback|tor|tbupdate)(?:[?#]|$)/i : /^(?:accounts|addons|cache|certificate|config|crashes|downloads|license|logins|preferences|protections|rights|sessionrestore|support|welcomeback|tor)(?:[?#]|$)/i), + _secureInternalUIWhitelist: (AppConstants.TOR_BROWSER_UPDATE ? /^(?:accounts|addons|cache|certificate|config|crashes|downloads|license|logins|preferences|protections|rights|sessionrestore|support|welcomeback|tor|torconnect|tbupdate)(?:[?#]|$)/i : /^(?:accounts|addons|cache|certificate|config|crashes|downloads|license|logins|preferences|protections|rights|sessionrestore|support|welcomeback|tor|torconnect)(?:[?#]|$)/i), /** * Whether the established HTTPS connection is considered "broken". diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 04f8752b93f4..916cd69320cb 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -77,6 +77,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { TabModalPrompt: "chrome://global/content/tabprompts.jsm", TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm", TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.jsm", + TorProtocolService: "resource:///modules/TorProtocolService.jsm", Translation: "resource:///modules/translation/TranslationParent.jsm", OnionAliasStore: "resource:///modules/OnionAliasStore.jsm", UITour: "resource:///modules/UITour.jsm", @@ -633,6 +634,7 @@ var gPageIcons = { var gInitialPages = [ "about:tor", + "about:torconnect", "about:blank", "about:newtab", "about:home", @@ -1959,6 +1961,8 @@ var gBrowserInit = { } this._loadHandled = true; + + TorBootstrapUrlbar.init(); }, _cancelDelayedStartup() { @@ -2490,6 +2494,10 @@ var gBrowserInit = { let uri = window.arguments[0]; let defaultArgs = BrowserHandler.defaultArgs; + if (TorProtocolService.shouldShowTorConnect()) { + return "about:torconnect"; + } + // If the given URI is different from the homepage, we want to load it. if (uri != defaultArgs) { AboutNewTab.noteNonDefaultStartup(); @@ -2582,6 +2590,8 @@ var gBrowserInit = { OnionAuthPrompt.uninit(); + TorBootstrapUrlbar.uninit(); + gAccessibilityServiceIndicator.uninit(); AccessibilityRefreshBlocker.uninit(); diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml index c2caecc1a416..032db1967c69 100644 --- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -112,6 +112,7 @@ Services.scriptloader.loadSubScript("chrome://browser/content/search/searchbar.js", this); Services.scriptloader.loadSubScript("chrome://torbutton/content/tor-circuit-display.js", this); Services.scriptloader.loadSubScript("chrome://torbutton/content/torbutton.js", this); + Services.scriptloader.loadSubScript("chrome://browser/content/torconnect/torBootstrapUrlbar.js", this); window.onload = gBrowserInit.onLoad.bind(gBrowserInit); window.onunload = gBrowserInit.onUnload.bind(gBrowserInit); @@ -1055,6 +1056,7 @@ data-l10n-id="urlbar-go-button"/> <hbox id="page-action-buttons" context="pageActionContextMenu"> <toolbartabstop/> +#include ../../components/torconnect/content/torconnect-urlbar.inc.xhtml <hbox id="contextual-feature-recommendation" role="button" hidden="true"> <hbox id="cfr-label-container"> <label id="cfr-label"/> diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index 5f708fca3d5c..8735783cee2b 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -17,6 +17,31 @@ const { AppConstants } = ChromeUtils.import( "resource://gre/modules/AppConstants.jsm" ); +// TorProtocolService and TorConnect modules need to be lazily-loaded +// here because they will trigger generation of the random password used +// to talk to the tor daemon in tor-launcher. Generating the random +// password will initialize the cryptographic service ( nsNSSComponent ) +// +// If this service is init'd before the profile has been setup, it will +// use the fallback init path which behaves as if security.nocertdb=true +// +// We make these module getters so init happens when they are needed +// (when init'ing the OnionAliasStore). With theze getters, the password +// generation is triggered in torbutton after the 'profile-after-change' +// topic (so after the profile is initialized) + +ChromeUtils.defineModuleGetter( + this, + "TorProtocolService", + "resource:///modules/TorProtocolService.jsm" +); + +ChromeUtils.defineModuleGetter( + this, + "TorConnect", + "resource:///modules/TorConnect.jsm" +); + ChromeUtils.defineModuleGetter( this, "ActorManagerParent", @@ -503,6 +528,20 @@ let JSWINDOWACTORS = { allFrames: true, }, + TorConnect: { + parent: { + moduleURI: "resource:///modules/TorConnectParent.jsm", + }, + child: { + moduleURI: "resource:///modules/TorConnectChild.jsm", + events: { + DOMWindowCreated: {}, + }, + }, + + matches: ["about:torconnect"], + }, + Translation: { parent: { moduleURI: "resource:///modules/translation/TranslationParent.jsm", @@ -2492,7 +2531,25 @@ BrowserGlue.prototype = { { task: () => { - OnionAliasStore.init(); + if (TorProtocolService.isBootstrapDone() || !TorProtocolService.ownsTorDaemon) { + // we will take this path when the user is using the legacy tor launcher or + // when Tor Browser didn't launch its own tor. + OnionAliasStore.init(); + } else { + // this path is taken when using about:torconnect, we wait to init + // after we are bootstrapped and connected to tor + const topic = "torconnect:bootstrap-complete"; + let bootstrapObserver = { + observe(aSubject, aTopic, aData) { + if (aTopic === topic) { + OnionAliasStore.init(); + // we only need to init once, so remove ourselves as an obvserver + Services.obs.removeObserver(this, topic); + } + } + }; + Services.obs.addObserver(bootstrapObserver, topic); + } }, }, diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp index e7c377d655e7..db5f3ead4bb8 100644 --- a/browser/components/about/AboutRedirector.cpp +++ b/browser/components/about/AboutRedirector.cpp @@ -120,6 +120,10 @@ static const RedirEntry kRedirMap[] = { nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT}, #endif + {"torconnect", "chrome://browser/content/torconnect/aboutTorConnect.xhtml", + nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | + nsIAboutModule::URI_CAN_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT | + nsIAboutModule::HIDE_FROM_ABOUTABOUT}, }; static nsAutoCString GetAboutModuleName(nsIURI* aURI) { diff --git a/browser/components/about/components.conf b/browser/components/about/components.conf index 8e04467c05da..01c99ad4ed0c 100644 --- a/browser/components/about/components.conf +++ b/browser/components/about/components.conf @@ -26,6 +26,7 @@ pages = [ 'robots', 'sessionrestore', 'tabcrashed', + 'torconnect', 'welcome', 'welcomeback', ] diff --git a/browser/components/moz.build b/browser/components/moz.build index b660be047b14..fb90c499c616 100644 --- a/browser/components/moz.build +++ b/browser/components/moz.build @@ -59,6 +59,7 @@ DIRS += [ 'syncedtabs', 'uitour', 'urlbar', + 'torconnect', 'torpreferences', 'translation', ] diff --git a/browser/components/onionservices/HttpsEverywhereControl.jsm b/browser/components/onionservices/HttpsEverywhereControl.jsm index 525ed5233be7..d673de4cd6e5 100644 --- a/browser/components/onionservices/HttpsEverywhereControl.jsm +++ b/browser/components/onionservices/HttpsEverywhereControl.jsm @@ -41,6 +41,7 @@ const SECUREDROP_TOR_ONION_CHANNEL = { class HttpsEverywhereControl { constructor() { this._extensionMessaging = null; + this._init(); } async _sendMessage(type, object) { @@ -61,7 +62,6 @@ class HttpsEverywhereControl { * Installs the .tor.onion update channel in https-everywhere */ async installTorOnionUpdateChannel(retries = 5) { - this._init(); // TODO: https-everywhere store is initialized asynchronously, so sending a message // immediately results in a `store.get is undefined` error. @@ -143,5 +143,20 @@ class HttpsEverywhereControl { if (!this._extensionMessaging) { this._extensionMessaging = new ExtensionMessaging(); } + + // update all of the existing https-everywhere channels + setTimeout(async () => { + let pinnedChannels = await this._sendMessage("get_pinned_update_channels"); + for(let channel of pinnedChannels.update_channels) { + this._sendMessage("update_update_channel", channel); + } + + let storedChannels = await this._sendMessage("get_stored_update_channels"); + for(let channel of storedChannels.update_channels) { + this._sendMessage("update_update_channel", channel); + } + }, 0); + + } } diff --git a/browser/components/sessionstore/SessionStore.jsm b/browser/components/sessionstore/SessionStore.jsm index 6ab86fd5913e..2d66422abf58 100644 --- a/browser/components/sessionstore/SessionStore.jsm +++ b/browser/components/sessionstore/SessionStore.jsm @@ -213,6 +213,10 @@ ChromeUtils.defineModuleGetter( "resource://gre/modules/sessionstore/SessionHistory.jsm" ); +const { TorProtocolService } = ChromeUtils.import( + "resource:///modules/TorProtocolService.jsm" +); + XPCOMUtils.defineLazyServiceGetters(this, { gScreenManager: ["@mozilla.org/gfx/screenmanager;1", "nsIScreenManager"], Telemetry: ["@mozilla.org/base/telemetry;1", "nsITelemetry"], @@ -1888,11 +1892,23 @@ var SessionStoreInternal = { }, "browser-delayed-startup-finished"); }); + let bootstrapPromise = new Promise(resolve => { + if (TorProtocolService.isBootstrapDone() || !TorProtocolService.ownsTorDaemon) { + resolve(); + } else { + Services.obs.addObserver(function obs(subject, topic) { + Services.obs.removeObserver(obs, topic); + resolve(); + }, "torconnect:bootstrap-complete"); + } + }); + // We are ready for initialization as soon as the session file has been // read from disk and the initial window's delayed startup has finished. this._promiseReadyForInitialization = Promise.all([ promise, SessionStartup.onceInitialized, + bootstrapPromise, ]); } diff --git a/browser/components/torconnect/TorConnectChild.jsm b/browser/components/torconnect/TorConnectChild.jsm new file mode 100644 index 000000000000..bd6dd549f156 --- /dev/null +++ b/browser/components/torconnect/TorConnectChild.jsm @@ -0,0 +1,9 @@ +// Copyright (c) 2021, The Tor Project, Inc. + +var EXPORTED_SYMBOLS = ["TorConnectChild"]; + +const { RemotePageChild } = ChromeUtils.import( + "resource://gre/actors/RemotePageChild.jsm" +); + +class TorConnectChild extends RemotePageChild {} diff --git a/browser/components/torconnect/TorConnectParent.jsm b/browser/components/torconnect/TorConnectParent.jsm new file mode 100644 index 000000000000..c34fab76ddbb --- /dev/null +++ b/browser/components/torconnect/TorConnectParent.jsm @@ -0,0 +1,126 @@ +// Copyright (c) 2021, The Tor Project, Inc. + +var EXPORTED_SYMBOLS = ["TorConnectParent"]; + +const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const { TorProtocolService } = ChromeUtils.import( + "resource:///modules/TorProtocolService.jsm" +); +const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm"); +const { TorLauncherUtil } = ChromeUtils.import( + "resource://torlauncher/modules/tl-util.jsm" +); + +const { TorConnect } = ChromeUtils.import( + "resource:///modules/TorConnect.jsm" +); + +const kTorProcessReadyTopic = "TorProcessIsReady"; +const kTorProcessExitedTopic = "TorProcessExited"; +const kTorProcessDidNotStartTopic = "TorProcessDidNotStart"; +const kTorShowProgressPanelTopic = "TorShowProgressPanel"; +const kTorBootstrapStatusTopic = "TorBootstrapStatus"; +const kTorBootstrapErrorTopic = "TorBootstrapError"; +const kTorLogHasWarnOrErrTopic = "TorLogHasWarnOrErr"; + +const gActiveTopics = [ + kTorProcessReadyTopic, + kTorProcessExitedTopic, + kTorProcessDidNotStartTopic, + kTorShowProgressPanelTopic, + kTorBootstrapStatusTopic, + kTorBootstrapErrorTopic, + kTorLogHasWarnOrErrTopic, + "torconnect:bootstrap-complete", +]; + +const gTorLauncherPrefs = { + quickstart: "extensions.torlauncher.quickstart", +} + +class TorConnectParent extends JSWindowActorParent { + constructor(...args) { + super(...args); + + const self = this; + this.gObserver = { + observe(aSubject, aTopic, aData) { + const obj = aSubject?.wrappedJSObject; + if (obj) { + obj.handled = true; + } + self.sendAsyncMessage(aTopic, obj); + }, + }; + + for (const topic of gActiveTopics) { + Services.obs.addObserver(this.gObserver, topic); + } + + this.quickstartObserver = { + observe(aSubject, aTopic, aData) { + if (aTopic === "nsPref:changed" && + aData == gTorLauncherPrefs.quickstart) { + self.sendAsyncMessage("TorQuickstartPrefChanged", Services.prefs.getBoolPref(gTorLauncherPrefs.quickstart)); + } + }, + } + Services.prefs.addObserver(gTorLauncherPrefs.quickstart, this.quickstartObserver); + } + + willDestroy() { + for (const topic of gActiveTopics) { + Services.obs.removeObserver(this.gObserver, topic); + } + } + + + _OpenTorAdvancedPreferences() { + const win = this.browsingContext.top.embedderElement.ownerGlobal; + win.openTrustedLinkIn("about:preferences#tor", "tab"); + } + + _TorCopyLog() { + // Copy tor log messages to the system clipboard. + const chSvc = Cc["@mozilla.org/widget/clipboardhelper;1"].getService( + Ci.nsIClipboardHelper + ); + const countObj = { value: 0 }; + chSvc.copyString(TorProtocolService.getLog(countObj)); + const count = countObj.value; + return TorLauncherUtil.getFormattedLocalizedString( + "copiedNLogMessagesShort", + [count], + 1 + ); + } + + receiveMessage(message) { + switch (message.name) { + case "TorBootstrapErrorOccurred": + return TorProtocolService.torBootstrapErrorOccurred(); + case "TorRetrieveBootstrapStatus": + return TorProtocolService.retrieveBootstrapStatus(); + case "OpenTorAdvancedPreferences": + return this._OpenTorAdvancedPreferences(); + case "GetLocalizedBootstrapStatus": + const { status, keyword } = message.data; + return TorLauncherUtil.getLocalizedBootstrapStatus(status, keyword); + case "TorCopyLog": + return this._TorCopyLog(); + case "TorIsNetworkDisabled": + return TorProtocolService.isNetworkDisabled(); + case "TorStopBootstrap": + return TorProtocolService.torStopBootstrap(); + case "TorConnect": + return TorProtocolService.connect(); + case "GetDirection": + return Services.locale.isAppLocaleRTL ? "rtl" : "ltr"; + case "GetTorStrings": + return TorStrings; + case "TorLogHasWarnOrErr": + return TorProtocolService.torLogHasWarnOrErr(); + } + return undefined; + } +} diff --git a/browser/components/torconnect/content/aboutTorConnect.css b/browser/components/torconnect/content/aboutTorConnect.css new file mode 100644 index 000000000000..a70904ca0b28 --- /dev/null +++ b/browser/components/torconnect/content/aboutTorConnect.css @@ -0,0 +1,151 @@ + +/* Copyright (c) 2021, The Tor Project, Inc. */ + + +@import url("chrome://browser/skin/error-pages.css"); + +:root { + --onion-opacity: 1; + --onion-color: var(--card-outline-color); + --onion-radius: 50px; +} + +/* override firefox's default blue focus coloring */ +:focus { + outline: none!important; + box-shadow: 0 0 0 3px #CD8CED !important; + border: 1px #59316B solid !important; +} + +@media (prefers-color-scheme: dark) +{ + :focus { + box-shadow: 0 0 0 3px #8C689E !important; + } +} + +/* override firefox's default blue border on hover */ +input[type="checkbox"]:not(:disabled):hover { + border-color: #59316B; +} + +/* fix checkbox visibility when dark mode enabled */ +input[type="checkbox"]:checked { + fill: var(--in-content-page-color); +} + +#connectButton { + background-color: #7D4698; +} + +#connectButton:hover { + background-color: #59316B; +} + +#progressBackground { + position:fixed; + padding:0; + margin:0; + top:0; + left:0; + width: 0%; + height: 7px; + background-image: linear-gradient(90deg, rgb(20, 218, 221) 0%, rgb(128, 109, 236) 100%); + border-radius: 0; +} + +#connectPageContainer { + margin-top: 10vh; + width: 50%; +} + +#quickstartCheckbox, #quickstartCheckboxLabel { + vertical-align: middle; +} + +#copyLogButton { + position: relative; +} + +/* mirrors p element spacing */ +#copyLogContainer { + margin: 1em 0; + height: 1.2em; + min-height: 1.2em; +} + +#copyLogLink { + position: relative; + display: inline-block; + color: var(--in-content-link-color); +} + +/* 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 { + background-color: #30E60B; + color: #003706; + border-radius: 2px; + padding: 4px; + line-height: 13px; + font: 11px sans-serif; + font-weight: 400; +} + +/* 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 { + padding: 0px !important; + justify-content: space-between; + background-color: var(--in-content-page-background); +} + +.title { + background-image: url("chrome://browser/content/torconnect/onion.svg"); + -moz-context-properties: fill, fill-opacity; + fill-opacity: 1; + fill: var(--onion-color); +} + +.title.error { + background-image: url("chrome://browser/content/torconnect/onion-slash.svg"); +} + diff --git a/browser/components/torconnect/content/aboutTorConnect.js b/browser/components/torconnect/content/aboutTorConnect.js new file mode 100644 index 000000000000..19fd335ccd13 --- /dev/null +++ b/browser/components/torconnect/content/aboutTorConnect.js @@ -0,0 +1,339 @@ +// Copyright (c) 2021, The Tor Project, Inc. + +/* eslint-env mozilla/frame-script */ + +const kTorProcessReadyTopic = "TorProcessIsReady"; +const kTorProcessExitedTopic = "TorProcessExited"; +const kTorProcessDidNotStartTopic = "TorProcessDidNotStart"; +const kTorBootstrapStatusTopic = "TorBootstrapStatus"; +const kTorBootstrapErrorTopic = "TorBootstrapError"; +const kTorLogHasWarnOrErrTopic = "TorLogHasWarnOrErr"; +const kTorQuickstartPrefChanged = "TorQuickstartPrefChanged"; + +const TorLauncherPrefs = { + quickstart: "extensions.torlauncher.quickstart", + prompt_at_startup: "extensions.torlauncher.prompt_at_startup", +} + +class AboutTorConnect { + log(...args) { + console.log(...args); + } + + logError(...args) { + console.error(...args); + } + + logDebug(...args) { + console.debug(...args); + } + + getElem(id) { + return document.getElementById(id); + } + get elemProgressContent() { + return this.getElem("progressContent"); + } + get elemProgressDesc() { + return this.getElem("connectShortDescText"); + } + 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"); + } + get elemQuickstartLabel() { + return this.getElem("quickstartCheckboxLabel"); + } + get elemConnectButton() { + return this.getElem("connectButton"); + } + get elemAdvancedButton() { + return this.getElem("advancedButton"); + } + get elemCancelButton() { + return this.getElem("cancelButton"); + } + get elemTextContainer() { + return this.getElem("text-container"); + } + get elemTitle() { + return this.elemTextContainer.getElementsByClassName("title")[0]; + } + + static get STATE_INITIAL() { + return "STATE_INITIAL"; + } + + static get STATE_BOOTSTRAPPING() { + return "STATE_BOOTSTRAPPING"; + } + + static get STATE_BOOTSTRAPPED() { + return "STATE_BOOTSTRAPPED"; + } + + static get STATE_BOOTSTRAP_ERROR() { + return "STATE_BOOTSTRAP_ERROR"; + } + + get state() { + return this._state; + } + + setInitialUI() { + this.setTitle(this.torStrings.torConnect.torConnect); + this.elemProgressDesc.textContent = + this.torStrings.settings.torPreferencesDescription; + this.showElem(this.elemConnectButton); + this.elemConnectButton.focus(); + this.showElem(this.elemAdvancedButton); + this.hideElem(this.elemCopyLogLink); + this.hideElem(this.elemCancelButton); + this.hideElem(this.elemProgressContent); + this.hideElem(this.elemProgressMeter); + this.elemTitle.classList.remove("error"); + } + + setBootstrappingUI() { + this.setTitle(this.torStrings.torConnect.torConnecting); + this.hideElem(this.elemConnectButton); + this.hideElem(this.elemAdvancedButton); + this.hideElem(this.elemCopyLogLink); + this.showElem(this.elemCancelButton); + this.elemCancelButton.focus(); + this.showElem(this.elemProgressContent); + this.showElem(this.elemProgressMeter); + this.elemTitle.classList.remove("error"); + } + + setBootstrapErrorUI() { + this.setTitle(this.torStrings.torConnect.torBootstrapFailed); + this.elemConnectButton.textContent = this.torStrings.torConnect.tryAgain; + this.showElem(this.elemConnectButton); + this.hideElem(this.elemCancelButton); + this.showElem(this.elemAdvancedButton); + this.elemAdvancedButton.focus(); + this.showElem(this.elemProgressContent); + this.hideElem(this.elemProgressMeter); + this.elemTitle.classList.add("error"); + } + + set state(state) { + const oldState = this.state; + if (oldState === state) { + return; + } + this._state = state; + switch (this.state) { + case AboutTorConnect.STATE_INITIAL: + this.setInitialUI(); + break; + case AboutTorConnect.STATE_BOOTSTRAPPING: + this.setBootstrappingUI(); + break; + case AboutTorConnect.STATE_BOOTSTRAP_ERROR: + this.setBootstrapErrorUI(); + break; + case AboutTorConnect.STATE_BOOTSTRAPPED: + window.close(); + break; + } + } + + async showErrorMessage(aErrorObj) { + if (aErrorObj && aErrorObj.message) { + this.setTitle(aErrorObj.message); + if (aErrorObj.details) { + this.elemProgressDesc.textContent = aErrorObj.details; + } + } + + this.showCopyLog(); + this.showElem(this.elemConnectButton); + } + + showElem(elem) { + elem.removeAttribute("hidden"); + } + + hideElem(elem) { + elem.setAttribute("hidden", "true"); + } + + async connect() { + // reset the text to original description + // in case we are trying again after an error (clears out error text) + this.elemProgressDesc.textContent = + this.torStrings.settings.torPreferencesDescription; + + this.state = AboutTorConnect.STATE_BOOTSTRAPPING; + const error = await RPMSendQuery("TorConnect"); + if (error) { + if (error.details) { + this.showErrorMessage({ message: error.details }, true); + this.showSaveSettingsError(error.details); + } + } + } + + showCopyLog() { + this.elemCopyLogLink.removeAttribute("hidden"); + } + + async updateBootstrapProgress(status) { + let labelText = await RPMSendQuery("GetLocalizedBootstrapStatus", { + status, + keyword: "TAG", + }); + let percentComplete = status.PROGRESS ? status.PROGRESS : 0; + this.elemProgressMeter.style.width = `${percentComplete}%`; + + if (await RPMSendQuery("TorBootstrapErrorOccurred")) { + this.state = AboutTorConnect.STATE_BOOTSTRAP_ERROR; + return; + } else if (await RPMSendQuery("TorIsNetworkDisabled")) { + // If tor network is not connected, let's go to the initial state, even + // if bootstrap state is greater than 0. + this.state = AboutTorConnect.STATE_INITIAL; + return; + } else if (percentComplete > 0) { + this.state = AboutTorConnect.STATE_BOOTSTRAPPING; + } + + // Due to async, status might have changed. Do not override desc if so. + if (this.state === AboutTorConnect.STATE_BOOTSTRAPPING) { + this.hideElem(this.elemConnectButton); + } + } + + stopTorBootstrap() { + RPMSendAsyncMessage("TorStopBootstrap"); + } + + setTitle(title) { + const titleElement = document.querySelector(".title-text"); + titleElement.textContent = title; + document.title = title; + } + + async initElements() { + this.elemAdvancedButton.textContent = this.torStrings.torConnect.torConfigure; + this.elemAdvancedButton.addEventListener("click", () => { + RPMSendAsyncMessage("OpenTorAdvancedPreferences"); + }); + + // sets the text content while keping the child elements intact + this.elemCopyLogLink.childNodes[0].nodeValue = + this.torStrings.torConnect.copyLog; + this.elemCopyLogLink.addEventListener("click", async (event) => { + const copiedMessage = await RPMSendQuery("TorCopyLog"); + aboutTorConnect.elemCopyLogTooltipText.textContent = copiedMessage; + aboutTorConnect.elemCopyLogTooltip.style.visibility = "visible"; + + // clear previous timeout if one already exists + if (aboutTorConnect.copyLogTimeoutId) { + clearTimeout(aboutTorConnect.copyLogTimeoutId); + } + + // hide tooltip after X ms + const TOOLTIP_TIMEOUT = 2000; + aboutTorConnect.copyLogTimeoutId = setTimeout(function() { + aboutTorConnect.elemCopyLogTooltip.style.visibility = "hidden"; + 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.showCopyLog(); + this.stopTorBootstrap(); + this.showErrorMessage(data); + }); + RPMAddMessageListener(kTorLogHasWarnOrErrTopic, () => { + this.showCopyLog(); + }); + RPMAddMessageListener(kTorProcessDidNotStartTopic, ({ data }) => { + this.showErrorMessage(data); + }); + RPMAddMessageListener(kTorBootstrapStatusTopic, ({ data }) => { + this.updateBootstrapProgress(data); + }); + RPMAddMessageListener(kTorQuickstartPrefChanged, ({ data }) => { + // update checkbox with latest quickstart pref value + this.elemQuickstartCheckbox.checked = data; + }); + RPMAddMessageListener("torconnect:bootstrap-complete", () => { + this.state = AboutTorConnect.STATE_BOOTSTRAPPED; + }); + } + + initKeyboardShortcuts() { + document.onkeydown = (evt) => { + // unfortunately it looks like we still haven't standardized keycodes to + // integers, so we must resort to a string compare here :( + // see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code for relevant documentation + if (evt.code === "Escape") { + this.stopTorBootstrap(); + } + }; + } + + async init() { + this.torStrings = await RPMSendQuery("GetTorStrings"); + document.documentElement.setAttribute( + "dir", + await RPMSendQuery("GetDirection") + ); + this.initElements(); + this.initObservers(); + this.initKeyboardShortcuts(); + this.state = AboutTorConnect.STATE_INITIAL; + + // Request the most recent bootstrap status info so that a + // TorBootstrapStatus notification is generated as soon as possible. + RPMSendAsyncMessage("TorRetrieveBootstrapStatus"); + + // quickstart is the user set pref for starting tor automatically + // prompt_at_startup will be set to false after successful bootstrap, and true on error + // by tor-launcher, so we want to keep the connect screen up when prompt_at_startup is true + /// even if quickstart is enabled so user can potentially resolve errors on next launch + if (await RPMGetBoolPref(TorLauncherPrefs.quickstart) && + !await RPMGetBoolPref(TorLauncherPrefs.prompt_at_startup)) { + this.connect(); + } + } +} + +const aboutTorConnect = new AboutTorConnect(); +aboutTorConnect.init(); diff --git a/browser/components/torconnect/content/aboutTorConnect.xhtml b/browser/components/torconnect/content/aboutTorConnect.xhtml new file mode 100644 index 000000000000..0a0721afb7db --- /dev/null +++ b/browser/components/torconnect/content/aboutTorConnect.xhtml @@ -0,0 +1,54 @@ +<!-- Copyright (c) 2021, The Tor Project, Inc. --> +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Security-Policy" content="default-src chrome:; object-src 'none'" /> + <link rel="stylesheet" href="chrome://browser/skin/onionPattern.css" type="text/css" media="all" /> + <link rel="stylesheet" href="chrome://browser/content/torconnect/aboutTorConnect.css" type="text/css" media="all" /> + </head> + <body> + <div id="progressBackground"></div> + <div id="connectPageContainer" class="container"> + <div id="text-container"> + <div class="title"> + <h1 class="title-text"/> + </div> + <div id="connectLongContent"> + <div id="connectShortDesc"> + <p id="connectShortDescText" /> + </div> + </div> + + <div id="progressContent" hidden="true"> + <div class="tbb-header" pack="center"> + <image class="tbb-logo"/> + </div> + <div flex="1"> + <div id="progressDesc"/> + </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"/> + </div> + + <div id="connectButtonContainer" class="button-container"> + <button id="advancedButton" hidden="true"></button> + <button id="cancelButton" hidden="true"></button> + <button id="connectButton" class="primary try-again" hidden="true"></button> + </div> + </div> + </div> +#include ../../../themes/shared/onionPattern.inc.xhtml + </body> + <script src="chrome://browser/content/torconnect/aboutTorConnect.js"/> +</html> diff --git a/browser/components/torconnect/content/onion-slash.svg b/browser/components/torconnect/content/onion-slash.svg new file mode 100644 index 000000000000..efb09700ec0b --- /dev/null +++ b/browser/components/torconnect/content/onion-slash.svg @@ -0,0 +1,7 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> + <g fill-opacity="context-fill-opacity" fill="context-fill"> + <path d="M3.409559 13.112147C3.409559 13.112147 8.200807 8.103115 8.200807 8.103115C8.200807 8.103115 8.200807 6.516403 8.200807 6.516403C8.620819 6.516403 9.009719 6.703075 9.274171 6.998639C9.274171 6.998639 10.160863 6.080835 10.160863 6.080835C9.663071 5.567487 8.978607 5.256367 8.200807 5.256367C8.200807 5.256367 8.200807 4.400787 8.200807 4.400787C9.196391 4.400787 10.098639 4.805243 10.736435 5.458595C10.736435 5.458595 11.623127 4.540791 11.623127 4.540791C10.751991 3.669655 9.538623 3.125195 8.200807 3.125195C8.200807 3.125195 8.200807 2.269615 8.200807 2.269615C9.756407 2.269615 11.172003 2.907411 12.214255 3.918551C12.214255 3.918551 13.100947 3.000747 13.100947 3.000747C11.825355 1.756267 10.098639 0.994023 8.185251 0.994023C4.311807 0.994023 1.185051 4.120779 1.185051 7.994223C1.185051 10.016503 2.040631 11.836555 3.409559 13.112147C3.409559 13.112147 3.409559 13.112147 3.409559 13.112147"/> + <path d="M14.205423 4.416343C14.205423 4.416343 13.287619 5.380815 13.287619 5.380815C13.692075 6.158615 13.909859 7.045307 13.909859 7.994223C13.909859 11.152091 11.358675 13.718831 8.200807 13.718831C8.200807 13.718831 8.200807 12.863251 8.200807 12.863251C10.891995 12.863251 13.069835 10.669855 13.069835 7.978667C13.069835 7.278647 12.929831 6.625295 12.665379 6.018611C12.665379 6.018611 11.685351 7.045307 11.685351 7.045307C11.763131 7.340871 11.809799 7.651991 11.809799 7.963111C11.809799 9.954279 10.207531 11.556547 8.216363 11.572103C8.216363 11.572103 8.216363 10.716523 8.216363 10.716523C9.725295 10.700967 10.954219 9.472043 10.954219 7.963111C10.954219 7.916443 10.954219 7.854219 10.954219 7.807551C10.954219 7.807551 4.887379 14.169955 4.887379 14.169955C5.867407 14.698859 6.987439 14.994423 8.185251 14.994423C12.058695 14.994423 15.185451 11.867667 15.185451 7.994223C15.185451 6.687519 14.827663 5.474151 14.205423 4.416343C14.205423 4.416343 14.205423 4.416343 14.20542 3 4.416343"/> + <path d="M1.791735 15.461103C1.402835 15.461103 1.045047 15.212207 0.889487 14.838863C0.733927 14.465519 0.827267 14.014395 1.107271 13.734387C1.107271 13.734387 13.458735 0.822907 13.458735 0.822907C13.847635 0.434007 14.454319 0.449563 14.827663 0.838467C15.201007 1.227367 15.216563 1.865163 14.843223 2.269619C14.843223 2.269619 2.491759 15.181099 2.491759 15.181099C2.289531 15.352215 2.040635 15.461107 1.791739 15.461107C1.791739 15.461107 1.791735 15.461103 1.791735 15.461103"/> + </g> +</svg> diff --git a/browser/components/torconnect/content/onion.svg b/browser/components/torconnect/content/onion.svg new file mode 100644 index 000000000000..30cd52ba5c51 --- /dev/null +++ b/browser/components/torconnect/content/onion.svg @@ -0,0 +1,3 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <path fill="context-fill" fill-opacity="context-fill-opacity" d="M12.0246161,21.8174863 L12.0246161,20.3628098 C16.6324777,20.3495038 20.3634751,16.6108555 20.3634751,11.9996673 C20.3634751,7.38881189 16.6324777,3.65016355 12.0246161,3.63685757 L12.0246161,2.18218107 C17.4358264,2.1958197 21.8178189,6.58546322 21.8178189,11.9996673 C21.8178189,17.4142042 17.4358264,21.8041803 12.0246161,21.8174863 L12.0246161,21.8174863 Z M12.0246161,16.7259522 C14.623607,16.7123136 16.7272828,14.6023175 16.7272828,11.9996673 C16.7272828,9.39734991 14.623607,7.28735377 12.0246161,7.27371516 L12.0246161,5.81937131 C15.4272884,5.8326773 18.1819593,8.59400123 18.1819593,11.9996673 C18.1819593,15.4056661 15.4272884,18.1669901 12.0246161,18.1802961 L12.0246161,16.7259522 Z M12.0246161,9.45556355 C13.4187503,9.46886953 14.5454344,10.6022066 14.5454344,11.9996673 C14.5454344,13.3974608 13.4187503,14.5307978 12.0246161,14.5441038 L12.0246161,9.45556355 Z M0,11.9996673 C0,18.6273771 5.37229031,24 12,24 C18 .6273771,24 24,18.6273771 24,11.9996673 C24,5.37229031 18.6273771,0 12,0 C5.37229031,0 0,5.37229031 0,11.9996673 Z"/> +</svg> \ No newline at end of file diff --git a/browser/components/torconnect/content/torBootstrapUrlbar.js b/browser/components/torconnect/content/torBootstrapUrlbar.js new file mode 100644 index 000000000000..55a595b2dbab --- /dev/null +++ b/browser/components/torconnect/content/torBootstrapUrlbar.js @@ -0,0 +1,136 @@ +// Copyright (c) 2021, The Tor Project, Inc. + +"use strict"; + + const TorConnectionStatus = { + invalid: -1, + offline: 0, + connecting: 1, + connected: 2, + failure: 3, + }; +var TorBootstrapUrlbar; + +{ + const { TorProtocolService } = ChromeUtils.import( + "resource:///modules/TorProtocolService.jsm" + ); + const { TorLauncherUtil } = ChromeUtils.import( + "resource://torlauncher/modules/tl-util.jsm" + ); + const { TorStrings } = ChromeUtils.import( + "resource:///modules/TorStrings.jsm" + ); + + const kTorProcessReadyTopic = "TorProcessIsReady"; + const kTorProcessExitedTopic = "TorProcessExited"; + const kTorProcessDidNotStartTopic = "TorProcessDidNotStart"; + const kTorBootstrapStatusTopic = "TorBootstrapStatus"; + const kTorBootstrapErrorTopic = "TorBootstrapError"; + + const gActiveTopics = [ + kTorProcessReadyTopic, + kTorProcessExitedTopic, + kTorProcessDidNotStartTopic, + kTorBootstrapStatusTopic, + kTorBootstrapErrorTopic, + ]; + + TorBootstrapUrlbar = { + _connectionStatus: TorConnectionStatus.invalid, + get ConnectionStatus() { + return this._connectionStatus; + }, + + _torConnectBox : null, + get TorConnectBox() { + if (!this._torConnectBox) { + this._torConnectBox = + browser.ownerGlobal.document.getElementById("torconnect-box"); + } + return this._torConnectBox; + }, + + _torConnectLabel : null, + get TorConnectLabel() { + if (!this._torConnectLabel) { + this._torConnectLabel = + browser.ownerGlobal.document.getElementById("torconnect-label"); + } + return this._torConnectLabel; + }, + + _updateConnectionStatus(percentComplete = 0) { + if (TorProtocolService.ownsTorDaemon && + !TorLauncherUtil.useLegacyLauncher) { + if (TorProtocolService.isNetworkDisabled()) { + if (TorProtocolService.torBootstrapErrorOccurred()) { + this._connectionStatus = TorConnectionStatus.failure; + } else { + this._connectionStatus = TorConnectionStatus.offline; + } + } else if (percentComplete < 100) { + this._connectionStatus = TorConnectionStatus.connecting; + } else if (percentComplete === 100) { + this._connectionStatus = TorConnectionStatus.connected; + } + } + else + { + this._connectionStatus = TorConnectionStatus.invalid; + } + + switch(this._connectionStatus) + { + case TorConnectionStatus.failure: + case TorConnectionStatus.offline: + this.TorConnectBox.removeAttribute("hidden"); + this.TorConnectLabel.textContent = TorStrings.torConnect.offline; + gURLBar._inputContainer.setAttribute("torconnect", "offline"); + break; + case TorConnectionStatus.connecting: + this.TorConnectLabel.textContent = + TorStrings.torConnect.torConnectingConcise; + gURLBar._inputContainer.setAttribute("torconnect", "connecting"); + break; + case TorConnectionStatus.connected: + this.TorConnectLabel.textContent = + TorStrings.torConnect.torConnectedConcise; + gURLBar._inputContainer.setAttribute("torconnect", "connected"); + // hide torconnect box after 5 seconds + let self = this; + setTimeout(function() { + self.TorConnectBox.setAttribute("hidden", "true"); + }, 5000); + break; + } + }, + + observe(aSubject, aTopic, aData) { + const obj = aSubject?.wrappedJSObject; + + switch (aTopic) { + case kTorProcessReadyTopic: + case kTorProcessExitedTopic: + case kTorProcessDidNotStartTopic: + case kTorBootstrapErrorTopic: + this._updateConnectionStatus(); + break; + case kTorBootstrapStatusTopic: + let percentComplete = obj.PROGRESS ? obj.PROGRESS : 0; + this._updateConnectionStatus(percentComplete); + break; + } + }, + init() { + for (const topic of gActiveTopics) { + Services.obs.addObserver(this, topic); + } + }, + uninit() { + for (const topic of gActiveTopics) { + Services.obs.removeObserver(this, topic); + } + }, + }; +} diff --git a/browser/components/torconnect/content/torconnect-urlbar.css b/browser/components/torconnect/content/torconnect-urlbar.css new file mode 100644 index 000000000000..db2f1069b22b --- /dev/null +++ b/browser/components/torconnect/content/torconnect-urlbar.css @@ -0,0 +1,65 @@ +/* + ensure our torconnect button is always visible (same rule as for the bookmark button) +*/ +hbox.urlbar-page-action#torconnect-box { + display: -moz-inline-box!important; + margin: 0 6px; + height: 28px; +} +/* disable the button-like default css */ +hbox.urlbar-page-action#torconnect-box:hover, +hbox.urlbar-page-action#torconnect-box:active { + background-color: inherit!important; +} + +label#torconnect-label { + line-height: 28px; + 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 { + line-height: 24px; + } +} +:root[uidensity=touch] { + hbox.urlbar-page-action#torconnect-box { + margin: 0 7px; + height: 30px; + } + label#torconnect-label { + line-height: 30px; + } +} + +/* hide when hidden attribute is set */ +hbox.urlbar-page-action#torconnect-box[hidden="true"], +/* hide when user is typing in URL bar */ +#urlbar[usertyping] > #urlbar-input-container > #page-action-buttons > #torconnect-box { + display: none!important; +} + +/* hide urlbar's placeholder text when not connectd to tor */ +hbox#urlbar-input-container[torconnect="offline"] input#urlbar-input::placeholder, +hbox#urlbar-input-container[torconnect="connecting"] input#urlbar-input::placeholder { + opacity: 0; +} + +/* hide search suggestions when not connected to tor */ +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/torconnect/content/torconnect-urlbar.inc.xhtml b/browser/components/torconnect/content/torconnect-urlbar.inc.xhtml new file mode 100644 index 000000000000..bdf9d8f0df00 --- /dev/null +++ b/browser/components/torconnect/content/torconnect-urlbar.inc.xhtml @@ -0,0 +1,11 @@ +# Copyright (c) 2021, The Tor Project, Inc. + +<hbox id="torconnect-box" + class="urlbar-icon-wrapper urlbar-page-action" + role="status" + hidden="true"> + <image id="torconnect-button" role="presentation"/> + <hbox id="torconnect-container"> + <label id="torconnect-label"/> + </hbox> +</hbox> \ No newline at end of file diff --git a/browser/components/torconnect/jar.mn b/browser/components/torconnect/jar.mn new file mode 100644 index 000000000000..ed8a4de299b2 --- /dev/null +++ b/browser/components/torconnect/jar.mn @@ -0,0 +1,7 @@ +browser.jar: + content/browser/torconnect/torBootstrapUrlbar.js (content/torBootstrapUrlbar.js) + content/browser/torconnect/aboutTorConnect.css (content/aboutTorConnect.css) +* content/browser/torconnect/aboutTorConnect.xhtml (content/aboutTorConnect.xhtml) + content/browser/torconnect/aboutTorConnect.js (content/aboutTorConnect.js) + content/browser/torconnect/onion.svg (content/onion.svg) + content/browser/torconnect/onion-slash.svg (content/onion-slash.svg) diff --git a/browser/components/torconnect/moz.build b/browser/components/torconnect/moz.build new file mode 100644 index 000000000000..eb29c31a4243 --- /dev/null +++ b/browser/components/torconnect/moz.build @@ -0,0 +1,6 @@ +JAR_MANIFESTS += ['jar.mn'] + +EXTRA_JS_MODULES += [ + 'TorConnectChild.jsm', + 'TorConnectParent.jsm', +] diff --git a/browser/components/torpreferences/content/torPane.js b/browser/components/torpreferences/content/torPane.js index 49054b5dac6a..01609ddda090 100644 --- a/browser/components/torpreferences/content/torPane.js +++ b/browser/components/torpreferences/content/torPane.js @@ -1,5 +1,7 @@ "use strict"; +/* global Services */ + const { TorProtocolService } = ChromeUtils.import( "resource:///modules/TorProtocolService.jsm" ); @@ -51,6 +53,10 @@ const { parsePort, parseBridgeStrings, parsePortList } = ChromeUtils.import( "chrome://browser/content/torpreferences/parseFunctions.jsm" ); +const TorLauncherPrefs = { + quickstart: "extensions.torlauncher.quickstart", +} + /* Tor Pane @@ -62,11 +68,21 @@ const gTorPane = (function() { category: { title: "label#torPreferences-labelCategory", }, + messageBox: { + box: "div#torPreferences-connectMessageBox", + message: "td#torPreferences-connectMessageBox-message", + button: "button#torPreferences-connectMessageBox-button", + }, torPreferences: { header: "h1#torPreferences-header", description: "span#torPreferences-description", learnMore: "label#torPreferences-learnMore", }, + quickstart: { + header: "h2#torPreferences-quickstart-header", + description: "span#torPreferences-quickstart-description", + enableQuickstartCheckbox: "checkbox#torPreferences-quickstart-toggle", + }, bridges: { header: "h2#torPreferences-bridges-header", description: "span#torPreferences-bridges-description", @@ -112,6 +128,10 @@ const gTorPane = (function() { let retval = { // cached frequently accessed DOM elements + _messageBox: null, + _messageBoxMessage: null, + _messageBoxButton: null, + _enableQuickstartCheckbox: null, _useBridgeCheckbox: null, _bridgeSelectionRadiogroup: null, _builtinBridgeOption: null, @@ -161,6 +181,43 @@ const gTorPane = (function() { let prefpane = document.getElementById("mainPrefPane"); + // 'Connect to Tor' Message Bar + + this._messageBox = prefpane.querySelector(selectors.messageBox.box); + this._messageBoxMessage = prefpane.querySelector(selectors.messageBox.message); + this._messageBoxButton = prefpane.querySelector(selectors.messageBox.button); + // wire up connect button + this._messageBoxButton.addEventListener("click", () => { + TorProtocolService.connect(); + let win = Services.wm.getMostRecentWindow("navigator:browser"); + // switch to existing about:torconnect tab or create a new one + win.switchToTabHavingURI("about:torconnect", true); + }); + + let populateMessagebox = () => { + if (TorProtocolService.shouldShowTorConnect()) { + // set messagebox style and text + if (TorProtocolService.torBootstrapErrorOccurred()) { + this._messageBox.className = "error"; + this._messageBoxMessage.innerText = TorStrings.torConnect.tryAgainMessage; + this._messageBoxButton.innerText = TorStrings.torConnect.tryAgain; + } else { + this._messageBox.className = "warning"; + this._messageBoxMessage.innerText = TorStrings.torConnect.connectMessage; + this._messageBoxButton.innerText = TorStrings.torConnect.torConnectButton; + } + } else { + this._messageBox.className = "hidden"; + this._messageBoxMessage.innerText = ""; + this._messageBoxButton.innerText = ""; + } + } + populateMessagebox(); + // update the messagebox whenever we come back to the page + window.addEventListener("focus", val => { + populateMessagebox(); + }); + // Heading prefpane.querySelector(selectors.torPreferences.header).innerText = TorStrings.settings.torPreferencesHeading; @@ -177,6 +234,26 @@ const gTorPane = (function() { ); } + // Quickstart + prefpane.querySelector(selectors.quickstart.header).innerText = + TorStrings.settings.quickstartHeading; + prefpane.querySelector(selectors.quickstart.description).textContent = + TorStrings.settings.quickstartDescription; + + this._enableQuickstartCheckbox = prefpane.querySelector( + selectors.quickstart.enableQuickstartCheckbox + ); + this._enableQuickstartCheckbox.setAttribute( + "label", + TorStrings.settings.quickstartCheckbox + ); + this._enableQuickstartCheckbox.addEventListener("command", e => { + const checked = this._enableQuickstartCheckbox.checked; + Services.prefs.setBoolPref(TorLauncherPrefs.quickstart, checked); + }); + this._enableQuickstartCheckbox.checked = Services.prefs.getBoolPref(TorLauncherPrefs.quickstart); + Services.prefs.addObserver(TorLauncherPrefs.quickstart, this); + // Bridge setup prefpane.querySelector(selectors.bridges.header).innerText = TorStrings.settings.bridgesHeading; @@ -537,6 +614,15 @@ const gTorPane = (function() { // Callbacks // + // callback for when the quickstart pref changes + observe(subject, topic, data) { + if (topic != "nsPref:changed") return; + if (data === TorLauncherPrefs.quickstart) { + this._enableQuickstartCheckbox.checked = + Services.prefs.getBoolPref(TorLauncherPrefs.quickstart); + } + }, + // callback when using bridges toggled onToggleBridge(enabled) { this._useBridgeCheckbox.checked = enabled; diff --git a/browser/components/torpreferences/content/torPane.xhtml b/browser/components/torpreferences/content/torPane.xhtml index 3c966b2b3726..7c8071f2cf10 100644 --- a/browser/components/torpreferences/content/torPane.xhtml +++ b/browser/components/torpreferences/content/torPane.xhtml @@ -3,6 +3,29 @@ <script type="application/javascript" src="chrome://browser/content/torpreferences/torPane.js"/> <html:template id="template-paneTor"> + +<!-- Tor Connect Message Box --> +<groupbox data-category="paneTor" hidden="true"> + <html:div id="torPreferences-connectMessageBox" + class="subcategory" + data-category="paneTor" + hidden="true"> + <html:table > + <html:tr> + <html:td> + <html:div id="torPreferences-connectMessageBox-icon"/> + </html:td> + <html:td id="torPreferences-connectMessageBox-message"> + </html:td> + <html:td> + <html:button id="torPreferences-connectMessageBox-button"> + </html:button> + </html:td> + </html:tr> + </html:table> + </html:div> +</groupbox> + <hbox id="torPreferencesCategory" class="subcategory" data-category="paneTor" @@ -18,6 +41,17 @@ </description> </groupbox> +<!-- Quickstart --> +<groupbox id="torPreferences-quickstart-group" + data-category="paneTor" + hidden="true"> + <html:h2 id="torPreferences-quickstart-header"/> + <description flex="1"> + <html:span id="torPreferences-quickstart-description"/> + </description> + <checkbox id="torPreferences-quickstart-toggle"/> +</groupbox> + <!-- Bridges --> <groupbox id="torPreferences-bridges-group" data-category="paneTor" diff --git a/browser/components/torpreferences/content/torPreferences.css b/browser/components/torpreferences/content/torPreferences.css index 4dac2c457823..f125936dac74 100644 --- a/browser/components/torpreferences/content/torPreferences.css +++ b/browser/components/torpreferences/content/torPreferences.css @@ -2,6 +2,127 @@ list-style-image: url("chrome://browser/content/torpreferences/torPreferencesIcon.svg"); } +/* Connect Message Box */ + +#torPreferences-connectMessageBox { + display: block; + position: relative; + + width: auto; + min-height: 32px; + border-radius: 4px; + padding: 4px; +} + +#torPreferences-connectMessageBox.hidden { + display: none; +} + +#torPreferences-connectMessageBox.error { + background-color: var(--red-60); + color: white; +} + +#torPreferences-connectMessageBox.warning { + background-color: var(--yellow-50); + color: var(--yellow-90); +} + +#torPreferences-connectMessageBox table { + border-collapse: collapse; + width: 100%; +} + +#torPreferences-connectMessageBox td { + vertical-align: top; + padding: 0px; +} + +#torPreferences-connectMessageBox td:first-child { + width: 24px; +} + +#torPreferences-connectMessageBox-icon { + display: block; + width: 16px; + height: 16px; + padding: 4px; + + mask-repeat: no-repeat !important; + mask-size: 16px !important; + mask-position: 4px 4px !important; +} + +#torPreferences-connectMessageBox.error #torPreferences-connectMessageBox-icon +{ + mask: url("chrome://browser/skin/onion-slash.svg"); + background-color: white; +} + +#torPreferences-connectMessageBox.warning #torPreferences-connectMessageBox-icon +{ + mask: url("chrome://global/skin/icons/warning.svg"); + background-color: black; +} + +#torPreferences-connectMessageBox-message { + display: block; + line-height: 16px; + font-size: 13px; + margin-right: 8px; + padding-left: 4px!important; + padding-top: 4px!important; +} + +#torPreferences-connectMessageBox-button { + display: block; + width: auto; + height: 24px; + line-height: 24px; + min-height: 24px; + max-height: 24px; + margin: 0px; + + border-radius: 2px; + border: 0; + padding-left: 8px; + padding-right: 8px; + margin-left: auto; + margin-right: 0px; + + font-size: 11px; + font-weight: 400; + white-space: nowrap; +} + +#torPreferences-connectMessageBox.error #torPreferences-connectMessageBox-button { + background-color: var(--red-70); +} + +#torPreferences-connectMessageBox.error #torPreferences-connectMessageBox-button:hover { + background-color: var(--red-80); +} + +#torPreferences-connectMessageBox.error #torPreferences-connectMessageBox-button:active { + background-color: var(--red-90); +} + +#torPreferences-connectMessageBox.warning #torPreferences-connectMessageBox-button { + background-color: var(--yellow-60); +} + +#torPreferences-connectMessageBox.warning #torPreferences-connectMessageBox-button:hover { + background-color: var(--yellow-70); + color: white!important; +} + +#torPreferences-connectMessageBox.warning #torPreferences-connectMessageBox-button:active { + background-color: var(--yellow-80); + color: white!important; +} + +/* Advanced Settings */ + #torPreferences-advanced-grid { display: grid; grid-template-columns: auto 1fr; 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/browser/modules/TorConnect.jsm b/browser/modules/TorConnect.jsm new file mode 100644 index 000000000000..3125c84558db --- /dev/null +++ b/browser/modules/TorConnect.jsm @@ -0,0 +1,62 @@ +"use strict"; + +var EXPORTED_SYMBOLS = ["TorConnect"]; + +const { Services } = ChromeUtils.import( + "resource://gre/modules/Services.jsm" +); + +const { BrowserWindowTracker } = ChromeUtils.import( + "resource:///modules/BrowserWindowTracker.jsm" +); + +const { TorProtocolService } = ChromeUtils.import( + "resource:///modules/TorProtocolService.jsm" +); + +// TODO: move the bootstrap state management out of each of the individual +// about:torconnect pages and stick it here +var TorConnect = (() => { + let retval = { + init : function() { + let topics = [ + "TorBootstrapStatus", + ]; + + for(const topic of topics) { + Services.obs.addObserver(this, topic); + } + }, + + observe: function(subject, topic, data) { + switch(topic) { + case "TorBootstrapStatus": + const obj = subject?.wrappedJSObject; + if (obj?.PROGRESS === 100) { + // open home page(s) in new tabs + const win = BrowserWindowTracker.getTopWindow() + const urls = Services.prefs.getStringPref("browser.startup.homepage").split('|'); + + let location="tab"; + for(const url of urls) { + win.openTrustedLinkIn(url, location); + // open subsequent tabs behind first tab + location = "tabshifted"; + } + + Services.obs.notifyObservers(null, "torconnect:bootstrap-complete"); + } + break; + default: + // ignore + break; + } + }, + + shouldShowTorConnect : function() { + return TorProtocolService.shouldShowTorConnect(); + }, + }; + retval.init(); + return retval; +})(); /* TorConnect */ \ No newline at end of file diff --git a/browser/modules/TorProcessService.jsm b/browser/modules/TorProcessService.jsm new file mode 100644 index 000000000000..201e331b2806 --- /dev/null +++ b/browser/modules/TorProcessService.jsm @@ -0,0 +1,12 @@ +"use strict"; + +var EXPORTED_SYMBOLS = ["TorProcessService"]; + +var TorProcessService = { + get isBootstrapDone() { + const svc = Cc["@torproject.org/torlauncher-process-service;1"].getService( + Ci.nsISupports + ).wrappedJSObject; + return svc.mIsBootstrapDone; + }, +}; diff --git a/browser/modules/TorProtocolService.jsm b/browser/modules/TorProtocolService.jsm index b4e6ed9a3253..fc7f2c884aa2 100644 --- a/browser/modules/TorProtocolService.jsm +++ b/browser/modules/TorProtocolService.jsm @@ -1,3 +1,5 @@ +// Copyright (c) 2021, The Tor Project, Inc. + "use strict"; var EXPORTED_SYMBOLS = ["TorProtocolService"]; @@ -11,6 +13,10 @@ var TorProtocolService = { Ci.nsISupports ).wrappedJSObject, + _tlproc: Cc["@torproject.org/torlauncher-process-service;1"].getService( + Ci.nsISupports + ).wrappedJSObject, + // maintain a map of tor settings set by Tor Browser so that we don't // repeatedly set the same key/values over and over // this map contains string keys to primitive or array values @@ -196,11 +202,11 @@ var TorProtocolService = { // writes current tor settings to disk flushSettings() { - this._tlps.TorSendCommand("SAVECONF"); + this.sendCommand("SAVECONF"); }, - getLog() { - let countObj = { value: 0 }; + getLog(countObj) { + countObj = countObj || { value: 0 }; let torLog = this._tlps.TorGetLog(countObj); return torLog; }, @@ -209,4 +215,116 @@ var TorProtocolService = { get ownsTorDaemon() { return TorLauncherUtil.shouldStartAndOwnTor; }, + + // Assumes `ownsTorDaemon` is true + isNetworkDisabled() { + const reply = TorProtocolService._tlps.TorGetConfBool( + "DisableNetwork", + true + ); + if (TorProtocolService._tlps.TorCommandSucceeded(reply)) { + return reply.retVal; + } + return true; + }, + + enableNetwork() { + let settings = {}; + settings.DisableNetwork = false; + let errorObject = {}; + if (!this._tlps.TorSetConfWithReply(settings, errorObject)) { + throw new Error(errorObject.details); + } + }, + + sendCommand(cmd) { + return this._tlps.TorSendCommand(cmd); + }, + + retrieveBootstrapStatus() { + return this._tlps.TorRetrieveBootstrapStatus(); + }, + + _GetSaveSettingsErrorMessage(aDetails) { + try { + return TorLauncherUtil.getSaveSettingsErrorMessage(aDetails); + } catch (e) { + console.log("GetSaveSettingsErrorMessage error", e); + return "Unexpected Error"; + } + }, + + setConfWithReply(settings) { + let result = false; + const error = {}; + try { + result = this._tlps.TorSetConfWithReply(settings, error); + } catch (e) { + console.log("TorSetConfWithReply error", e); + error.details = this._GetSaveSettingsErrorMessage(e.message); + } + return { result, error }; + }, + + isBootstrapDone() { + return this._tlproc.mIsBootstrapDone; + }, + + clearBootstrapError() { + return this._tlproc.TorClearBootstrapError(); + }, + + shouldShowTorConnect() { + return ( + this.ownsTorDaemon && + !TorLauncherUtil.useLegacyLauncher && + (this.isNetworkDisabled() || !this.isBootstrapDone()) + ); + }, + + torBootstrapErrorOccurred() { + return this._tlproc.TorBootstrapErrorOccurred; + }, + + // Resolves to null if ok, or an error otherwise + connect() { + const kTorConfKeyDisableNetwork = "DisableNetwork"; + const settings = {}; + settings[kTorConfKeyDisableNetwork] = false; + const { result, error } = this.setConfWithReply(settings); + if (!result) { + return error; + } + try { + this.sendCommand("SAVECONF"); + this.clearBootstrapError(); + this.retrieveBootstrapStatus(); + } catch (e) { + return error; + } + return null; + }, + + torLogHasWarnOrErr() { + return this._tlps.TorLogHasWarnOrErr; + }, + + torStopBootstrap() { + // Tell tor to disable use of the network; this should stop the bootstrap + // process. + const kErrorPrefix = "Setting DisableNetwork=1 failed: "; + try { + let settings = {}; + settings.DisableNetwork = true; + const { result, error } = this.setConfWithReply(settings); + if (!result) { + console.log( + `Error stopping bootstrap ${kErrorPrefix} ${error.details}` + ); + } + } catch (e) { + console.log(`Error stopping bootstrap ${kErrorPrefix} ${e}`); + } + this.retrieveBootstrapStatus(); + }, }; diff --git a/browser/modules/TorStrings.jsm b/browser/modules/TorStrings.jsm index 1e08b168e4af..c086d0fe3117 100644 --- a/browser/modules/TorStrings.jsm +++ b/browser/modules/TorStrings.jsm @@ -257,6 +257,9 @@ var TorStrings = { "Tor Browser routes your traffic over the Tor Network, run by thousands of volunteers around the world." ), learnMore: getString("torPreferences.learnMore", "Learn More"), + quickstartHeading: getString("torPreferences.quickstart", "Quickstart"), + quickstartDescription: getString("torPreferences.quickstartDescription", "Quickstart allows Tor Browser to connect automatically."), + quickstartCheckbox : getString("torPreferences.quickstartCheckbox", "Always connect automatically"), bridgesHeading: getString("torPreferences.bridges", "Bridges"), bridgesDescription: getString( "torPreferences.bridgesDescription", @@ -364,6 +367,78 @@ var TorStrings = { return retval; })() /* Tor Network Settings Strings */, + torConnect: (() => { + const tsbNetwork = new TorDTDStringBundle( + ["chrome://torlauncher/locale/network-settings.dtd"], + "" + ); + const tsbLauncher = new TorPropertyStringBundle( + "chrome://torlauncher/locale/torlauncher.properties", + "torlauncher." + ); + const tsbCommon = new TorPropertyStringBundle( + "chrome://global/locale/commonDialogs.properties", + "" + ); + + const getStringNet = tsbNetwork.getString.bind(tsbNetwork); + const getStringLauncher = tsbLauncher.getString.bind(tsbLauncher); + const getStringCommon = tsbCommon.getString.bind(tsbCommon); + + return { + torConnect: getStringNet( + "torsettings.wizard.title.default", + "Connect to Tor" + ), + + torConnecting: getStringNet( + "torsettings.wizard.title.connecting", + "Establishing a Connection" + ), + + torConnectingConcise: getStringNet( + "torConnect.connectingConcise", + "Connecting…" + ), + + torBootstrapFailed: getStringLauncher( + "tor_bootstrap_failed", + "Tor failed to establish a Tor network connection." + ), + + torConfigure: getStringNet( + "torsettings.wizard.title.configure", + "Tor Network Settings" + ), + + copyLog: getStringNet( + "torConnect.copyLog", + "Copy Tor Logs" + ), + + torConnectButton: getStringNet("torSettings.connect", "Connect"), + + cancel: getStringCommon("Cancel", "Cancel"), + + torConnected: getStringLauncher( + "torlauncher.bootstrapStatus.done", + "Connected to the Tor network" + ), + + torConnectedConcise: getStringLauncher( + "torConnect.connectedConcise", + "Connected" + ), + + tryAgain: getStringNet("torConnect.tryAgain", "Try connecting again"), + offline: getStringNet("torConnect.offline", "Offline"), + + // tor connect strings for message box in about:preferences#tor + connectMessage: getStringNet("torConnect.connectMessage", "Changes to Tor Settings will not take effect until you connect to the Tor Network"), + tryAgainMessage: getStringNet("torConnect.tryAgainMessage", "Tor Browser has failed to establish a connection to the Tor Network"), + }; + })(), + /* Tor Onion Services Strings, e.g., for the authentication prompt. */ diff --git a/browser/modules/moz.build b/browser/modules/moz.build index 5fb78d1c07a8..7f091e0e7711 100644 --- a/browser/modules/moz.build +++ b/browser/modules/moz.build @@ -155,6 +155,8 @@ EXTRA_JS_MODULES += [ 'TabUnloader.jsm', 'ThemeVariableMap.jsm', 'TopSiteAttribution.jsm', + 'TorConnect.jsm', + 'TorProcessService.jsm', 'TorProtocolService.jsm', 'TorStrings.jsm', 'TransientPrefs.jsm', diff --git a/browser/themes/shared/jar.inc.mn b/browser/themes/shared/jar.inc.mn index e4a3c8d2d41c..d38e1001282b 100644 --- a/browser/themes/shared/jar.inc.mn +++ b/browser/themes/shared/jar.inc.mn @@ -8,6 +8,7 @@ # to the location of the actual manifest. skin/classic/browser/aboutNetError.css (../shared/aboutNetError.css) + skin/classic/browser/onionPattern.css (../shared/onionPattern.css) skin/classic/browser/blockedSite.css (../shared/blockedSite.css) skin/classic/browser/error-pages.css (../shared/error-pages.css) skin/classic/browser/aboutRestartRequired.css (../shared/aboutRestartRequired.css) diff --git a/browser/themes/shared/onionPattern.css b/browser/themes/shared/onionPattern.css new file mode 100644 index 000000000000..c605a4b4f59e --- /dev/null +++ b/browser/themes/shared/onionPattern.css @@ -0,0 +1,124 @@ +/* Onion pattern */ + +:root { + --sqrt3: 1.73205080757; +} + +.onion-pattern-container { + opacity: var(--onion-opacity, 1); + flex: auto; /* grow to consume remaining space on the page */ + display: flex; + margin: 0 auto; + width: 100%; + height: calc((2 + var(--sqrt3)) * var(--onion-radius, 50px)); /* room for 2 rows of circles */ + max-height: calc((2 + var(--sqrt3)) * var(--onion-radius, 50px)); + direction: ltr; +} + +.onion-pattern-crop { + display: flex; + justify-content: center; + overflow-x: hidden; + pointer-events: none; /* for some reason, elements with overflow-x: hidden set become focusable */ + + margin: 0 auto; +} + +/* Centers horizontally within the root container*/ +.onion-pattern-column { + width: calc(40 * var(--onion-radius, 50px)); /* room for 20 circles in a row */ + height: calc((2 + var(--sqrt3)) * var(--onion-radius, 50px)); /* room for 2 rows of circles */ + flex-shrink: 0; + overflow-x: hidden; /* clip extra circles on the sides */ + pointer-events: none; /* for some reason, elements with overflow-x: hidden set become focusable */ +} + +.onion-pattern-row { + width: calc(40 * var(--onion-radius, 50px)); /* room for 20 circles in a row */ + display: flex; + flex-direction: row; + position: relative; +} + +.onion-pattern-offset-row { + left: calc(-1 * var(--onion-radius, 50px)); + margin-top: calc((var(--sqrt3) - 2.0) * var(--onion-radius, 50px)); +} + +/* With borders, circles are 100x100 pixels*/ +.circle { + position: relative; + min-width: calc(2 * var(--onion-radius, 50px)); + min-height: calc(2 * var(--onion-radius, 50px)); + border-radius: 50%; + box-sizing: border-box; +} + +.inner { + position: absolute; + box-sizing: border-box; + border-radius: 50%; +} + +.inner:nth-child(1){ + width: 100%; + height: 100%; +} + +.inner:nth-child(2){ + transform: translate(20%, 20%); + width: calc(100% * 5/7); + height: calc(100% * 5/7); +} + +.inner:nth-child(3){ + transform: translate(calc(100% * 2/3), calc(100% * 2/3)); + width: calc(100% * 3/7); + height: calc(100% * 3/7); +} + +.inner:nth-child(4){ + transform: translate(300%, 300%); + width: calc(100% * 1/7); + height: calc(100% * 1/7); +} + +.solid { + background-color: var(--onion-color, #000); +} + +.border { + border: 4px solid var(--onion-color, #000); +} + +.dashed { + border: 4px dashed var(--onion-color, #000); +} + +.dotted { + border: 4px dotted var(--onion-color, #000); +} + +.bold { + border: 8px solid var(--onion-color, #000); +} + +.top-half { + width: calc(2 * var(--onion-radius, 50px)); + height: var(--onion-radius, 50px); + border-radius: var(--onion-radius, 50px) var(--onion-radius, 50px) 0 0; + box-sizing: border-box; +} + +.bottom-half { + width: calc(2 * var(--onion-radius, 50px)); + height: var(--onion-radius, 50px); + border-radius: 0 0 var(--onion-radius, 50px) var(--onion-radius, 50px); + box-sizing: border-box; +} + +.scaler { + position: absolute; + left:0; + bottom:0; +} \ No newline at end of file diff --git a/browser/themes/shared/onionPattern.inc.xhtml b/browser/themes/shared/onionPattern.inc.xhtml new file mode 100644 index 000000000000..6bbde93684a2 --- /dev/null +++ b/browser/themes/shared/onionPattern.inc.xhtml @@ -0,0 +1,210 @@ +<!-- + - The abstract onion pattern begins here. There are two + - "onion-pattern-row" elements, each containing 14 circles. The width + - of "onion-pattern-row" is fixed at a value that is wide enough so the + - circles are not distorted by the flex-based layout. The parent + - "onion-pattern-container" element has overflow-x: hidden and is designed + - to expand to the width of the page, until it reaches a maximum width + - that can accommodate all 14 circles. Since the rows are wider than + - most browser windows, typically the two rows of onions will fill the + - bottom of the page. On really wide pages, the onions are centered at + - the bottom of the page. +--> + +<div class="onion-pattern-container"> + <!-- for some reason, these two elements are focusable, seems related to + - flex css somehow; disable their tabindex to fix + --> + <div class="onion-pattern-crop" tabindex="-1"> + <div class="onion-pattern-column" tabindex="-1"> + <div class="onion-pattern-row"> + <div class="circle solid"></div> + + <div class="circle dashed"></div> + + <div class="circle"> + <div class="inner border"></div> + <div class="inner border"></div> + <div class="inner border"></div> + <div class="inner border"></div> + </div> + + <div class="circle"> + <div class="bottom-half solid"></div> + <div class="bottom-half dotted"></div> + </div> + + <div class="circle border"></div> + + <div class="circle"> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + </div> + + <div class="circle solid"></div> + + <div class="circle"> + <div class="inner dashed"></div> + <div class="inner dashed"></div> + <div class="inner dashed"></div> + <div class="inner dashed"></div> + </div> + + <div class="circle bold"></div> + + <div class="circle"> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + </div> + + <div class="circle"> + <div class="inner border"></div> + <div class="inner border"></div> + <div class="inner border"></div> + <div class="inner border"></div> + </div> + + <div class="circle bold"></div> + + <div class="circle"> + <div class="bottom-half solid"></div> + <div class="bottom-half solid"></div> + </div> + + <div class="circle"> + <div class="inner dashed"></div> + <div class="inner dashed"></div> + <div class="inner dashed"></div> + <div class="inner dashed"></div> + </div> + + <div class="circle dotted"></div> + + <div class="circle"> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + </div> + + <div class="circle solid"></div> + + <div class="circle"> + <div class="inner dashed"></div> + <div class="inner dashed"></div> + <div class="inner dashed"></div> + <div class="inner dashed"></div> + </div> + + <div class="circle bold"></div> + + <div class="circle dashed"></div> + </div> + + <div class="onion-pattern-row onion-pattern-offset-row"> + <div class="circle"> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + </div> + + <div class="circle"> + <div class="inner dashed"></div> + <div class="inner dashed"></div> + <div class="inner dashed"></div> + <div class="inner dashed"></div> + </div> + + <div class="circle bold"></div> + + <div class="circle solid"></div> + + <div class="circle"> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + </div> + + <div class="circle"> + <div class="top-half solid"></div> + <div class="top-half solid"></div> + </div> + + <div class="circle border"></div> + + <div class="circle dotted"></div> + + <div class="circle"> + <div class="top-half border"></div> + <div class="top-half dashed"></div> + </div> + + <div class="circle"> + <div class="inner border"></div> + <div class="inner border"></div> + <div class="inner border"></div> + <div class="inner border"></div> + </div> + + <div class="circle"> + <div class="top-half dotted"></div> + <div class="top-half solid"></div> + </div> + + <div class="circle"> + <div class="inner dashed"></div> + <div class="inner dashed"></div> + <div class="inner dashed"></div> + <div class="inner dashed"></div> + </div> + + <div class="circle dotted"></div> + + <div class="circle bold"></div> + + <div class="circle solid"></div> + + <div class="circle"> + <div class="top-half solid"></div> + <div class="top-half dotted"></div> + </div> + + <div class="circle"> + <div class="inner border"></div> + <div class="inner border"></div> + <div class="inner border"></div> + <div class="inner border"></div> + </div> + + <div class="circle"> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + <div class="inner dotted"></div> + </div> + + <div class="circle"> + <div class="inner border"></div> + <div class="inner border"></div> + <div class="inner border"></div> + <div class="inner border"></div> + </div> + + <div class="circle dotted"></div> + + <div class="circle"> + <div class="top-half solid"></div> + <div class="top-half solid"></div> + </div> + + <div class="circle dotted"></div> + </div> + </div> + </div> +</div> \ No newline at end of file diff --git a/browser/themes/shared/urlbar-searchbar.inc.css b/browser/themes/shared/urlbar-searchbar.inc.css index d3cc6bf7f024..297dbcdf444d 100644 --- a/browser/themes/shared/urlbar-searchbar.inc.css +++ b/browser/themes/shared/urlbar-searchbar.inc.css @@ -826,3 +826,5 @@ } %include ../../components/onionservices/content/onionlocation-urlbar.css +%include ../../components/torconnect/content/torconnect-urlbar.css + diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index afc872569519..e74851a6672c 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -16387,9 +16387,56 @@ void Document::RemoveToplevelLoadingDocument(Document* aDoc) { StylePrefersColorScheme Document::PrefersColorScheme( IgnoreRFP aIgnoreRFP) const { + + // tor-browser#27476 + // should this document ignore resist finger-printing settings with regards to + // setting the color scheme + // currently only enabled for about:torconnect but we could expand to other non- + // SystemPrincipal pages if we wish + const auto documentUsesPreferredColorScheme = [](auto const* constDocument) -> bool { + if (auto* document = const_cast<Document*>(constDocument); document != nullptr) { + auto uri = document->GetDocBaseURI(); + + // try and extract out our prepath and filepath portions of the uri to C-strings + nsAutoCString prePathStr, filePathStr; + if(NS_FAILED(uri->GetPrePath(prePathStr)) || + NS_FAILED(uri->GetFilePath(filePathStr))) { + return false; + } + + // stick them in string view for easy comparisons + std::string_view prePath(prePathStr.get(), prePathStr.Length()), + filePath(filePathStr.get(), filePathStr.Length()); + + // these about URIs will have the user's preferred color scheme exposed to them + // we can place other URIs here in the future if we wish + // see nsIURI.idl for URI part definitions + constexpr struct { + std::string_view prePath; + std::string_view filePath; + } allowedURIs[] = { + { "about:", "torconnect" }, + }; + + // check each uri in the allow list against this document's uri + // verify the prepath and the file path match + for(auto const& uri : allowedURIs) { + if (prePath == uri.prePath && + filePath == uri.filePath) { + // positive match means we can apply dark-mode to the page + return true; + } + } + } + + // do not allow if no match or other error + return false; + }; + if (aIgnoreRFP == IgnoreRFP::No && - nsContentUtils::ShouldResistFingerprinting(this)) { - return StylePrefersColorScheme::Light; + nsContentUtils::ShouldResistFingerprinting(this) && + !documentUsesPreferredColorScheme(this)) { + return StylePrefersColorScheme::Light; } if (nsPresContext* pc = GetPresContext()) { diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp index abe1e56d9714..759060f131ff 100644 --- a/dom/base/nsGlobalWindowOuter.cpp +++ b/dom/base/nsGlobalWindowOuter.cpp @@ -6082,6 +6082,8 @@ void nsGlobalWindowOuter::CloseOuter(bool aTrustedCaller) { NS_ENSURE_SUCCESS_VOID(rv); if (!StringBeginsWith(url, NS_LITERAL_STRING("about:neterror")) && + // we want about:torconnect pages to be able to close themselves after bootstrap + !StringBeginsWith(url, NS_LITERAL_STRING("about:torconnect")) && !HadOriginalOpener() && !aTrustedCaller) { bool allowClose = mAllowScriptsToClose || diff --git a/toolkit/modules/AsyncPrefs.jsm b/toolkit/modules/AsyncPrefs.jsm index aca86556cd5e..b81ff5e22b9b 100644 --- a/toolkit/modules/AsyncPrefs.jsm +++ b/toolkit/modules/AsyncPrefs.jsm @@ -18,6 +18,8 @@ const kAllowedPrefs = new Set([ "testing.allowed-prefs.some-char-pref", "testing.allowed-prefs.some-int-pref", + "extensions.torlauncher.quickstart", + "narrate.rate", "narrate.voice", diff --git a/toolkit/modules/RemotePageAccessManager.jsm b/toolkit/modules/RemotePageAccessManager.jsm index eceaa7c857de..0927391c2ba7 100644 --- a/toolkit/modules/RemotePageAccessManager.jsm +++ b/toolkit/modules/RemotePageAccessManager.jsm @@ -96,6 +96,7 @@ let RemotePageAccessManager = { RPMPrefIsLocked: ["security.tls.version.min"], RPMAddToHistogram: ["*"], RPMGetTorStrings: ["*"], + RPMSendQuery: ["ShouldShowTorConnect"], }, "about:newinstall": { RPMGetUpdateChannel: ["*"], @@ -179,6 +180,31 @@ let RemotePageAccessManager = { RPMAddMessageListener: ["*"], RPMRemoveMessageListener: ["*"], }, + "about:torconnect": { + RPMAddMessageListener: ["*"], + RPMSendAsyncMessage: [ + "OpenTorAdvancedPreferences", + "TorRetrieveBootstrapStatus", + "TorStopBootstrap", + ], + RPMSendQuery: [ + "GetDirection", + "GetLocalizedBootstrapStatus", + "GetTorStrings", + "TorBootstrapErrorOccurred", + "TorConnect", + "TorCopyLog", + "TorIsNetworkDisabled", + "TorLogHasWarnOrErr", + ], + RPMGetBoolPref: [ + "extensions.torlauncher.quickstart", + "extensions.torlauncher.prompt_at_startup", + ], + RPMSetBoolPref: [ + "extensions.torlauncher.quickstart", + ], + }, }, /** diff --git a/toolkit/mozapps/update/UpdateService.jsm b/toolkit/mozapps/update/UpdateService.jsm index 1fb397373151..79881cba42d6 100644 --- a/toolkit/mozapps/update/UpdateService.jsm +++ b/toolkit/mozapps/update/UpdateService.jsm @@ -12,6 +12,17 @@ const { AppConstants } = ChromeUtils.import( const { AUSTLMY } = ChromeUtils.import( "resource://gre/modules/UpdateTelemetry.jsm" ); + +const { TorProtocolService } = ChromeUtils.import( + "resource:///modules/TorProtocolService.jsm" +); + +function _shouldRegisterBootstrapObserver(errorCode) { + return errorCode == PROXY_SERVER_CONNECTION_REFUSED && + !TorProtocolService.isBootstrapDone() && + TorProtocolService.ownsTorDaemon; +}; + const { Bits, BitsRequest, @@ -201,6 +212,7 @@ const INVALID_UPDATER_STATUS_CODE = 99; // Custom update error codes const BACKGROUNDCHECK_MULTIPLE_FAILURES = 110; const NETWORK_ERROR_OFFLINE = 111; +const PROXY_SERVER_CONNECTION_REFUSED = 2152398920; // Error codes should be < 1000. Errors above 1000 represent http status codes const HTTP_ERROR_OFFSET = 1000; @@ -2220,6 +2232,9 @@ UpdateService.prototype = { case "network:offline-status-changed": this._offlineStatusChanged(data); break; + case "torconnect:bootstrap-complete": + this._bootstrapComplete(); + break; case "nsPref:changed": if (data == PREF_APP_UPDATE_LOG || data == PREF_APP_UPDATE_LOG_FILE) { gLogEnabled; // Assigning this before it is lazy-loaded is an error. @@ -2640,6 +2655,35 @@ UpdateService.prototype = { this._attemptResume(); }, + _registerBootstrapObserver: function AUS__registerBootstrapObserver() { + if (this._registeredBootstrapObserver) { + LOG( + "UpdateService:_registerBootstrapObserver - observer already registered" + ); + return; + } + + LOG( + "UpdateService:_registerBootstrapObserver - waiting for tor bootstrap to " + + "be complete, then forcing another check" + ); + + Services.obs.addObserver(this, "torconnect:bootstrap-complete"); + this._registeredBootstrapObserver = true; + }, + + _bootstrapComplete: function AUS__bootstrapComplete() { + Services.obs.removeObserver(this, "torconnect:bootstrap-complete"); + this._registeredBootstrapObserver = false; + + LOG( + "UpdateService:_bootstrapComplete - bootstrapping complete, forcing " + + "another background check" + ); + + this._attemptResume(); + }, + onCheckComplete: function AUS_onCheckComplete(request, updates) { this._selectAndInstallUpdate(updates); }, @@ -2659,6 +2703,11 @@ UpdateService.prototype = { AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_OFFLINE); } return; + } else if (_shouldRegisterBootstrapObserver(update.errorCode)) { + // Register boostrap observer to try again, but only when we own the + // tor process. + this._registerBootstrapObserver(); + return; } // Send the error code to telemetry @@ -5189,6 +5238,7 @@ Downloader.prototype = { var state = this._patch.state; var shouldShowPrompt = false; var shouldRegisterOnlineObserver = false; + var shouldRegisterBootstrapObserver = false; var shouldRetrySoon = false; var deleteActiveUpdate = false; var retryTimeout = Services.prefs.getIntPref( @@ -5266,7 +5316,18 @@ Downloader.prototype = { ); shouldRegisterOnlineObserver = true; deleteActiveUpdate = false; - + } else if(_shouldRegisterBootstrapObserver(status)) { + // Register a bootstrap observer to try again. + // The bootstrap observer will continue the incremental download by + // calling downloadUpdate on the active update which continues + // downloading the file from where it was. + LOG("Downloader:onStopRequest - not bootstrapped, register bootstrap observer: true"); + AUSTLMY.pingDownloadCode( + this.isCompleteUpdate, + AUSTLMY.DWNLD_RETRY_OFFLINE + ); + shouldRegisterBootstrapObserver = true; + deleteActiveUpdate = false; // Each of NS_ERROR_NET_TIMEOUT, ERROR_CONNECTION_REFUSED, // NS_ERROR_NET_RESET and NS_ERROR_DOCUMENT_NOT_CACHED can be returned // when disconnecting the internet while a download of a MAR is in @@ -5384,7 +5445,7 @@ Downloader.prototype = { // Only notify listeners about the stopped state if we // aren't handling an internal retry. - if (!shouldRetrySoon && !shouldRegisterOnlineObserver) { + if (!shouldRetrySoon && !shouldRegisterOnlineObserver && !shouldRegisterBootstrapObserver) { // Make shallow copy in case listeners remove themselves when called. var listeners = this._listeners.concat(); var listenerCount = listeners.length; @@ -5532,6 +5593,9 @@ Downloader.prototype = { if (shouldRegisterOnlineObserver) { LOG("Downloader:onStopRequest - Registering online observer"); this.updateService._registerOnlineObserver(); + } else if (shouldRegisterBootstrapObserver) { + LOG("Downloader:onStopRequest - Registering bootstrap observer"); + this.updateService._registerBootstrapObserver(); } else if (shouldRetrySoon) { LOG("Downloader:onStopRequest - Retrying soon"); this.updateService._consecutiveSocketErrors++; diff --git a/toolkit/themes/shared/in-content/info-pages.inc.css b/toolkit/themes/shared/in-content/info-pages.inc.css index 6943a3340e35..5b3c911a5aab 100644 --- a/toolkit/themes/shared/in-content/info-pages.inc.css +++ b/toolkit/themes/shared/in-content/info-pages.inc.css @@ -41,10 +41,11 @@ body.wide-container { background-image: url("chrome://global/skin/icons/info.svg"); background-position: left 0; background-repeat: no-repeat; - background-size: 1.6em; - margin-inline-start: -2.3em; - padding-inline-start: 2.3em; - font-size: 2.2em; + background-size: 3.0em; + margin-inline-start: -4.5em; + padding-inline-start: 4.5em; + margin-bottom: -2.0em; + font-size: 1.5em; -moz-context-properties: fill; fill: currentColor; } @@ -56,7 +57,10 @@ body.wide-container { .title-text { font-size: inherit; - padding-bottom: 0.4em; + padding-bottom: 2.0em !important; + line-height: 1.0em; + font-weight: bold; + vertical-align: top; } @media (max-width: 970px) { @@ -68,6 +72,7 @@ body.wide-container { .title-text { padding-top: 0; + vertical-align: middle !important; } } diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js index 2ff107b553b2..f8fa83574df7 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js @@ -70,6 +70,10 @@ function getGlobalScriptIncludes(scriptPath) { let match = line.match(globalScriptsRegExp); if (match) { let sourceFile = match[1] + .replace( + "chrome://browser/content/torconnect/", + "browser/components/torconnect/content/" + ) .replace( "chrome://browser/content/search/", "browser/components/search/content/"
1 0
0 0
[tor-browser/tor-browser-78.14.0esr-10.5-1] Bug 1642754 - Update prompts should not depend on how update was initiated r=bytesized
by sysrqb@torproject.org 04 Sep '21

04 Sep '21
commit ce4a0acd8a97a23fa194184808eefa3c1bd1126f Author: Mark Smith <mcs(a)pearlcrescent.com> Date: Wed Jun 17 19:24:09 2020 +0000 Bug 1642754 - Update prompts should not depend on how update was initiated r=bytesized Show update badge and doorhanger when entering the "pending" state for foreground updates. Differential Revision: https://phabricator.services.mozilla.com/D79903 --- toolkit/mozapps/update/UpdateService.jsm | 10 ++-------- .../browser/browser_aboutDialog_fc_downloadAuto.js | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/toolkit/mozapps/update/UpdateService.jsm b/toolkit/mozapps/update/UpdateService.jsm index 8dd397f628f5..1dc86a073646 100644 --- a/toolkit/mozapps/update/UpdateService.jsm +++ b/toolkit/mozapps/update/UpdateService.jsm @@ -5002,8 +5002,6 @@ Downloader.prototype = { } } - // XXX ehsan shouldShowPrompt should always be false here. - // But what happens when there is already a UI showing? var state = this._patch.state; var shouldShowPrompt = false; var shouldRegisterOnlineObserver = false; @@ -5044,9 +5042,7 @@ Downloader.prototype = { } else { state = STATE_PENDING; } - if (this.background) { - shouldShowPrompt = !getCanStageUpdates(); - } + shouldShowPrompt = !getCanStageUpdates(); AUSTLMY.pingDownloadCode(this.isCompleteUpdate, AUSTLMY.DWNLD_SUCCESS); // Tell the updater.exe we're ready to apply. @@ -5329,9 +5325,7 @@ Downloader.prototype = { LOG( "Downloader:onStopRequest - failed to stage update. Exception: " + e ); - if (this.background) { - shouldShowPrompt = true; - } + shouldShowPrompt = true; } } } diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_downloadAuto.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_downloadAuto.js index 6a8835251dec..be65ce8ddef1 100644 --- a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_downloadAuto.js +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_fc_downloadAuto.js @@ -15,7 +15,7 @@ add_task(async function aboutDialog_foregroundCheck_downloadAuto() { // Since the partial should be successful specify an invalid size for the // complete update. - let params = { queryString: "&invalidCompleteSize=1" }; + let params = { queryString: "&invalidCompleteSize=1&promptWaitTime=0" }; await runAboutDialogUpdateTest(params, [ { panelId: "checkingForUpdates", @@ -28,6 +28,22 @@ add_task(async function aboutDialog_foregroundCheck_downloadAuto() { continueFile: CONTINUE_DOWNLOAD, downloadInfo, }, + async function aboutDialog_restart_notification() { + is( + PanelUI.notificationPanel.state, + "closed", + "The window's doorhanger is closed." + ); + ok( + PanelUI.menuButton.hasAttribute("badge-status"), + "The window has a badge." + ); + is( + PanelUI.menuButton.getAttribute("badge-status"), + "update-restart", + "The restart badge is showing for the background window" + ); + }, { panelId: "apply", checkActiveUpdate: { state: STATE_PENDING },
1 0
0 0
[tor-browser/tor-browser-78.14.0esr-10.5-1] Bug 1642404 - add an option to show that an update is being downloaded r=bytesized, fluent-reviewers, flod
by sysrqb@torproject.org 04 Sep '21

04 Sep '21
commit 829fa204308052b43a3fc8bca4309cd0187e44cf Author: Mark Smith <mcs(a)pearlcrescent.com> Date: Mon Jun 22 20:24:46 2020 +0000 Bug 1642404 - add an option to show that an update is being downloaded r=bytesized,fluent-reviewers,flod Add support for a hidden preference named app.update.notifyDuringDownload that, when set to true, causes a "Downloading update" message to appear in the app menu during a MAR download. Clicking the message opens the about box so the user can see detailed progress information. Differential Revision: https://phabricator.services.mozilla.com/D77688 --- browser/app/profile/firefox.js | 4 ++ browser/components/BrowserGlue.jsm | 1 + .../customizableui/content/panelUI.inc.xhtml | 2 + .../components/customizableui/content/panelUI.js | 5 ++ .../test/browser_panelUINotifications.js | 62 ++++++++++++++++++++++ browser/locales/en-US/browser/appmenu.ftl | 2 + .../themes/shared/customizableui/panelUI.inc.css | 3 ++ browser/themes/shared/notification-icons.inc.css | 1 + browser/themes/shared/toolbarbutton-icons.inc.css | 1 + toolkit/mozapps/update/UpdateListener.jsm | 50 +++++++++++------ toolkit/mozapps/update/UpdateService.jsm | 27 ++++++++++ .../mozapps/update/tests/browser/browser.bits.ini | 1 + toolkit/mozapps/update/tests/browser/browser.ini | 1 + .../update/tests/browser/browser.legacy.bits.ini | 1 + .../update/tests/browser/browser.legacy.ini | 1 + .../browser/browser_aboutDialog_bc_downloading.js | 17 ++++++ .../browser_aboutDialog_bc_downloading_notify.js | 58 ++++++++++++++++++++ toolkit/mozapps/update/tests/data/shared.js | 1 + 18 files changed, 222 insertions(+), 16 deletions(-) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index a7e0bd808254..479c68efdd8c 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -131,6 +131,10 @@ pref("app.update.download.promptMaxAttempts", 2); // download a fresh installer. pref("app.update.elevation.promptMaxAttempts", 2); +// If set to true, a message will be displayed in the hamburger menu while +// an update is being downloaded. +pref("app.update.notifyDuringDownload", false); + // If set to true, the Update Service will automatically download updates if the // user can apply updates. This pref is no longer used on Windows, except as the // default value to migrate to the new location that this data is now stored diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index 70f5ad8b85e4..0a3555f26432 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -769,6 +769,7 @@ const global = this; const listeners = { observers: { + "update-downloading": ["UpdateListener"], "update-staged": ["UpdateListener"], "update-downloaded": ["UpdateListener"], "update-available": ["UpdateListener"], diff --git a/browser/components/customizableui/content/panelUI.inc.xhtml b/browser/components/customizableui/content/panelUI.inc.xhtml index e5c9c00c35e4..3a8b74b0a9f3 100644 --- a/browser/components/customizableui/content/panelUI.inc.xhtml +++ b/browser/components/customizableui/content/panelUI.inc.xhtml @@ -223,6 +223,8 @@ <vbox class="panel-subview-body"> <vbox id="appMenu-addon-banners"/> <toolbarbutton id="appMenu-update-banner" class="panel-banner-item" + data-l10n-id="appmenuitem-update-banner" + data-l10n-attrs="label-update-downloading" label-update-available="&updateAvailable.panelUI.label;" label-update-manual="&updateManual.panelUI.label;" label-update-unsupported="&updateUnsupported.panelUI.label;" diff --git a/browser/components/customizableui/content/panelUI.js b/browser/components/customizableui/content/panelUI.js index 1f6ed5caf839..a81be30f3ec7 100644 --- a/browser/components/customizableui/content/panelUI.js +++ b/browser/components/customizableui/content/panelUI.js @@ -65,6 +65,7 @@ const PanelUI = { Services.obs.addObserver(this, "fullscreen-nav-toolbox"); Services.obs.addObserver(this, "appMenu-notifications"); + Services.obs.addObserver(this, "show-update-progress"); XPCOMUtils.defineLazyPreferenceGetter( this, @@ -182,6 +183,7 @@ const PanelUI = { Services.obs.removeObserver(this, "fullscreen-nav-toolbox"); Services.obs.removeObserver(this, "appMenu-notifications"); + Services.obs.removeObserver(this, "show-update-progress"); window.removeEventListener("MozDOMFullscreen:Entered", this); window.removeEventListener("MozDOMFullscreen:Exited", this); @@ -271,6 +273,9 @@ const PanelUI = { this._notifications = AppMenuNotifications.notifications; this._updateNotifications(true); break; + case "show-update-progress": + openAboutDialog(); + break; } }, diff --git a/browser/components/customizableui/test/browser_panelUINotifications.js b/browser/components/customizableui/test/browser_panelUINotifications.js index 39ae5435c453..cab471bc946f 100644 --- a/browser/components/customizableui/test/browser_panelUINotifications.js +++ b/browser/components/customizableui/test/browser_panelUINotifications.js @@ -156,6 +156,68 @@ add_task(async function testSecondaryActionWorkflow() { }); }); +/** + * This tests that the PanelUI update downloading badge and banner + * notification are correctly displayed and that clicking the banner + * item calls the main action. + */ +add_task(async function testDownloadingBadge() { + let options = { + gBrowser: window.gBrowser, + url: "about:blank", + }; + + await BrowserTestUtils.withNewTab(options, async function(browser) { + let mainActionCalled = false; + let mainAction = { + callback: () => { + mainActionCalled = true; + }, + }; + // The downloading notification is always displayed in a dismissed state. + AppMenuNotifications.showNotification( + "update-downloading", + mainAction, + undefined, + { dismissed: true } + ); + is(PanelUI.notificationPanel.state, "closed", "doorhanger is closed."); + + is( + PanelUI.menuButton.getAttribute("badge-status"), + "update-downloading", + "Downloading badge is displaying on PanelUI button." + ); + + await gCUITestUtils.openMainMenu(); + isnot( + PanelUI.menuButton.getAttribute("badge-status"), + "update-downloading", + "Downloading badge is hidden on PanelUI button." + ); + let menuItem = PanelUI.mainView.querySelector(".panel-banner-item"); + is( + menuItem.label, + menuItem.getAttribute("label-update-downloading"), + "Showing correct label (downloading)" + ); + is(menuItem.hidden, false, "update-downloading menu item is showing."); + + await gCUITestUtils.hideMainMenu(); + is( + PanelUI.menuButton.getAttribute("badge-status"), + "update-downloading", + "Downloading badge is shown on PanelUI button." + ); + + await gCUITestUtils.openMainMenu(); + menuItem.click(); + ok(mainActionCalled, "Main action callback was called"); + + AppMenuNotifications.removeNotification(/.*/); + }); +}); + /** * We want to ensure a few things with this: * - Adding a doorhanger will make a badge disappear diff --git a/browser/locales/en-US/browser/appmenu.ftl b/browser/locales/en-US/browser/appmenu.ftl index 12fd2bec3e6a..3026b2597287 100644 --- a/browser/locales/en-US/browser/appmenu.ftl +++ b/browser/locales/en-US/browser/appmenu.ftl @@ -4,6 +4,8 @@ ## App Menu +appmenuitem-update-banner = + .label-update-downloading = Downloading { -brand-shorter-name } update appmenuitem-protection-dashboard-title = Protections Dashboard appmenuitem-customize-mode = .label = Customize… diff --git a/browser/themes/shared/customizableui/panelUI.inc.css b/browser/themes/shared/customizableui/panelUI.inc.css index 8a24f03c0ad6..c991daee0759 100644 --- a/browser/themes/shared/customizableui/panelUI.inc.css +++ b/browser/themes/shared/customizableui/panelUI.inc.css @@ -67,6 +67,7 @@ } #PanelUI-menu-button[badge-status="update-available"] > .toolbarbutton-badge-stack > .toolbarbutton-badge, +#PanelUI-menu-button[badge-status="update-downloading"] > .toolbarbutton-badge-stack > .toolbarbutton-badge, #PanelUI-menu-button[badge-status="update-manual"] > .toolbarbutton-badge-stack > .toolbarbutton-badge, #PanelUI-menu-button[badge-status="update-restart"] > .toolbarbutton-badge-stack > .toolbarbutton-badge, #PanelUI-menu-button[badge-status="update-unsupported"] > .toolbarbutton-badge-stack > .toolbarbutton-badge { @@ -80,6 +81,7 @@ } #PanelUI-menu-button[badge-status="update-available"] > .toolbarbutton-badge-stack > .toolbarbutton-badge, +#PanelUI-menu-button[badge-status="update-downloading"] > .toolbarbutton-badge-stack > .toolbarbutton-badge, #PanelUI-menu-button[badge-status="update-manual"] > .toolbarbutton-badge-stack > .toolbarbutton-badge, #PanelUI-menu-button[badge-status="update-restart"] > .toolbarbutton-badge-stack > .toolbarbutton-badge { background: #74BF43 url(chrome://browser/skin/update-badge.svg) no-repeat center; @@ -90,6 +92,7 @@ } .panel-banner-item[notificationid="update-available"]::after, +.panel-banner-item[notificationid="update-downloading"]::after, .panel-banner-item[notificationid="update-manual"]::after, .panel-banner-item[notificationid="update-restart"]::after { background: #74BF43 url(chrome://browser/skin/update-badge.svg) no-repeat center; diff --git a/browser/themes/shared/notification-icons.inc.css b/browser/themes/shared/notification-icons.inc.css index 74d861200f45..f17ddae9dc79 100644 --- a/browser/themes/shared/notification-icons.inc.css +++ b/browser/themes/shared/notification-icons.inc.css @@ -401,6 +401,7 @@ html|*#webRTC-previewVideo { /* UPDATE */ .popup-notification-icon[popupid="update-available"], +.popup-notification-icon[popupid="update-downloading"], .popup-notification-icon[popupid="update-manual"], .popup-notification-icon[popupid="update-restart"] { background: #74BF43 url(chrome://browser/skin/notification-icons/update.svg) no-repeat center; diff --git a/browser/themes/shared/toolbarbutton-icons.inc.css b/browser/themes/shared/toolbarbutton-icons.inc.css index 998537e1f57d..9514eb1d5338 100644 --- a/browser/themes/shared/toolbarbutton-icons.inc.css +++ b/browser/themes/shared/toolbarbutton-icons.inc.css @@ -290,6 +290,7 @@ toolbar[brighttext] { } #PanelUI-menu-button[badge-status="update-available"], +#PanelUI-menu-button[badge-status="update-downloading"], #PanelUI-menu-button[badge-status="update-manual"], #PanelUI-menu-button[badge-status="update-restart"] { list-style-image: url("chrome://browser/skin/menu-badged.svg"); diff --git a/toolkit/mozapps/update/UpdateListener.jsm b/toolkit/mozapps/update/UpdateListener.jsm index 17919e914b11..110640628771 100644 --- a/toolkit/mozapps/update/UpdateListener.jsm +++ b/toolkit/mozapps/update/UpdateListener.jsm @@ -113,16 +113,18 @@ var UpdateListener = { mainAction, beforeShowDoorhanger ) { + const addTelemetry = id => { + // No telemetry for the "downloading" state. + if (type !== "downloading") { + Services.telemetry.getHistogramById(id).add(type); + } + }; let action = { callback(win, fromDoorhanger) { if (fromDoorhanger) { - Services.telemetry - .getHistogramById("UPDATE_NOTIFICATION_MAIN_ACTION_DOORHANGER") - .add(type); + addTelemetry("UPDATE_NOTIFICATION_MAIN_ACTION_DOORHANGER"); } else { - Services.telemetry - .getHistogramById("UPDATE_NOTIFICATION_MAIN_ACTION_MENU") - .add(type); + addTelemetry("UPDATE_NOTIFICATION_MAIN_ACTION_MENU"); } mainAction(win); }, @@ -131,13 +133,10 @@ var UpdateListener = { let secondaryAction = { callback() { - Services.telemetry - .getHistogramById("UPDATE_NOTIFICATION_DISMISSED") - .add(type); + addTelemetry("UPDATE_NOTIFICATION_DISMISSED"); }, dismiss: true, }; - AppMenuNotifications.showNotification( "update-" + type, action, @@ -145,13 +144,9 @@ var UpdateListener = { { dismissed, beforeShowDoorhanger } ); if (dismissed) { - Services.telemetry - .getHistogramById("UPDATE_NOTIFICATION_BADGE_SHOWN") - .add(type); + addTelemetry("UPDATE_NOTIFICATION_BADGE_SHOWN"); } else { - Services.telemetry - .getHistogramById("UPDATE_NOTIFICATION_SHOWN") - .add(type); + addTelemetry("UPDATE_NOTIFICATION_SHOWN"); } }, @@ -205,6 +200,15 @@ var UpdateListener = { } }, + showUpdateDownloadingNotification() { + this.showUpdateNotification("downloading", true, true, () => { + // The user clicked on the "Downloading update" app menu item. + // Code in browser/components/customizableui/content/panelUI.js + // receives the following notification and opens the about dialog. + Services.obs.notifyObservers(null, "show-update-progress"); + }); + }, + handleUpdateError(update, status) { switch (status) { case "download-attempt-failed": @@ -287,6 +291,17 @@ var UpdateListener = { } }, + handleUpdateDownloading(status) { + switch (status) { + case "downloading": + this.showUpdateDownloadingNotification(); + break; + case "idle": + this.reset(); + break; + } + }, + observe(subject, topic, status) { let update = subject && subject.QueryInterface(Ci.nsIUpdate); @@ -299,6 +314,9 @@ var UpdateListener = { } this.handleUpdateAvailable(update, status); break; + case "update-downloading": + this.handleUpdateDownloading(status); + break; case "update-staged": case "update-downloaded": // An update check has found an update and downloaded / staged the diff --git a/toolkit/mozapps/update/UpdateService.jsm b/toolkit/mozapps/update/UpdateService.jsm index 0cc26f683078..8dd397f628f5 100644 --- a/toolkit/mozapps/update/UpdateService.jsm +++ b/toolkit/mozapps/update/UpdateService.jsm @@ -59,6 +59,7 @@ const PREF_APP_UPDATE_ELEVATE_ATTEMPTS = "app.update.elevate.attempts"; const PREF_APP_UPDATE_ELEVATE_MAXATTEMPTS = "app.update.elevate.maxAttempts"; const PREF_APP_UPDATE_LOG = "app.update.log"; const PREF_APP_UPDATE_LOG_FILE = "app.update.log.file"; +const PREF_APP_UPDATE_NOTIFYDURINGDOWNLOAD = "app.update.notifyDuringDownload"; const PREF_APP_UPDATE_PROMPTWAITTIME = "app.update.promptWaitTime"; const PREF_APP_UPDATE_SERVICE_ENABLED = "app.update.service.enabled"; const PREF_APP_UPDATE_SERVICE_ERRORS = "app.update.service.errors"; @@ -4446,6 +4447,24 @@ Downloader.prototype = { return selectedPatch; }, + /** + * Whether or not the user wants to be notified that an update is being + * downloaded. + */ + get _notifyDuringDownload() { + return Services.prefs.getBoolPref( + PREF_APP_UPDATE_NOTIFYDURINGDOWNLOAD, + false + ); + }, + + _notifyDownloadStatusObservers: function Downloader_notifyDownloadStatusObservers() { + if (this._notifyDuringDownload) { + let status = this.updateService.isDownloading ? "downloading" : "idle"; + Services.obs.notifyObservers(this._update, "update-downloading", status); + } + }, + /** * Whether or not we are currently downloading something. */ @@ -4687,6 +4706,9 @@ Downloader.prototype = { .getService(Ci.nsIUpdateManager) .saveUpdates(); } + + this._notifyDownloadStatusObservers(); + return STATE_DOWNLOADING; }, @@ -5193,6 +5215,11 @@ Downloader.prototype = { this._request = null; + // This notification must happen after _request is set to null so that + // the correct this.updateService.isDownloading value is available in + // _notifyDownloadStatusObservers(). + this._notifyDownloadStatusObservers(); + if (state == STATE_DOWNLOAD_FAILED) { var allFailed = true; // If we haven't already, attempt to download without BITS diff --git a/toolkit/mozapps/update/tests/browser/browser.bits.ini b/toolkit/mozapps/update/tests/browser/browser.bits.ini index 9355e22550f2..5a44d1e0f6bf 100644 --- a/toolkit/mozapps/update/tests/browser/browser.bits.ini +++ b/toolkit/mozapps/update/tests/browser/browser.bits.ini @@ -21,6 +21,7 @@ prefs = # About Dialog Application Update Tests [browser_aboutDialog_bc_downloading.js] [browser_aboutDialog_bc_downloading_staging.js] +[browser_aboutDialog_bc_downloading_notify.js] [browser_aboutDialog_bc_downloaded.js] [browser_aboutDialog_bc_downloaded_staging.js] [browser_aboutDialog_bc_downloaded_staged.js] diff --git a/toolkit/mozapps/update/tests/browser/browser.ini b/toolkit/mozapps/update/tests/browser/browser.ini index 5ce14c9c2633..c4f3fd055bbf 100644 --- a/toolkit/mozapps/update/tests/browser/browser.ini +++ b/toolkit/mozapps/update/tests/browser/browser.ini @@ -15,6 +15,7 @@ prefs = # About Dialog Application Update Tests [browser_aboutDialog_bc_downloading.js] [browser_aboutDialog_bc_downloading_staging.js] +[browser_aboutDialog_bc_downloading_notify.js] [browser_aboutDialog_bc_downloaded.js] [browser_aboutDialog_bc_downloaded_staging.js] [browser_aboutDialog_bc_downloaded_stagingFailure.js] diff --git a/toolkit/mozapps/update/tests/browser/browser.legacy.bits.ini b/toolkit/mozapps/update/tests/browser/browser.legacy.bits.ini index 7bf1f706a5b7..555eaea82cd6 100644 --- a/toolkit/mozapps/update/tests/browser/browser.legacy.bits.ini +++ b/toolkit/mozapps/update/tests/browser/browser.legacy.bits.ini @@ -20,6 +20,7 @@ prefs = # About Dialog Application Update Tests [browser_aboutDialog_bc_downloading.js] [browser_aboutDialog_bc_downloading_staging.js] +[browser_aboutDialog_bc_downloading_notify.js] [browser_aboutDialog_bc_downloaded.js] [browser_aboutDialog_bc_downloaded_staging.js] [browser_aboutDialog_bc_downloaded_staged.js] diff --git a/toolkit/mozapps/update/tests/browser/browser.legacy.ini b/toolkit/mozapps/update/tests/browser/browser.legacy.ini index 0cf61d64f42e..e3f681f53236 100644 --- a/toolkit/mozapps/update/tests/browser/browser.legacy.ini +++ b/toolkit/mozapps/update/tests/browser/browser.legacy.ini @@ -14,6 +14,7 @@ prefs = # About Dialog Application Update Tests [browser_aboutDialog_bc_downloading.js] [browser_aboutDialog_bc_downloading_staging.js] +[browser_aboutDialog_bc_downloading_notify.js] [browser_aboutDialog_bc_downloaded.js] [browser_aboutDialog_bc_downloaded_staging.js] [browser_aboutDialog_bc_downloaded_stagingFailure.js] diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading.js index 776d637512ad..67ddd65205da 100644 --- a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading.js +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading.js @@ -6,6 +6,10 @@ // Test for About Dialog background check for updates // with the About Dialog opened during downloading. add_task(async function aboutDialog_backgroundCheck_downloading() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_NOTIFYDURINGDOWNLOAD, false]], + }); + let downloadInfo = []; if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { downloadInfo[0] = { patchType: "partial", bitsResult: "0" }; @@ -21,6 +25,17 @@ add_task(async function aboutDialog_backgroundCheck_downloading() { waitForUpdateState: STATE_DOWNLOADING, }; await runAboutDialogUpdateTest(params, [ + async function aboutDialog_downloading() { + is( + PanelUI.notificationPanel.state, + "closed", + "The window's doorhanger is closed." + ); + ok( + !PanelUI.menuButton.hasAttribute("badge-status"), + "The window does not have a badge." + ); + }, { panelId: "downloading", checkActiveUpdate: { state: STATE_DOWNLOADING }, @@ -33,4 +48,6 @@ add_task(async function aboutDialog_backgroundCheck_downloading() { continueFile: null, }, ]); + + await SpecialPowers.popPrefEnv(); }); diff --git a/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading_notify.js b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading_notify.js new file mode 100644 index 000000000000..cf427b149a54 --- /dev/null +++ b/toolkit/mozapps/update/tests/browser/browser_aboutDialog_bc_downloading_notify.js @@ -0,0 +1,58 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test for About Dialog background check for updates with the +// "notify during download" feature turned on. +add_task(async function aboutDialog_backgroundCheck_downloading_notify() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_APP_UPDATE_NOTIFYDURINGDOWNLOAD, true]], + }); + + let downloadInfo = []; + if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) { + downloadInfo[0] = { patchType: "partial", bitsResult: "0" }; + } else { + downloadInfo[0] = { patchType: "partial", internalResult: "0" }; + } + + // Since the partial should be successful specify an invalid size for the + // complete update. + let params = { + queryString: "&useSlowDownloadMar=1&invalidCompleteSize=1", + backgroundUpdate: true, + waitForUpdateState: STATE_DOWNLOADING, + }; + await runAboutDialogUpdateTest(params, [ + async function aboutDialog_downloading_notification() { + is( + PanelUI.notificationPanel.state, + "closed", + "The window's doorhanger is closed." + ); + ok( + PanelUI.menuButton.hasAttribute("badge-status"), + "The window has a badge." + ); + is( + PanelUI.menuButton.getAttribute("badge-status"), + "update-downloading", + "The downloading badge is showing for the background window" + ); + }, + { + panelId: "downloading", + checkActiveUpdate: { state: STATE_DOWNLOADING }, + continueFile: CONTINUE_DOWNLOAD, + downloadInfo, + }, + { + panelId: "apply", + checkActiveUpdate: { state: STATE_PENDING }, + continueFile: null, + }, + ]); + + await SpecialPowers.popPrefEnv(); +}); diff --git a/toolkit/mozapps/update/tests/data/shared.js b/toolkit/mozapps/update/tests/data/shared.js index 51d9de99d7f2..5106aa5fc7a2 100644 --- a/toolkit/mozapps/update/tests/data/shared.js +++ b/toolkit/mozapps/update/tests/data/shared.js @@ -40,6 +40,7 @@ const PREF_APP_UPDATE_INTERVAL = "app.update.interval"; const PREF_APP_UPDATE_LASTUPDATETIME = "app.update.lastUpdateTime.background-update-timer"; const PREF_APP_UPDATE_LOG = "app.update.log"; +const PREF_APP_UPDATE_NOTIFYDURINGDOWNLOAD = "app.update.notifyDuringDownload"; const PREF_APP_UPDATE_PROMPTWAITTIME = "app.update.promptWaitTime"; const PREF_APP_UPDATE_RETRYTIMEOUT = "app.update.socket.retryTimeout"; const PREF_APP_UPDATE_SERVICE_ENABLED = "app.update.service.enabled";
1 0
0 0
[tor-browser/tor-browser-78.14.0esr-10.5-1] Bug 1585470 - Remove duplicate cpu-features.c definition when building GV without webrtc r=glandium
by sysrqb@torproject.org 04 Sep '21

04 Sep '21
commit 376be5b110ec6c50971f48b7a151094850e20172 Author: Matthew Finkel <Matthew.Finkel(a)gmail.com> Date: Thu Jul 9 19:10:34 2020 +0000 Bug 1585470 - Remove duplicate cpu-features.c definition when building GV without webrtc r=glandium Differential Revision: https://phabricator.services.mozilla.com/D82120 --- media/libaom/moz.build | 5 ----- 1 file changed, 5 deletions(-) diff --git a/media/libaom/moz.build b/media/libaom/moz.build index 2dec3de4581c..0b3ba0707df9 100644 --- a/media/libaom/moz.build +++ b/media/libaom/moz.build @@ -84,11 +84,6 @@ if CONFIG['OS_TARGET'] == 'Android': # the OS they're on, so do it for them. DEFINES['__linux__'] = True - if not CONFIG['MOZ_WEBRTC']: - SOURCES += [ - '%%%s/sources/android/cpufeatures/cpu-features.c' % CONFIG['ANDROID_NDK'], - ] - for f in SOURCES: if f.endswith('sse2.c'): SOURCES[f].flags += CONFIG['SSE2_FLAGS']
1 0
0 0
[tor-browser/tor-browser-78.14.0esr-10.5-1] TB3: Tor Browser's official .mozconfigs.
by sysrqb@torproject.org 04 Sep '21

04 Sep '21
commit 39ccb88c03e34821e04b91a9c507afa28bf3be1a Author: Mike Perry <mikeperry-git(a)torproject.org> Date: Mon May 6 15:51:06 2013 -0700 TB3: Tor Browser's official .mozconfigs. Also: Bug #9829.1: new .mozconfig file for the new cross-compiler and ESR24 Changes needed to build Mac in 64bit Bug 10715: Enable Webgl for mingw-w64 again. Disable ICU when cross-compiling; clean-up. Bug 15773: Enable ICU on OS X Bug 15990: Don't build the sandbox with mingw-w64 Bug 12761: Switch to ESR 38 for OS X Updating .mozconfig-asan Bug 12516: Compile hardenend Tor Browser with -fwrapv Bug 18331: Switch to Mozilla's toolchain for building Tor Browser for OS X Bug 17858: Cannot create incremental MARs for hardened builds. Define HOST_CFLAGS, etc. to avoid compiling programs such as mbsdiff (which is part of mar-tools and is not distributed to end-users) with ASan. Bug 13419: Add back ICU for Windows Bug 21239: Use GTK2 for ESR52 Linux builds Bug 23025: Add hardening flags for macOS Bug 24478: Enable debug assertions and tests in our ASan builds --enable-proxy-bypass-protection Bug 27597: ASan build option in tor-browser-build is broken Bug 27623 - Export MOZILLA_OFFICIAL during desktop builds This fixes a problem where some preferences had the wrong default value. Also see bug 27472 where we made a similar fix for Android. Bug 30463: Explicitly disable MOZ_TELEMETRY_REPORTING Bug 31450: Set proper BINDGEN_CFLAGS for ASan builds Add an --enable-tor-browser-data-outside-app-dir configure option Add --with-tor-browser-version configure option Bug 21849: Don't allow SSL key logging. Bug 31457: disable per-installation profiles The dedicated profiles (per-installation) feature does not interact well with our bundled profiles on Linux and Windows, and it also causes multiple profiles to be created on macOS under TorBrowser-Data. Bug 31935: Disable profile downgrade protection. Since Tor Browser does not support more than one profile, disable the prompt and associated code that offers to create one when a version downgrade situation is detected. Bug 32493: Disable MOZ_SERVICES_HEALTHREPORT Bug 25741 - TBA: Disable features at compile-time MOZ_NATIVE_DEVICES for casting and the media player MOZ_TELEMETRY_REPORTING for telemetry MOZ_DATA_REPORTING for all data reporting preferences (crashreport, telemetry, geo) Bug 25741 - TBA: Add default configure options in dedicated file Define MOZ_ANDROID_NETWORK_STATE and MOZ_ANDROID_LOCATION Bug 29859: Disable HLS support for now Add --disable-tor-launcher build option Add --enable-tor-browser-update build option Bug 33734: Set MOZ_NORMANDY to False Bug 33851: Omit Parental Controls. Bug 40061: Omit the Windows default browser agent from the build Bug 40107: Adapt .mozconfig-asan for ESR 78 Bug 40252: Add --enable-rust-simd to our tor-browser mozconfig files --- .mozconfig | 39 ++++++++++++++++++++++++ .mozconfig-android | 36 ++++++++++++++++++++++ .mozconfig-asan | 45 ++++++++++++++++++++++++++++ .mozconfig-mac | 56 +++++++++++++++++++++++++++++++++++ .mozconfig-mingw | 31 +++++++++++++++++++ browser/base/moz.build | 3 ++ browser/installer/Makefile.in | 8 +++++ browser/moz.configure | 8 ++--- build/moz.configure/old.configure | 6 ++++ mobile/android/confvars.sh | 9 ++++++ mobile/android/geckoview/build.gradle | 1 + mobile/android/moz.configure | 17 +++++++++-- mobile/android/torbrowser.configure | 30 +++++++++++++++++++ old-configure.in | 49 ++++++++++++++++++++++++++++++ security/moz.build | 2 +- security/nss/lib/ssl/Makefile | 2 +- toolkit/modules/AppConstants.jsm | 9 ++++++ toolkit/modules/moz.build | 3 ++ 18 files changed, 346 insertions(+), 8 deletions(-) diff --git a/.mozconfig b/.mozconfig new file mode 100755 index 000000000000..18cd1f9b6487 --- /dev/null +++ b/.mozconfig @@ -0,0 +1,39 @@ +. $topsrcdir/browser/config/mozconfig + +# This mozconfig file is not used in official Tor Browser builds. +# It is only intended to be used when doing incremental Linux builds +# during development. The platform-specific mozconfig configuration +# files used in official Tor Browser releases can be found in the +# tor-browser-build repo: +# https://gitweb.torproject.org/builders/tor-browser-build.git/ +# under: +# tor-browser-build/projects/firefox/mozconfig-$OS-$ARCH + +mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-@CONFIG_GUESS@ +mk_add_options MOZ_APP_DISPLAYNAME="Tor Browser" +export MOZILLA_OFFICIAL=1 + +ac_add_options --enable-optimize +ac_add_options --enable-rust-simd +ac_add_options --enable-official-branding + +# Let's support GTK3 for ESR60 +ac_add_options --enable-default-toolkit=cairo-gtk3 + +ac_add_options --disable-strip +ac_add_options --disable-install-strip +ac_add_options --disable-tests +ac_add_options --disable-debug +ac_add_options --disable-crashreporter +ac_add_options --disable-webrtc +ac_add_options --disable-parental-controls +# Let's make sure no preference is enabling either Adobe's or Google's CDM. +ac_add_options --disable-eme +ac_add_options --enable-proxy-bypass-protection + +# Disable telemetry +ac_add_options MOZ_TELEMETRY_REPORTING= + +ac_add_options --disable-tor-launcher +ac_add_options --with-tor-browser-version=dev-build +ac_add_options --disable-tor-browser-update diff --git a/.mozconfig-android b/.mozconfig-android new file mode 100755 index 000000000000..50015ec615ef --- /dev/null +++ b/.mozconfig-android @@ -0,0 +1,36 @@ +mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-arm-linux-androideabi +mk_add_options MOZ_APP_DISPLAYNAME="Tor Browser" +export MOZILLA_OFFICIAL=1 + +ac_add_options --enable-optimize +ac_add_options --enable-rust-simd +ac_add_options --enable-official-branding + +# Android +ac_add_options --enable-application=mobile/android +ac_add_options --target=arm-linux-androideabi +ac_add_options --with-android-ndk="$NDK_BASE" #Enter the android ndk location(ndk r17b) +ac_add_options --with-android-sdk="$SDK_BASE" #Enter the android sdk location +ac_add_options --with-branding=mobile/android/branding/alpha + +# Use Mozilla's Clang blobs +CC="$HOME/.mozbuild/clang/bin/clang" +CXX="$HOME/.mozbuild/clang/bin/clang++" + +#enable ccache to set amount of cache assigned for build. +ac_add_options --with-ccache + +ac_add_options --enable-strip +ac_add_options --disable-tests +ac_add_options --disable-debug +ac_add_options --disable-rust-debug + +ac_add_options --disable-updater +ac_add_options --disable-crashreporter +ac_add_options --disable-webrtc +ac_add_options --disable-parental-controls + +ac_add_options --enable-proxy-bypass-protection + +# Disable telemetry +ac_add_options MOZ_TELEMETRY_REPORTING= diff --git a/.mozconfig-asan b/.mozconfig-asan new file mode 100644 index 000000000000..98ea6ac6f3fe --- /dev/null +++ b/.mozconfig-asan @@ -0,0 +1,45 @@ +. $topsrcdir/browser/config/mozconfig + +export CFLAGS="-fsanitize=address -Dxmalloc=myxmalloc" +export CXXFLAGS="-fsanitize=address -Dxmalloc=myxmalloc" +# We need to add -ldl explicitely due to bug 1213698 +export LDFLAGS="-fsanitize=address -ldl" + +# Define HOST_CFLAGS, etc. to avoid compiling programs such as mbsdiff +# (which is part of mar-tools and is not distributed to end-users) with +# ASan. See bug 17858. +export HOST_CFLAGS="" +export HOST_CXXFLAGS="" +export HOST_LDFLAGS="-ldl" + +mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-@CONFIG_GUESS@ +mk_add_options MOZ_APP_DISPLAYNAME="Tor Browser" +export MOZILLA_OFFICIAL=1 +export BINDGEN_CFLAGS='--gcc-toolchain=/var/tmp/dist/gcc' + +ac_add_options --enable-address-sanitizer +ac_add_options --disable-jemalloc +ac_add_options --disable-elf-hack +ac_add_options --with-clang-path=/var/tmp/dist/clang/bin/clang + +ac_add_options --enable-optimize +ac_add_options --enable-rust-simd +ac_add_options --enable-official-branding + +# Let's support GTK3 for ESR60 +ac_add_options --enable-default-toolkit=cairo-gtk3 + +ac_add_options --enable-tor-browser-update + +ac_add_options --disable-strip +ac_add_options --disable-install-strip +ac_add_options --disable-tests +ac_add_options --disable-debug +ac_add_options --disable-crashreporter +ac_add_options --disable-webrtc +ac_add_options --disable-parental-controls +ac_add_options --disable-eme +ac_add_options --enable-proxy-bypass-protection + +# Disable telemetry +ac_add_options MOZ_TELEMETRY_REPORTING= diff --git a/.mozconfig-mac b/.mozconfig-mac new file mode 100644 index 000000000000..26e2b6b92fdb --- /dev/null +++ b/.mozconfig-mac @@ -0,0 +1,56 @@ +# ld needs libLTO.so from llvm +mk_add_options "export LD_LIBRARY_PATH=$topsrcdir/clang/lib" + +CROSS_CCTOOLS_PATH=$topsrcdir/cctools +CROSS_SYSROOT=$topsrcdir/MacOSX10.7.sdk +CROSS_PRIVATE_FRAMEWORKS=$CROSS_SYSROOT/System/Library/PrivateFrameworks +HARDENING_FLAGS="-Werror=format -Werror=format-security -fstack-protector-strong -D_FORTIFY_SOURCE=2" +FLAGS="-target x86_64-apple-darwin10 -mlinker-version=136 -B $CROSS_CCTOOLS_PATH/bin -isysroot $CROSS_SYSROOT $HARDENING_FLAGS" + +export CC="$topsrcdir/clang/bin/clang $FLAGS" +export CXX="$topsrcdir/clang/bin/clang++ $FLAGS" +export CPP="$topsrcdir/clang/bin/clang $FLAGS -E" +export LLVMCONFIG=$topsrcdir/clang/bin/llvm-config +export LDFLAGS="-Wl,-syslibroot,$CROSS_SYSROOT -Wl,-dead_strip -Wl,-pie" +export TOOLCHAIN_PREFIX=$CROSS_CCTOOLS_PATH/bin/x86_64-apple-darwin10- +#TODO: bug 1184202 - would be nice if these could be detected with TOOLCHAIN_PREFIX automatically +export AR=${TOOLCHAIN_PREFIX}ar +export RANLIB=${TOOLCHAIN_PREFIX}ranlib +export STRIP=${TOOLCHAIN_PREFIX}strip +export OTOOL=${TOOLCHAIN_PREFIX}otool +export DSYMUTIL=$topsrcdir/clang/bin/llvm-dsymutil + +export HOST_CC="$topsrcdir/clang/bin/clang" +export HOST_CXX="$topsrcdir/clang/bin/clang++" +export HOST_CPP="$topsrcdir/clang/bin/clang -E" +export HOST_CFLAGS="-g" +export HOST_CXXFLAGS="-g" +export HOST_LDFLAGS="-g" + +ac_add_options --target=x86_64-apple-darwin +ac_add_options --with-macos-private-frameworks=$CROSS_PRIVATE_FRAMEWORKS + +mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-macos +mk_add_options MOZ_APP_DISPLAYNAME="Tor Browser" +export MOZILLA_OFFICIAL=1 + +ac_add_options --enable-application=browser +ac_add_options --enable-strip +ac_add_options --enable-official-branding +ac_add_options --enable-optimize +ac_add_options --enable-rust-simd +ac_add_options --disable-debug + +ac_add_options --enable-tor-browser-data-outside-app-dir +ac_add_options --enable-tor-browser-update + +ac_add_options --disable-crashreporter +ac_add_options --disable-webrtc +ac_add_options --disable-parental-controls +ac_add_options --disable-tests +# Let's make sure no preference is enabling either Adobe's or Google's CDM. +ac_add_options --disable-eme +ac_add_options --enable-proxy-bypass-protection + +# Disable telemetry +ac_add_options MOZ_TELEMETRY_REPORTING= diff --git a/.mozconfig-mingw b/.mozconfig-mingw new file mode 100644 index 000000000000..3ec6ff18a3e9 --- /dev/null +++ b/.mozconfig-mingw @@ -0,0 +1,31 @@ +CROSS_COMPILE=1 + +ac_add_options --enable-application=browser +ac_add_options --target=i686-w64-mingw32 +ac_add_options --with-toolchain-prefix=i686-w64-mingw32- +ac_add_options --enable-default-toolkit=cairo-windows +mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/obj-mingw +mk_add_options MOZ_APP_DISPLAYNAME="Tor Browser" +export MOZILLA_OFFICIAL=1 + +ac_add_options --disable-debug +ac_add_options --enable-optimize +ac_add_options --enable-rust-simd +ac_add_options --enable-strip +ac_add_options --enable-official-branding + +ac_add_options --enable-tor-browser-update +ac_add_options --disable-bits-download + +# Let's make sure no preference is enabling either Adobe's or Google's CDM. +ac_add_options --disable-eme +ac_add_options --disable-crashreporter +ac_add_options --disable-maintenance-service +ac_add_options --disable-webrtc +ac_add_options --disable-parental-controls +ac_add_options --disable-tests +ac_add_options --enable-proxy-bypass-protection + +# Disable telemetry +ac_add_options MOZ_TELEMETRY_REPORTING= +ac_add_options --disable-default-browser-agent diff --git a/browser/base/moz.build b/browser/base/moz.build index e136e0986a3c..ebb4cbf79fd0 100644 --- a/browser/base/moz.build +++ b/browser/base/moz.build @@ -71,4 +71,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk', 'cocoa'): if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk'): DEFINES['MENUBAR_CAN_AUTOHIDE'] = 1 +if CONFIG['TOR_BROWSER_UPDATE']: + DEFINES['TOR_BROWSER_UPDATE'] = 1 + JAR_MANIFESTS += ['jar.mn'] diff --git a/browser/installer/Makefile.in b/browser/installer/Makefile.in index b861ad214a64..0325f0ffab9a 100644 --- a/browser/installer/Makefile.in +++ b/browser/installer/Makefile.in @@ -82,6 +82,14 @@ endif endif endif +ifdef TOR_BROWSER_DISABLE_TOR_LAUNCHER +DEFINES += -DTOR_BROWSER_DISABLE_TOR_LAUNCHER +endif + +ifdef TOR_BROWSER_UPDATE +DEFINES += -DTOR_BROWSER_UPDATE +endif + ifneq (,$(filter WINNT Darwin Android,$(OS_TARGET))) DEFINES += -DMOZ_SHARED_MOZGLUE=1 endif diff --git a/browser/moz.configure b/browser/moz.configure index a251050feb9b..3b6b377235ca 100644 --- a/browser/moz.configure +++ b/browser/moz.configure @@ -5,11 +5,11 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. imply_option('MOZ_PLACES', True) -imply_option('MOZ_SERVICES_HEALTHREPORT', True) +imply_option('MOZ_SERVICES_HEALTHREPORT', False) imply_option('MOZ_SERVICES_SYNC', True) -imply_option('MOZ_DEDICATED_PROFILES', True) -imply_option('MOZ_BLOCK_PROFILE_DOWNGRADE', True) -imply_option('MOZ_NORMANDY', True) +imply_option('MOZ_DEDICATED_PROFILES', False) +imply_option('MOZ_BLOCK_PROFILE_DOWNGRADE', False) +imply_option('MOZ_NORMANDY', False) with only_when(target_is_linux & compile_environment): option(env='MOZ_NO_PIE_COMPAT', diff --git a/build/moz.configure/old.configure b/build/moz.configure/old.configure index 136abbcafa69..9b663a1bf4f1 100644 --- a/build/moz.configure/old.configure +++ b/build/moz.configure/old.configure @@ -248,6 +248,12 @@ def old_configure_options(*options): '--with-user-appdir', '--x-includes', '--x-libraries', + + # Tor additions. + '--with-tor-browser-version', + '--enable-tor-browser-update', + '--enable-tor-browser-data-outside-app-dir', + '--enable-tor-launcher', ) def prepare_configure_options(host, target, all_options, *options): # old-configure only supports the options listed in @old_configure_options diff --git a/mobile/android/confvars.sh b/mobile/android/confvars.sh index 77191834d240..47a6a8dbae1d 100644 --- a/mobile/android/confvars.sh +++ b/mobile/android/confvars.sh @@ -30,9 +30,18 @@ MOZ_ANDROID_BROWSER_INTENT_CLASS=org.mozilla.gecko.BrowserApp MOZ_NO_SMART_CARDS=1 +# Adds MIME-type support for raw video MOZ_RAW=1 # use custom widget for html:select MOZ_USE_NATIVE_POPUP_WINDOWS=1 MOZ_APP_ID={aa3c5121-dab2-40e2-81ca-7ea25febc110} + +### Tor Browser for Android ### + +# Disable telemetry at compile-time +unset MOZ_TELEMETRY_REPORTING + +# Disable data reporting at compile-time +unset MOZ_DATA_REPORTING diff --git a/mobile/android/geckoview/build.gradle b/mobile/android/geckoview/build.gradle index 82d36c179c92..c1b51537031d 100644 --- a/mobile/android/geckoview/build.gradle +++ b/mobile/android/geckoview/build.gradle @@ -92,6 +92,7 @@ android { buildConfigField 'String', "MOZ_APP_DISPLAYNAME", "\"${mozconfig.substs.MOZ_APP_DISPLAYNAME}\""; buildConfigField 'String', "MOZ_APP_UA_NAME", "\"${mozconfig.substs.MOZ_APP_UA_NAME}\""; buildConfigField 'String', "MOZ_UPDATE_CHANNEL", "\"${mozconfig.substs.MOZ_UPDATE_CHANNEL}\""; + buildConfigField 'String', "TOR_BROWSER_VERSION", "\"${mozconfig.substs.TOR_BROWSER_VERSION}\""; // MOZILLA_VERSION is oddly quoted from autoconf, but we don't have to handle it specially in Gradle. buildConfigField 'String', "MOZILLA_VERSION", "\"${mozconfig.substs.MOZILLA_VERSION}\""; diff --git a/mobile/android/moz.configure b/mobile/android/moz.configure index fa510f0a57d3..f7b4df4ac24a 100644 --- a/mobile/android/moz.configure +++ b/mobile/android/moz.configure @@ -10,7 +10,7 @@ project_flag('MOZ_ANDROID_EXCLUDE_FONTS', project_flag('MOZ_ANDROID_HLS_SUPPORT', help='Enable HLS (HTTP Live Streaming) support (currently using the ExoPlayer library)', - default=True) + default=False) option(env='FENNEC_NIGHTLY', help='Enable experimental code for Fennec Nightly users. NOTE: This is *not* equivalent ' @@ -26,9 +26,12 @@ def fennec_nightly(nightly): return bool(nightly) imply_option('MOZ_NORMANDY', False) -imply_option('MOZ_SERVICES_HEALTHREPORT', True) imply_option('MOZ_ANDROID_HISTORY', True) imply_option('--enable-small-chunk-size', True) +# Comment this so we can imply |False| in torbrowser.configure +# The Build system doesn't allow multiple imply_option() +# calls with the same key. +#imply_option('MOZ_SERVICES_HEALTHREPORT', True) @depends(target) def check_target(target): @@ -39,6 +42,8 @@ def check_target(target): 'Build_Instructions/Simple_Firefox_for_Android_build ' 'for more information about the necessary options.') +include('torbrowser.configure') + include('../../toolkit/moz.configure') include('../../build/moz.configure/android-sdk.configure') include('../../build/moz.configure/java.configure') @@ -50,3 +55,11 @@ option(env='MOZ_ANDROID_FAT_AAR_ARCHITECTURES', help='Comma-separated list of Android CPU architectures like "armeabi-v7a,arm64-v8a,x86,x86_64"') set_config('MOZ_ANDROID_FAT_AAR_ARCHITECTURES', depends('MOZ_ANDROID_FAT_AAR_ARCHITECTURES')(lambda x: x)) + +project_flag('MOZ_ANDROID_NETWORK_STATE', + help='Include permission for accessing WiFi/network state on Android', + default=False) + +project_flag('MOZ_ANDROID_LOCATION', + help='Include permission for accessing fine and course-grain Location on Android', + default=False) diff --git a/mobile/android/torbrowser.configure b/mobile/android/torbrowser.configure new file mode 100644 index 000000000000..2ff6215eedc9 --- /dev/null +++ b/mobile/android/torbrowser.configure @@ -0,0 +1,30 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +# Set Tor Browser default config + +imply_option('MOZ_ANDROID_EXCLUDE_FONTS', False) + +# Disable uploading crash reports and dump files to an external server +# This is still configured in old-configure. Uncomment when this moves +# to the python config +#imply_option('MOZ_CRASHREPORTER', False) + +# Disable uploading information about the browser configuration and +# performance to an external server +imply_option('MOZ_SERVICES_HEALTHREPORT', False) + +# Disable creating telemetry and data reports that are uploaded to an +# external server +# These aren't actually configure options. These are disabled in +# confvars.sh, but they look like configure options so we'll document +# them here, as well. +#XXX: no confvars.sh here +#imply_option('MOZ_TELEMETRY_REPORTING', False) +#imply_option('MOZ_DATA_REPORTING', False) + +imply_option('MOZ_ANDROID_NETWORK_STATE', False); +imply_option('MOZ_ANDROID_LOCATION', False); diff --git a/old-configure.in b/old-configure.in index dfb072b19cfb..2c3308a27657 100644 --- a/old-configure.in +++ b/old-configure.in @@ -1966,6 +1966,55 @@ if test -n "$MOZ_UPDATER"; then AC_DEFINE(MOZ_UPDATER) fi +dnl ======================================================== +dnl Tor additions +dnl ======================================================== +MOZ_ARG_WITH_STRING(tor-browser-version, +[ --with-tor-browser-version=VERSION + Set Tor Browser version, e.g., 7.0a1], + TOR_BROWSER_VERSION="$withval") + +if test -z "$TOR_BROWSER_VERSION"; then + AC_MSG_ERROR([--with-tor-browser-version is required for Tor Browser.]) +fi + +MOZ_ARG_ENABLE_BOOL(tor-browser-update, +[ --enable-tor-browser-update + Enable Tor Browser update], + TOR_BROWSER_UPDATE=1, + TOR_BROWSER_UPDATE= ) + +if test -n "$TOR_BROWSER_UPDATE"; then + AC_DEFINE(TOR_BROWSER_UPDATE) +fi + +MOZ_ARG_ENABLE_BOOL(tor-browser-data-outside-app-dir, +[ --enable-tor-browser-data-outside-app-dir + Enable Tor Browser data outside of app directory], + TOR_BROWSER_DATA_OUTSIDE_APP_DIR=1, + TOR_BROWSER_DATA_OUTSIDE_APP_DIR= ) + +if test -n "$TOR_BROWSER_DATA_OUTSIDE_APP_DIR"; then + AC_DEFINE(TOR_BROWSER_DATA_OUTSIDE_APP_DIR) +fi + +AC_DEFINE_UNQUOTED(TOR_BROWSER_VERSION,$TOR_BROWSER_VERSION) +AC_DEFINE_UNQUOTED(TOR_BROWSER_VERSION_QUOTED,"$TOR_BROWSER_VERSION") +AC_SUBST(TOR_BROWSER_UPDATE) +AC_SUBST(TOR_BROWSER_DATA_OUTSIDE_APP_DIR) + +MOZ_ARG_DISABLE_BOOL(tor-launcher, +[ --disable-tor-launcher + Do not include Tor Launcher], + TOR_BROWSER_DISABLE_TOR_LAUNCHER=1, + TOR_BROWSER_DISABLE_TOR_LAUNCHER=) + +if test -n "$TOR_BROWSER_DISABLE_TOR_LAUNCHER"; then + AC_DEFINE(TOR_BROWSER_DISABLE_TOR_LAUNCHER) +fi + +AC_SUBST(TOR_BROWSER_DISABLE_TOR_LAUNCHER) + dnl ======================================================== dnl parental controls (for Windows Vista) dnl ======================================================== diff --git a/security/moz.build b/security/moz.build index dec6f3ef7e21..f00f9fe5d7a7 100644 --- a/security/moz.build +++ b/security/moz.build @@ -85,7 +85,7 @@ gyp_vars['nss_dist_obj_dir'] = '$PRODUCT_DIR/dist/bin' gyp_vars['disable_tests'] = 1 gyp_vars['disable_dbm'] = 1 gyp_vars['disable_libpkix'] = 1 -gyp_vars['enable_sslkeylogfile'] = 1 +gyp_vars['enable_sslkeylogfile'] = 0 # pkg-config won't reliably find zlib on our builders, so just force it. # System zlib is only used for modutil and signtool unless # SSL zlib is enabled, which we are disabling immediately below this. diff --git a/security/nss/lib/ssl/Makefile b/security/nss/lib/ssl/Makefile index 8a8b06f4b508..90571bb3e256 100644 --- a/security/nss/lib/ssl/Makefile +++ b/security/nss/lib/ssl/Makefile @@ -41,7 +41,7 @@ endif # Enable key logging by default in debug builds, but not opt builds. # Logging still needs to be enabled at runtime through env vars. -NSS_ALLOW_SSLKEYLOGFILE ?= $(if $(BUILD_OPT),0,1) +NSS_ALLOW_SSLKEYLOGFILE ?= 0 ifeq (1,$(NSS_ALLOW_SSLKEYLOGFILE)) DEFINES += -DNSS_ALLOW_SSLKEYLOGFILE=1 endif diff --git a/toolkit/modules/AppConstants.jsm b/toolkit/modules/AppConstants.jsm index 9b035435aed6..cd8ca2659626 100644 --- a/toolkit/modules/AppConstants.jsm +++ b/toolkit/modules/AppConstants.jsm @@ -341,6 +341,8 @@ this.AppConstants = Object.freeze({ MOZ_WIDGET_TOOLKIT: "@MOZ_WIDGET_TOOLKIT@", ANDROID_PACKAGE_NAME: "@ANDROID_PACKAGE_NAME@", + TOR_BROWSER_VERSION: "@TOR_BROWSER_VERSION@", + DEBUG_JS_MODULES: "@DEBUG_JS_MODULES@", MOZ_BING_API_CLIENTID: "@MOZ_BING_API_CLIENTID@", @@ -418,4 +420,11 @@ this.AppConstants = Object.freeze({ #else false, #endif + + TOR_BROWSER_UPDATE: +#ifdef TOR_BROWSER_UPDATE + true, +#else + false, +#endif }); diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build index e5858122fa1c..f000f35c126f 100644 --- a/toolkit/modules/moz.build +++ b/toolkit/modules/moz.build @@ -296,6 +296,9 @@ for var in ('MOZ_ALLOW_ADDON_SIDELOAD', if CONFIG[var]: DEFINES[var] = True +if CONFIG['TOR_BROWSER_UPDATE']: + DEFINES['TOR_BROWSER_UPDATE'] = 1 + JAR_MANIFESTS += ['jar.mn'] DEFINES['TOPOBJDIR'] = TOPOBJDIR
1 0
0 0
[tor-browser/tor-browser-78.14.0esr-10.5-1] Bug 12620: TorBrowser regression tests
by sysrqb@torproject.org 04 Sep '21

04 Sep '21
commit 5e096e9599d40a8c7b33a5c0799ae6ef6baa5b5a Author: Arthur Edelstein <arthuredelstein(a)gmail.com> Date: Wed Aug 27 16:25:00 2014 -0700 Bug 12620: TorBrowser regression tests Regression tests for Bug #2950: Make Permissions Manager memory-only Regression tests for TB4: Tor Browser's Firefox preference overrides. Note: many more functional tests could be made here Regression tests for #2874: Block Components.interfaces from content Bug 18923: Add a script to run all Tor Browser specific tests Regression tests for Bug #16441: Suppress "Reset Tor Browser" prompt. --- run-tbb-tests | 66 +++++++++++++++++++++++++++++++++++ tbb-tests-ignore.txt | 13 +++++++ tbb-tests/browser.ini | 5 +++ tbb-tests/browser_tor_TB4.js | 35 +++++++++++++++++++ tbb-tests/browser_tor_bug2950.js | 74 ++++++++++++++++++++++++++++++++++++++++ tbb-tests/mochitest.ini | 3 ++ tbb-tests/moz.build | 10 ++++++ tbb-tests/test_tor_bug2874.html | 25 ++++++++++++++ toolkit/toolkit.mozbuild | 3 +- 9 files changed, 233 insertions(+), 1 deletion(-) diff --git a/run-tbb-tests b/run-tbb-tests new file mode 100755 index 000000000000..bc09839f9f05 --- /dev/null +++ b/run-tbb-tests @@ -0,0 +1,66 @@ +#!/bin/bash + +# This script runs all the Mochitest tests that have been added or +# modified since the last ffxbld commit. +# +# It does not currently run XPCShell tests. We should change this if we +# start using this type or other types of tests. +# +# The logs of the tests are stored in the tbb-tests.log file. +# Ignored tests are listed in the tbb-tests-ignore.txt file. +# +# https://trac.torproject.org/projects/tor/ticket/18923 + +IFS=$'\n' + +if [ -n "$USE_TESTS_LIST" ] && [ -f tbb-tests-list.txt ] +then + echo "Using tests list from file tbb-tests-list.txt" + tests=($(cat tbb-tests-list.txt)) +else + ffxbld_commit=$(git log -500 --format='oneline' | grep "TB3: Tor Browser's official .mozconfigs." \ + | head -1 | cut -d ' ' -f 1) + + tests=($(git diff --name-status "$ffxbld_commit" HEAD | \ + grep -e '^[AM].*/test_[^/]\+\.\(html\|xul\)$' \ + -e '^[AM].*/browser_[^/]\+\.js$' \ + | sed 's/^[AM]\s\+//')) +fi + +echo 'The following tests will be run:' +for i in "${!tests[@]}" +do + if [ -z "$USE_TESTS_LIST" ] \ + && grep -q "^${tests[$i]}$" tbb-tests-ignore.txt + then + unset "tests[$i]" + continue + fi + echo "- ${tests[$i]}" +done + +if [ -n "$WRITE_TESTS_LIST" ] +then + rm -f tbb-tests-list.txt + for i in "${!tests[@]}" + do + echo "${tests[$i]}" >> tbb-tests-list.txt + done + exit 0 +fi + +rm -f tbb-tests.log +echo $'\n''Starting tests' +# We need `security.nocertdb = false` because of #18087. That pref is +# forced to have the same value as `browser.privatebrowsing.autostart` in +# torbutton, so we just set `browser.privatebrowsing.autostart=false` here. +./mach mochitest --log-tbpl tbb-tests.log \ + --setpref network.file.path_blacklist='' \ + --setpref extensions.torbutton.use_nontor_proxy=true \ + --setpref browser.privatebrowsing.autostart=false \ + "${tests[@]}" + +echo "*************************" +echo "*************************" +echo "Summary of failed tests:" +grep --color=never TEST-UNEXPECTED-FAIL tbb-tests.log diff --git a/tbb-tests-ignore.txt b/tbb-tests-ignore.txt new file mode 100644 index 000000000000..ee3927a9e7c4 --- /dev/null +++ b/tbb-tests-ignore.txt @@ -0,0 +1,13 @@ +browser/extensions/onboarding/test/browser/browser_onboarding_accessibility.js +browser/extensions/onboarding/test/browser/browser_onboarding_keyboard.js +browser/extensions/onboarding/test/browser/browser_onboarding_notification.js +browser/extensions/onboarding/test/browser/browser_onboarding_notification_2.js +browser/extensions/onboarding/test/browser/browser_onboarding_notification_3.js +browser/extensions/onboarding/test/browser/browser_onboarding_notification_4.js +browser/extensions/onboarding/test/browser/browser_onboarding_notification_5.js +browser/extensions/onboarding/test/browser/browser_onboarding_notification_click_auto_complete_tour.js +browser/extensions/onboarding/test/browser/browser_onboarding_select_default_tour.js +browser/extensions/onboarding/test/browser/browser_onboarding_skip_tour.js +browser/extensions/onboarding/test/browser/browser_onboarding_tours.js +browser/extensions/onboarding/test/browser/browser_onboarding_tourset.js +browser/extensions/onboarding/test/browser/browser_onboarding_uitour.js diff --git a/tbb-tests/browser.ini b/tbb-tests/browser.ini new file mode 100644 index 000000000000..f481660f1417 --- /dev/null +++ b/tbb-tests/browser.ini @@ -0,0 +1,5 @@ +[DEFAULT] + +[browser_tor_bug2950.js] +[browser_tor_omnibox.js] +[browser_tor_TB4.js] diff --git a/tbb-tests/browser_tor_TB4.js b/tbb-tests/browser_tor_TB4.js new file mode 100644 index 000000000000..8bb12f360e5e --- /dev/null +++ b/tbb-tests/browser_tor_TB4.js @@ -0,0 +1,35 @@ +// # Test for TB4: Tor Browser's Firefox preference overrides +// This is a minimal test to check whether the 000-tor-browser.js +// pref overrides are being used at all or not. More comprehensive +// pref tests are maintained in the tor-browser-bundle-testsuite project. + +function test() { + +let expectedPrefs = [ + // Homepage + ["browser.startup.homepage", "about:tor"], + + // Disable the "Refresh" prompt that is displayed for stale profiles. + ["browser.disableResetPrompt", true], + + // Version placeholder + ["torbrowser.version", "dev-build"], + ]; + +let getPref = function (prefName) { + let type = Services.prefs.getPrefType(prefName); + if (type === Services.prefs.PREF_INT) return Services.prefs.getIntPref(prefName); + if (type === Services.prefs.PREF_BOOL) return Services.prefs.getBoolPref(prefName); + if (type === Services.prefs.PREF_STRING) return Services.prefs.getCharPref(prefName); + // Something went wrong. + throw new Error("Can't access pref " + prefName); +}; + +let testPref = function([key, expectedValue]) { + let foundValue = getPref(key); + is(foundValue, expectedValue, "Pref '" + key + "' should be '" + expectedValue +"'."); +}; + +expectedPrefs.map(testPref); + +} // end function test() diff --git a/tbb-tests/browser_tor_bug2950.js b/tbb-tests/browser_tor_bug2950.js new file mode 100644 index 000000000000..16e41344a3c4 --- /dev/null +++ b/tbb-tests/browser_tor_bug2950.js @@ -0,0 +1,74 @@ +// # Regression tests for tor Bug #2950, Make Permissions Manager memory-only +// Ensures that permissions.sqlite file in profile directory is not written to, +// even when we write a value to Firefox's permissions database. + +// The requisite test() function. +function test() { + +// Needed because of asynchronous part later in the test. +waitForExplicitFinish(); + +// Shortcut +let Ci = Components.interfaces; + +// ## utility functions + +// __principal(spec)__. +// Creates a principal instance from a spec +// (string address such as "https://www.torproject.org"). +let principal = spec => Services.scriptSecurityManager.createContentPrincipalFromOrigin(spec); + +// __setPermission(spec, key, value)__. +// Sets the site permission of type key to value, for the site located at address spec. +let setPermission = (spec, key, value) => SitePermissions.setForPrincipal(principal(spec), key, value); + +// __getPermission(spec, key)__. +// Reads the site permission value for permission type key, for the site +// located at address spec. +let getPermission = (spec, key) => SitePermissions.getForPrincipal(principal(spec), key); + +// __profileDirPath__. +// The Firefox Profile directory. Expected location of various persistent files. +let profileDirPath = Services.dirsvc.get("ProfD", Components.interfaces.nsIFile).path; + +// __fileInProfile(fileName)__. +// Returns an nsIFile instance corresponding to a file in the Profile directory. +let fileInProfile = fileName => FileUtils.File(profileDirPath + "/" + fileName); + +// ## Now let's run the test. + +let SITE = "https://www.torproject.org", + KEY = "popup"; + +let permissionsFile = fileInProfile("permissions.sqlite"), + lastModifiedTime = null, + newModifiedTime = null; +if (permissionsFile.exists()) { + lastModifiedTime = permissionsFile.lastModifiedTime; +} +// Read the original value of the permission. +let originalValue = getPermission(SITE, KEY); + +// We need to delay by at least 1000 ms, because that's the granularity +// of file time stamps, it seems. +window.setTimeout( + function () { + // Set the permission to a new value. + setPermission(SITE, KEY, SitePermissions.BLOCK); + // Now read back the permission value again. + let newReadValue = getPermission(SITE, KEY); + // Compare to confirm that the permission + // value was successfully changed. + Assert.notDeepEqual(originalValue, newReadValue, "Set a value in permissions db (perhaps in memory)."); + // If file existed or now exists, get the current time stamp. + if (permissionsFile.exists()) { + newModifiedTime = permissionsFile.lastModifiedTime; + } + // If file was created or modified since we began this test, + // then permissions db is not memory only. Complain! + is(lastModifiedTime, newModifiedTime, "Don't write to permissions.sqlite file on disk."); + // We are done with the test. + finish(); + }, 1100); + +} // test() diff --git a/tbb-tests/mochitest.ini b/tbb-tests/mochitest.ini new file mode 100644 index 000000000000..cc5172733bbe --- /dev/null +++ b/tbb-tests/mochitest.ini @@ -0,0 +1,3 @@ +[DEFAULT] + +[test_tor_bug2874.html] diff --git a/tbb-tests/moz.build b/tbb-tests/moz.build new file mode 100644 index 000000000000..de8a41a67a5c --- /dev/null +++ b/tbb-tests/moz.build @@ -0,0 +1,10 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +MOCHITEST_MANIFESTS += ['mochitest.ini'] + +BROWSER_CHROME_MANIFESTS += [ 'browser.ini' ] + diff --git a/tbb-tests/test_tor_bug2874.html b/tbb-tests/test_tor_bug2874.html new file mode 100644 index 000000000000..c0a956e9f687 --- /dev/null +++ b/tbb-tests/test_tor_bug2874.html @@ -0,0 +1,25 @@ +<!DOCTYPE HTML> +<html> +<!-- +Tor bug +https://trac.torproject.org/projects/tor/ticket/2874 +--> +<head> + <meta charset="utf-8"> + <title>Test for Tor Bug 2874</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + is(typeof Components, 'undefined', "The global window object should not expose a Components property to untrusted content."); + </script> +</head> +<body> +<a target="_blank" href="https://trac.torproject.org/projects/tor/ticket/2874">Tor Bug 2874</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/toolkit/toolkit.mozbuild b/toolkit/toolkit.mozbuild index d092b8b22346..6e35a4602300 100644 --- a/toolkit/toolkit.mozbuild +++ b/toolkit/toolkit.mozbuild @@ -96,7 +96,8 @@ if CONFIG['MOZ_WEBRTC'] and CONFIG['COMPILE_ENVIRONMENT']: ] if CONFIG['ENABLE_TESTS']: - DIRS += ['/testing/specialpowers'] + DIRS += ['/testing/specialpowers', + '/tbb-tests'] DIRS += [ '/testing/gtest',
1 0
0 0
[tor-browser/tor-browser-78.14.0esr-10.5-1] Bug 3547: Block all plugins.
by sysrqb@torproject.org 04 Sep '21

04 Sep '21
commit e2f4640d7ae53932c3dfa65f3f21ac981c17fc24 Author: Mike Perry <mikeperry-git(a)torproject.org> Date: Tue Dec 4 16:03:13 2012 -0800 Bug 3547: Block all plugins. We cannot use the @mozilla.org/extensions/blocklist;1 service, because we actually want to stop plugins from ever entering the browser's process space and/or executing code (for example, AV plugins that collect statistics/analyse urls, magical toolbars that phone home or "help" the user, skype buttons that ruin our day, and censorship filters). Hence we rolled our own. See https://trac.torproject.org/projects/tor/ticket/3547#comment:6 for musings on a better way. Until then, it is delta-darwinism for us. --- dom/plugins/base/PluginFinder.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dom/plugins/base/PluginFinder.cpp b/dom/plugins/base/PluginFinder.cpp index 4e1c1fd53698..cace7d4ef6ba 100644 --- a/dom/plugins/base/PluginFinder.cpp +++ b/dom/plugins/base/PluginFinder.cpp @@ -480,6 +480,9 @@ nsresult PluginFinder::ScanPluginsDirectory(nsIFile* pluginsDir, *aPluginsChanged = false; + // Block all plugins + return NS_OK; + #ifdef PLUGIN_LOGGING nsAutoCString dirPath; pluginsDir->GetNativePath(dirPath);
1 0
0 0
[tor-browser/tor-browser-78.14.0esr-10.5-1] Bug 10760: Integrate TorButton to TorBrowser core
by sysrqb@torproject.org 04 Sep '21

04 Sep '21
commit b60399b09b25ff7c778875b104b9f3c4e8ce0219 Author: Alex Catarineu <acat(a)torproject.org> Date: Wed Feb 19 23:05:08 2020 +0100 Bug 10760: Integrate TorButton to TorBrowser core Because of the non-restartless nature of Torbutton, it required a two-stage installation process. On mobile, it was a problem, because it was not loading when the user opened the browser for the first time. Moving it to tor-browser and making it a system extension allows it to load when the user opens the browser for first time. Additionally, this patch also fixes Bug 27611. Bug 26321: New Circuit and New Identity menu items Bug 14392: Make about:tor behave like other initial pages. Bug 25013: Add torbutton as a tor-browser submodule --- .gitmodules | 3 ++ browser/base/content/aboutDialog.xhtml | 38 +++++++++++------ browser/base/content/browser-doctype.inc | 6 +++ browser/base/content/browser-menubar.inc | 49 ++++++++++++++++------ browser/base/content/browser-sets.inc | 2 + browser/base/content/browser.js | 1 + browser/base/content/browser.xhtml | 9 ++++ .../controlcenter/content/identityPanel.inc.xhtml | 17 ++++++++ .../customizableui/content/panelUI.inc.xhtml | 17 +++++++- browser/installer/package-manifest.in | 2 + docshell/base/nsAboutRedirector.cpp | 6 ++- docshell/build/components.conf | 1 + mobile/android/installer/package-manifest.in | 4 ++ toolkit/moz.build | 1 + .../mozapps/extensions/internal/XPIProvider.jsm | 9 ++++ toolkit/torproject/torbutton | 1 + .../lib/environments/browser-window.js | 6 ++- 17 files changed, 142 insertions(+), 30 deletions(-) diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000000..2f03bd8e22df --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "toolkit/torproject/torbutton"] + path = toolkit/torproject/torbutton + url = https://git.torproject.org/torbutton.git diff --git a/browser/base/content/aboutDialog.xhtml b/browser/base/content/aboutDialog.xhtml index 69cbf846bbef..5274cbc02831 100644 --- a/browser/base/content/aboutDialog.xhtml +++ b/browser/base/content/aboutDialog.xhtml @@ -7,11 +7,11 @@ <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/content/aboutDialog.css" type="text/css"?> <?xml-stylesheet href="chrome://branding/content/aboutDialog.css" type="text/css"?> +<?xml-stylesheet href="chrome://torbutton/skin/aboutDialog.css" type="text/css"?> +<!-- We need to include the localization DTDs until we migrate to Fluent --> <!DOCTYPE window [ -#ifdef XP_MACOSX #include browser-doctype.inc -#endif ]> <window xmlns:html="http://www.w3.org/1999/xhtml" @@ -28,7 +28,7 @@ data-l10n-id="aboutDialog-title" #endif role="dialog" - aria-describedby="version distribution distributionId communityDesc contributeDesc trademark" + aria-describedby="version distribution distributionId projectDesc helpDesc trademark trademarkTor" > #ifdef XP_MACOSX #include macWindow.inc.xhtml @@ -132,24 +132,36 @@ <label is="text-link" useoriginprincipal="true" href="about:credits" data-l10n-name="community-exp-creditsLink"></label> </description> </vbox> - <description class="text-blurb" id="communityDesc" data-l10n-id="community-2"> - <label is="text-link" href="http://www.mozilla.org/" data-l10n-name="community-mozillaLink"></label> - <label is="text-link" useoriginprincipal="true" href="about:credits" data-l10n-name="community-creditsLink"></label> + <!-- Keep communityDesc and contributeDesc to avoid JS errors trying to hide them --> + <description class="text-blurb" id="communityDesc" data-l10n-id="community-2" hidden="true"></description> + <description class="text-blurb" id="contributeDesc" data-l10n-id="helpus" hidden="true"></description> + <description class="text-blurb" id="projectDesc"> + &project.start; + <label is="text-link" href="https://www.torproject.org/"> + &project.tpoLink; + </label>&project.end; </description> - <description class="text-blurb" id="contributeDesc" data-l10n-id="helpus"> - <label is="text-link" href="https://donate.mozilla.org/?utm_source=firefox&#38;utm_medium=referral&#38;…" data-l10n-name="helpus-donateLink"></label> - <label is="text-link" href="http://www.mozilla.org/contribute/" data-l10n-name="helpus-getInvolvedLink"></label> + <description class="text-blurb" id="helpDesc"> + &help.start; + <label is="text-link" href="https://donate.torproject.org/"> + &help.donateLink; + </label> + &help.or; + <label is="text-link" href="https://community.torproject.org/"> + &help.getInvolvedLink; + </label>&help.end; </description> </vbox> </vbox> </hbox> <vbox id="bottomBox"> - <hbox pack="center"> - <label is="text-link" class="bottom-link" useoriginprincipal="true" href="about:license" data-l10n-id="bottomLinks-license"></label> - <label is="text-link" class="bottom-link" useoriginprincipal="true" href="about:rights" data-l10n-id="bottomLinks-rights"></label> - <label is="text-link" class="bottom-link" href="https://www.mozilla.org/privacy/" data-l10n-id="bottomLinks-privacy"></label> + <hbox id="newBottom" pack="center" position="1"> + <label is="text-link" class="bottom-link" href="https://support.torproject.org/">&bottomLinks.questions;</label> + <label is="text-link" class="bottom-link" href="https://community.torproject.org/relay/">&bottomLinks.grow;</label> + <label is="text-link" class="bottom-link" useoriginprincipal="true" href="about:license">&bottomLinks.license;</label> </hbox> <description id="trademark" data-l10n-id="trademarkInfo"></description> + <description id="trademarkTor">&tor.TrademarkStatement;</description> </vbox> </vbox> diff --git a/browser/base/content/browser-doctype.inc b/browser/base/content/browser-doctype.inc index 9aa278773158..48cf6cd3eda0 100644 --- a/browser/base/content/browser-doctype.inc +++ b/browser/base/content/browser-doctype.inc @@ -14,3 +14,9 @@ %syncBrandDTD; <!ENTITY % brandingsDTD SYSTEM "chrome://browser/locale/brandings.dtd"> %brandingsDTD; +<!ENTITY % torbuttonDTD SYSTEM "chrome://torbutton/locale/torbutton.dtd"> +%torbuttonDTD; +<!ENTITY % aboutTorDTD SYSTEM "chrome://torbutton/locale/aboutTor.dtd"> +%aboutTorDTD; +<!ENTITY % aboutDialogDTD SYSTEM "chrome://torbutton/locale/aboutDialog.dtd"> +%aboutDialogDTD; diff --git a/browser/base/content/browser-menubar.inc b/browser/base/content/browser-menubar.inc index 267ec91707ba..6f4aa9289c35 100644 --- a/browser/base/content/browser-menubar.inc +++ b/browser/base/content/browser-menubar.inc @@ -33,6 +33,18 @@ command="Tools:NonFissionWindow" accesskey="s" label="New Non-Fission Window"/> #endif + <menuseparator/> + <menuitem id="menu_newIdentity" + accesskey="&torbutton.context_menu.new_identity_key;" + key="torbutton-new-identity-key" + label="&torbutton.context_menu.new_identity;" + oncommand="torbutton_new_identity();"/> + <menuitem id="menu_newCircuit" + accesskey="&torbutton.context_menu.new_circuit_key;" + key="torbutton-new-circuit-key" + label="&torbutton.context_menu.new_circuit;" + oncommand="torbutton_new_circuit();"/> + <menuseparator/> <menuitem id="menu_openLocation" hidden="true" command="Browser:OpenLocation" @@ -455,17 +467,28 @@ #endif data-l10n-id="menu-help"> <menupopup id="menu_HelpPopup" onpopupshowing="buildHelpMenu();"> - <menuitem id="menu_openHelp" + <!-- dummy elements to avoid 'getElementById' errors --> + <box id="feedbackPage"/> + <box id="helpSafeMode"/> + <box id="menu_HelpPopup_reportPhishingtoolmenu"/> + <box id="menu_HelpPopup_reportPhishingErrortoolmenu"/> + <!-- Add Tor Browser manual link --> + <menuitem id="torBrowserUserManual" + oncommand="gBrowser.selectedTab = gBrowser.addTab('https://tb-manual.torproject.org/' + Services.locale.requestedLocale, {triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()});" + label="&aboutTor.torbrowser_user_manual.label;" + accesskey="&aboutTor.torbrowser_user_manual.accesskey;"/> + <!-- Bug 18905: Hide unused help menu items --> + <!-- <menuitem id="menu_openHelp" oncommand="openHelpLink('firefox-help')" onclick="checkForMiddleClick(this, event);" data-l10n-id="menu-help-product" #ifdef XP_MACOSX - key="key_openHelpMac"/> + key="key_openHelpMac"/> --> #else - /> + /> --> #endif - <menuitem id="menu_openTour" - oncommand="openTourPage();" data-l10n-id="menu-help-show-tour"/> + <!-- <menuitem id="menu_openTour" + oncommand="openTourPage();" data-l10n-id="menu-help-show-tour"/> --> <menuitem id="help_importFromAnotherBrowser" command="cmd_help_importFromAnotherBrowser" data-l10n-id="menu-help-import-from-another-browser"/> <menuitem id="menu_keyboardShortcuts" @@ -474,22 +497,22 @@ <menuitem id="troubleShooting" oncommand="openTroubleshootingPage()" onclick="checkForMiddleClick(this, event);" data-l10n-id="menu-help-troubleshooting-info"/> - <menuitem id="feedbackPage" + <!-- <menuitem id="feedbackPage" oncommand="openFeedbackPage()" - onclick="checkForMiddleClick(this, event);" data-l10n-id="menu-help-feedback-page"/> - <menuitem id="helpSafeMode" - oncommand="safeModeRestart();" data-l10n-id="menu-help-safe-mode-without-addons"/> - <menuitem id="menu_HelpPopup_reportPhishingtoolmenu" + onclick="checkForMiddleClick(this, event);" data-l10n-id="menu-help-feedback-page"/> --> + <!-- <menuitem id="helpSafeMode" + oncommand="safeModeRestart();" data-l10n-id="menu-help-safe-mode-without-addons"/> --> + <!-- <menuitem id="menu_HelpPopup_reportPhishingtoolmenu" disabled="true" oncommand="openUILink(gSafeBrowsing.getReportURL('Phish'), event, {triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({})});" onclick="checkForMiddleClick(this, event);" - hidden="true" data-l10n-id="menu-help-report-deceptive-site"/> - <menuitem id="menu_HelpPopup_reportPhishingErrortoolmenu" + hidden="true" data-l10n-id="menu-help-report-deceptive-site"/> --> + <!-- <menuitem id="menu_HelpPopup_reportPhishingErrortoolmenu" disabled="true" oncommand="ReportFalseDeceptiveSite();" onclick="checkForMiddleClick(this, event);" data-l10n-id="menu-help-not-deceptive" - hidden="true"/> + hidden="true"/> --> <menuseparator id="helpPolicySeparator" hidden="true"/> <menuitem id="helpPolicySupport" diff --git a/browser/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc index aae94e8d4654..fa71bfb37a84 100644 --- a/browser/base/content/browser-sets.inc +++ b/browser/base/content/browser-sets.inc @@ -374,4 +374,6 @@ data-l10n-id="hide-other-apps-shortcut" modifiers="accel,alt"/> #endif + <key id="torbutton-new-identity-key" modifiers="accel shift" key="U" oncommand="torbutton_new_identity()"/> + <key id="torbutton-new-circuit-key" modifiers="accel shift" key="L" oncommand="torbutton_new_circuit()"/> </keyset> diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 5eb38ba78282..3c342dedd5d4 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -620,6 +620,7 @@ var gPageIcons = { }; var gInitialPages = [ + "about:tor", "about:blank", "about:newtab", "about:home", diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml index 62825bfd206a..229fc2a26dd2 100644 --- a/browser/base/content/browser.xhtml +++ b/browser/base/content/browser.xhtml @@ -29,6 +29,8 @@ <?xml-stylesheet href="chrome://browser/skin/searchbar.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/skin/places/tree-icons.css" type="text/css"?> <?xml-stylesheet href="chrome://browser/skin/places/editBookmark.css" type="text/css"?> +<?xml-stylesheet href="chrome://torbutton/skin/tor-circuit-display.css" type="text/css"?> +<?xml-stylesheet href="chrome://torbutton/skin/torbutton.css" type="text/css"?> # All DTD information is stored in a separate file so that it can be shared by # hiddenWindowMac.xhtml. @@ -105,11 +107,18 @@ Services.scriptloader.loadSubScript("chrome://browser/content/places/places-menupopup.js", this); Services.scriptloader.loadSubScript("chrome://browser/content/search/autocomplete-popup.js", this); Services.scriptloader.loadSubScript("chrome://browser/content/search/searchbar.js", this); + Services.scriptloader.loadSubScript("chrome://torbutton/content/tor-circuit-display.js", this); + Services.scriptloader.loadSubScript("chrome://torbutton/content/torbutton.js", this); window.onload = gBrowserInit.onLoad.bind(gBrowserInit); window.onunload = gBrowserInit.onUnload.bind(gBrowserInit); window.onclose = WindowIsClosing; + //onLoad Handler + try { + window.addEventListener("load", torbutton_init, false); + } catch (e) {} + window.addEventListener("MozBeforeInitialXULLayout", gBrowserInit.onBeforeInitialXULLayout.bind(gBrowserInit), { once: true }); diff --git a/browser/components/controlcenter/content/identityPanel.inc.xhtml b/browser/components/controlcenter/content/identityPanel.inc.xhtml index 77c0b9b2413f..a8edda858e41 100644 --- a/browser/components/controlcenter/content/identityPanel.inc.xhtml +++ b/browser/components/controlcenter/content/identityPanel.inc.xhtml @@ -60,6 +60,23 @@ oncommand="gIdentityHandler.showSecuritySubView();"/> </hbox> + <!-- Circuit display section --> + <hbox id="circuit-display-container" class="identity-popup-section"> + <vbox id="circuit-display-content" flex="1" role="group" + aria-labelledby="circuit-display-headline"> + <hbox id="circuit-display-header" align="center"> + <label id="circuit-display-headline" + role="heading" aria-level="2">&torbutton.circuit_display.title;</label> + </hbox> + <html:ul id="circuit-display-nodes" dir="auto"/> + </vbox> + <vbox id="circuit-reload-content" flex="1"> + <html:button id="circuit-reload-button" + onclick="torbutton_new_circuit()">&torbutton.circuit_display.new_circuit;</html:button> + <hbox id="circuit-guard-note-container"/> + </vbox> + </hbox> + <!-- Permissions Section --> <hbox class="identity-popup-section" when-connection="not-secure secure secure-ev secure-cert-user-overridden file extension cert-error-page"> diff --git a/browser/components/customizableui/content/panelUI.inc.xhtml b/browser/components/customizableui/content/panelUI.inc.xhtml index 3a8b74b0a9f3..bdb8a7c227cf 100644 --- a/browser/components/customizableui/content/panelUI.inc.xhtml +++ b/browser/components/customizableui/content/panelUI.inc.xhtml @@ -265,7 +265,8 @@ class="subviewbutton subviewbutton-iconic" label="&newPrivateWindow.label;" key="key_privatebrowsing" - command="Tools:PrivateBrowsing"/> + command="Tools:PrivateBrowsing" + hidden="true"/> #ifdef NIGHTLY_BUILD <toolbarbutton id="appMenu-fission-window-button" class="subviewbutton subviewbutton-iconic" @@ -281,7 +282,19 @@ <toolbarbutton id="appMenuRestoreLastSession" label="&appMenuHistory.restoreSession.label;" class="subviewbutton subviewbutton-iconic" - command="Browser:RestoreLastSession"/> + command="Browser:RestoreLastSession" + hidden="true"/> + <toolbarseparator/> + <toolbarbutton id="appMenuNewIdentity" + class="subviewbutton subviewbutton-iconic" + key="torbutton-new-identity-key" + label="&torbutton.context_menu.new_identity;" + oncommand="torbutton_new_identity();"/> + <toolbarbutton id="appMenuNewCircuit" + class="subviewbutton subviewbutton-iconic" + key="torbutton-new-circuit-key" + label="&torbutton.context_menu.new_circuit;" + oncommand="torbutton_new_circuit();"/> <toolbarseparator/> <toolbaritem id="appMenu-zoom-controls" class="toolbaritem-combined-buttons" closemenu="none"> <!-- Use a spacer, because panel sizing code gets confused when using CSS methods. --> diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 582a6e13d607..3722bf2ee22b 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -253,6 +253,8 @@ @RESPATH@/browser/chrome/torlauncher/* @RESPATH@/browser/@PREF_DIR@/torlauncher-prefs.js #endif +@RESPATH@/chrome/torbutton.manifest +@RESPATH@/chrome/torbutton/* @RESPATH@/chrome/toolkit@JAREXT@ @RESPATH@/chrome/toolkit.manifest @RESPATH@/chrome/recording.manifest diff --git a/docshell/base/nsAboutRedirector.cpp b/docshell/base/nsAboutRedirector.cpp index 730fd6aea654..051f239c76ac 100644 --- a/docshell/base/nsAboutRedirector.cpp +++ b/docshell/base/nsAboutRedirector.cpp @@ -146,7 +146,11 @@ static const RedirEntry kRedirMap[] = { {"crashcontent", "about:blank", nsIAboutModule::HIDE_FROM_ABOUTABOUT | nsIAboutModule::URI_CAN_LOAD_IN_CHILD | - nsIAboutModule::URI_MUST_LOAD_IN_CHILD}}; + nsIAboutModule::URI_MUST_LOAD_IN_CHILD}, + {"tor", "chrome://torbutton/content/aboutTor/aboutTor.xhtml", + nsIAboutModule::URI_MUST_LOAD_IN_CHILD | + nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | + nsIAboutModule::ALLOW_SCRIPT}}; static const int kRedirTotal = mozilla::ArrayLength(kRedirMap); NS_IMETHODIMP diff --git a/docshell/build/components.conf b/docshell/build/components.conf index 6d7253d01631..2d56ea33389d 100644 --- a/docshell/build/components.conf +++ b/docshell/build/components.conf @@ -27,6 +27,7 @@ about_pages = [ 'srcdoc', 'support', 'telemetry', + 'tor', 'url-classifier', 'webrtc', ] diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index 17d6471c4742..055eb4717447 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -137,6 +137,10 @@ @BINPATH@/chrome/devtools@JAREXT@ @BINPATH@/chrome/devtools.manifest +; Torbutton +@BINPATH@/chrome/torbutton@JAREXT@ +@BINPATH@/chrome/torbutton.manifest + ; [Default Preferences] ; All the pref files must be part of base to prevent migration bugs #ifdef MOZ_GECKOVIEW_JAR diff --git a/toolkit/moz.build b/toolkit/moz.build index b6f792da7124..3451334de15c 100644 --- a/toolkit/moz.build +++ b/toolkit/moz.build @@ -23,6 +23,7 @@ DIRS += [ 'pluginproblem', 'profile', 'themes', + 'torproject/torbutton', ] if CONFIG['OS_ARCH'] == 'WINNT' and CONFIG['MOZ_DEFAULT_BROWSER_AGENT']: diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index bcdf6f40d5ed..bf31932b59f1 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -1462,6 +1462,15 @@ var XPIStates = { for (let [id, file] of loc.readAddons()) { knownIds.delete(id); + // Uninstall torbutton if it is installed in the user profile + if (id === "torbutton(a)torproject.org" && + loc.name === KEY_APP_PROFILE) { + logger.debug("Uninstalling torbutton from user profile."); + loc.installer.uninstallAddon(id); + changed = true; + continue; + } + // Since it is now part of the browser, uninstall the Tor Launcher // extension. This will remove the Tor Launcher .xpi from user // profiles on macOS. diff --git a/toolkit/torproject/torbutton b/toolkit/torproject/torbutton new file mode 160000 index 000000000000..32c71313e4e1 --- /dev/null +++ b/toolkit/torproject/torbutton @@ -0,0 +1 @@ +Subproject commit 32c71313e4e1da24510402b9051543e144a3129b diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js index 76e03f2d49bb..2ff107b553b2 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js @@ -75,7 +75,11 @@ function getGlobalScriptIncludes(scriptPath) { "browser/components/search/content/" ) .replace("chrome://browser/content/", "browser/base/content/") - .replace("chrome://global/content/", "toolkit/content/"); + .replace("chrome://global/content/", "toolkit/content/") + .replace( + "chrome://torbutton/content/", + "toolkit/torproject/torbutton/chrome/content/" + ); for (let mapping of Object.getOwnPropertyNames(MAPPINGS)) { if (sourceFile.includes(mapping)) {
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.