tbb-commits
Threads by month
- ----- 2026 -----
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- 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
- 1 participants
- 20449 discussions
[tor-browser/tor-browser-78.10.0esr-10.5-1] Merge remote-tracking branch 'richardgl/27476_rev2' into tor-browser-78.10.0esr-10.5-1
by sysrqb@torproject.org 17 May '21
by sysrqb@torproject.org 17 May '21
17 May '21
commit 41c6d99e17639bab7cfc4b5e1e6f971508406acc
Merge: 627d83ded2fb 6d8d49baa9ae
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Mon May 17 19:34:32 2021 +0000
Merge remote-tracking branch 'richardgl/27476_rev2' into tor-browser-78.10.0esr-10.5-1
browser/actors/NetErrorParent.jsm | 8 +
browser/base/content/aboutNetError.js | 8 +-
browser/base/content/browser-siteIdentity.js | 2 +-
browser/base/content/browser.js | 10 +
browser/base/content/browser.xhtml | 2 +
browser/components/BrowserGlue.jsm | 14 +
browser/components/about/AboutRedirector.cpp | 4 +
browser/components/about/components.conf | 1 +
browser/components/moz.build | 1 +
browser/components/torconnect/TorConnectChild.jsm | 9 +
browser/components/torconnect/TorConnectParent.jsm | 117 ++++++++
.../torconnect/content/aboutTorConnect.css | 96 +++++++
.../torconnect/content/aboutTorConnect.js | 299 +++++++++++++++++++++
.../torconnect/content/aboutTorConnect.xhtml | 46 ++++
.../components/torconnect/content/onion-slash.svg | 7 +
browser/components/torconnect/content/onion.svg | 3 +
.../torconnect/content/torBootstrapUrlbar.js | 136 ++++++++++
.../torconnect/content/torconnect-urlbar.css | 55 ++++
.../torconnect/content/torconnect-urlbar.inc.xhtml | 11 +
browser/components/torconnect/jar.mn | 7 +
browser/components/torconnect/moz.build | 6 +
.../components/torpreferences/content/torPane.js | 46 ++++
.../torpreferences/content/torPane.xhtml | 23 ++
.../torpreferences/content/torPreferences.css | 121 +++++++++
browser/modules/TorProcessService.jsm | 12 +
browser/modules/TorProtocolService.jsm | 124 ++++++++-
browser/modules/TorStrings.jsm | 72 +++++
browser/modules/moz.build | 1 +
browser/themes/shared/jar.inc.mn | 1 +
browser/themes/shared/onionPattern.css | 121 +++++++++
browser/themes/shared/onionPattern.inc.xhtml | 207 ++++++++++++++
browser/themes/shared/urlbar-searchbar.inc.css | 2 +
dom/base/Document.cpp | 51 +++-
toolkit/modules/RemotePageAccessManager.jsm | 20 ++
.../themes/shared/in-content/info-pages.inc.css | 15 +-
.../lib/environments/browser-window.js | 4 +
36 files changed, 1650 insertions(+), 12 deletions(-)
1
0
[tor-browser/tor-browser-78.10.0esr-10.5-1] Bug 27476: Implement about:torconnect captive portal within Tor Browser
by sysrqb@torproject.org 17 May '21
by sysrqb@torproject.org 17 May '21
17 May '21
commit 6d8d49baa9aebb4f5872040f8646adc4429dec30
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 | 8 +-
browser/base/content/browser-siteIdentity.js | 2 +-
browser/base/content/browser.js | 10 +
browser/base/content/browser.xhtml | 2 +
browser/components/BrowserGlue.jsm | 14 +
browser/components/about/AboutRedirector.cpp | 4 +
browser/components/about/components.conf | 1 +
browser/components/moz.build | 1 +
browser/components/torconnect/TorConnectChild.jsm | 9 +
browser/components/torconnect/TorConnectParent.jsm | 117 ++++++++
.../torconnect/content/aboutTorConnect.css | 96 +++++++
.../torconnect/content/aboutTorConnect.js | 299 +++++++++++++++++++++
.../torconnect/content/aboutTorConnect.xhtml | 46 ++++
.../components/torconnect/content/onion-slash.svg | 7 +
browser/components/torconnect/content/onion.svg | 3 +
.../torconnect/content/torBootstrapUrlbar.js | 136 ++++++++++
.../torconnect/content/torconnect-urlbar.css | 55 ++++
.../torconnect/content/torconnect-urlbar.inc.xhtml | 11 +
browser/components/torconnect/jar.mn | 7 +
browser/components/torconnect/moz.build | 6 +
.../components/torpreferences/content/torPane.js | 46 ++++
.../torpreferences/content/torPane.xhtml | 23 ++
.../torpreferences/content/torPreferences.css | 121 +++++++++
browser/modules/TorProcessService.jsm | 12 +
browser/modules/TorProtocolService.jsm | 124 ++++++++-
browser/modules/TorStrings.jsm | 72 +++++
browser/modules/moz.build | 1 +
browser/themes/shared/jar.inc.mn | 1 +
browser/themes/shared/onionPattern.css | 121 +++++++++
browser/themes/shared/onionPattern.inc.xhtml | 207 ++++++++++++++
browser/themes/shared/urlbar-searchbar.inc.css | 2 +
dom/base/Document.cpp | 51 +++-
toolkit/modules/RemotePageAccessManager.jsm | 20 ++
.../themes/shared/in-content/info-pages.inc.css | 15 +-
.../lib/environments/browser-window.js | 4 +
36 files changed, 1650 insertions(+), 12 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..238b4930461c 100644
--- a/browser/base/content/aboutNetError.js
+++ b/browser/base/content/aboutNetError.js
@@ -194,8 +194,14 @@ async function setErrorPageStrings(err) {
document.l10n.setAttributes(titleElement, title);
}
-function initPage() {
+async function initPage() {
var err = getErrorCode();
+ 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..2bd28ec1b04c 100644
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -503,6 +503,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",
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/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..03b258608b5c
--- /dev/null
+++ b/browser/components/torconnect/TorConnectParent.jsm
@@ -0,0 +1,117 @@
+// 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 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,
+];
+
+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);
+ }
+ }
+
+ willDestroy() {
+ for (const topic of gActiveTopics) {
+ Services.obs.removeObserver(this.gObserver, topic);
+ }
+ }
+
+ get browser() {
+ return this.browsingContext.top.embedderElement;
+ }
+
+ _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
+ );
+ }
+
+ _GoToBrowserHome() {
+ const window = this.browser.ownerGlobal;
+ window.BrowserHome();
+ }
+
+ receiveMessage(message) {
+ switch (message.name) {
+ case "TorBootstrapErrorOccurred":
+ return TorProtocolService.torBootstrapErrorOccurred();
+ case "TorRetrieveBootstrapStatus":
+ return TorProtocolService.retrieveBootstrapStatus();
+ case "OpenTorAdvancedPreferences":
+ return this._OpenTorAdvancedPreferences();
+ case "GoToBrowserHome":
+ return this._GoToBrowserHome();
+ 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..eb4277f2ce5e
--- /dev/null
+++ b/browser/components/torconnect/content/aboutTorConnect.css
@@ -0,0 +1,96 @@
+
+/* 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;
+}
+
+#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%;
+}
+
+#copyLogButton {
+ position: relative;
+}
+
+#copyLogTooltip {
+ visibility: hidden;
+ display: inline-block;
+ width: 100%;
+
+ position: absolute;
+ z-index: 1;
+ left: 0px;
+ bottom: calc(100% + 6px);
+}
+
+#copyLogTooltip::after {
+ content: "";
+ position: absolute;
+ top: 100%;
+ left: 50%;
+ margin-left: -4px;
+ border-width: 4px;
+ border-style: solid;
+ border-color: #30E60B transparent transparent transparent;
+}
+
+
+#copyLogTooltipText {
+ display: inline-block;
+ background-color: #30E60B;
+ color: #003706;
+ border-radius: 2px;
+ text-align: center;
+ line-height: 13px;
+ font: 11px Regular;
+ font-weight: 400;
+
+ margin-left: auto;
+ margin-right: auto;
+ padding: 4px;
+}
+
+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..ad398ccd86f9
--- /dev/null
+++ b/browser/components/torconnect/content/aboutTorConnect.js
@@ -0,0 +1,299 @@
+// 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";
+
+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 elemConnectButton() {
+ return this.getElem("connectButton");
+ }
+ get elemCopyLogButton() {
+ return this.getElem("copyLogButton");
+ }
+ get elemCopyLogTooltip() {
+ return this.getElem("copyLogTooltip");
+ }
+ get elemCopyLogTooltipText() {
+ return this.getElem("copyLogTooltipText");
+ }
+ get elemAdvancedButton() {
+ return this.getElem("advancedButton");
+ }
+ 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.showElem(this.elemAdvancedButton);
+ this.hideElem(this.elemCopyLogButton);
+ 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.elemCopyLogButton);
+ this.showElem(this.elemCancelButton);
+ 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.showElem(this.elemProgressContent);
+ this.hideElem(this.elemProgressMeter);
+ this.elemTitle.classList.add("error");
+
+ this.elem
+ }
+
+ goToBrowserHome() {
+ this.hideElem(this.elemCancelButton);
+ RPMSendAsyncMessage("GoToBrowserHome");
+ }
+
+ 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:
+ this.goToBrowserHome();
+ break;
+ }
+ }
+
+ async showErrorMessage(aErrorObj) {
+ if (aErrorObj && aErrorObj.message) {
+ this.setTitle(aErrorObj.message);
+ if (aErrorObj.details) {
+ this.elemProgressDesc.textContent = aErrorObj.details;
+ }
+ }
+
+ let haveErrorOrWarning =
+ (await RPMSendQuery("TorBootstrapErrorOccurred")) ||
+ (await RPMSendQuery("TorLogHasWarnOrErr"));
+ this.showCopyLogButton(haveErrorOrWarning);
+ this.showElem(this.elemConnectButton);
+ }
+
+ showElem(elem) {
+ elem.removeAttribute("hidden");
+ }
+
+ hideElem(elem) {
+ elem.setAttribute("hidden", "true");
+ }
+
+ async connect() {
+ 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);
+ }
+ }
+ }
+
+ restoreCopyLogVisibility() {
+ this.elemCopyLogButton.setAttribute("hidden", true);
+ }
+
+ showCopyLogButton() {
+ this.elemCopyLogButton.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 >= 100) {
+ this.state = AboutTorConnect.STATE_BOOTSTRAPPED;
+ } 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;
+ }
+
+ initButtons() {
+ this.elemAdvancedButton.textContent = this.torStrings.torConnect.torConfigure;
+ this.elemAdvancedButton.addEventListener("click", () => {
+ RPMSendAsyncMessage("OpenTorAdvancedPreferences");
+ });
+
+ this.elemConnectButton.textContent =
+ this.torStrings.torConnect.torConnectButton;
+ this.elemConnectButton.addEventListener("click", () => {
+ this.connect();
+ });
+
+ this.elemCancelButton.textContent = this.torStrings.torConnect.cancel;
+ this.elemCancelButton.addEventListener("click", () => {
+ this.stopTorBootstrap();
+ });
+
+ // sets the text content while keping the child elements intact
+ this.elemCopyLogButton.childNodes[0].nodeValue =
+ this.torStrings.torConnect.copyLog;
+ this.elemCopyLogButton.addEventListener("click", async () => {
+ 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);
+ });
+ }
+
+ initObservers() {
+ RPMAddMessageListener(kTorBootstrapErrorTopic, ({ data }) => {
+ this.showCopyLogButton(true);
+ this.stopTorBootstrap();
+ this.showErrorMessage(data);
+ });
+ RPMAddMessageListener(kTorLogHasWarnOrErrTopic, () => {
+ this.showCopyLogButton(true);
+ });
+ RPMAddMessageListener(kTorProcessDidNotStartTopic, ({ data }) => {
+ this.showErrorMessage(data);
+ });
+ RPMAddMessageListener(kTorBootstrapStatusTopic, ({ data }) => {
+ this.updateBootstrapProgress(data);
+ });
+ }
+
+ async init() {
+ this.torStrings = await RPMSendQuery("GetTorStrings");
+ document.documentElement.setAttribute(
+ "dir",
+ await RPMSendQuery("GetDirection")
+ );
+ this.initButtons();
+ this.initObservers();
+ 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");
+ }
+}
+
+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..e0f813f62d67
--- /dev/null
+++ b/browser/components/torconnect/content/aboutTorConnect.xhtml
@@ -0,0 +1,46 @@
+<!-- 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="connectButtonContainer" class="button-container">
+ <button id="advancedButton" hidden="true"></button>
+ <button id="copyLogButton" hidden="true">
+ <div id="copyLogTooltip">
+ <div id="copyLogTooltipText"></div>
+ </div>
+ </button>
+ <button id="cancelButton" hidden="true"></button>
+ <button id="connectButton" class="primary try-again" hidden="true"></button>
+ </div>
+ </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..7331f3cd48df
--- /dev/null
+++ b/browser/components/torconnect/content/torconnect-urlbar.css
@@ -0,0 +1,55 @@
+/*
+ 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;
+ 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 0.1em;
+ opacity: 0.6;
+}
+
+/* set appropriate sizes for the non-standard ui densities */
+:root[uidensity=compact] {
+ hbox.urlbar-page-action#torconnect-box {
+ height: 24px;
+ }
+ label#torconnect-label {
+ line-height: 24px;
+ }
+}
+:root[uidensity=touch] {
+ hbox.urlbar-page-action#torconnect-box {
+ 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;
+}
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..66213ceb7789 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"
);
@@ -62,6 +64,11 @@ 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",
@@ -112,6 +119,9 @@ const gTorPane = (function() {
let retval = {
// cached frequently accessed DOM elements
+ _messageBox: null,
+ _messageBoxMessage: null,
+ _messageBoxButton: null,
_useBridgeCheckbox: null,
_bridgeSelectionRadiogroup: null,
_builtinBridgeOption: null,
@@ -161,6 +171,42 @@ 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");
+ win.switchToTabHavingURI("about:torconnect");
+ });
+
+ 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;
diff --git a/browser/components/torpreferences/content/torPane.xhtml b/browser/components/torpreferences/content/torPane.xhtml
index 3c966b2b3726..88f82c37a3c9 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"
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/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 bf522234d588..acbba8147803 100644
--- a/browser/modules/TorStrings.jsm
+++ b/browser/modules/TorStrings.jsm
@@ -364,6 +364,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..f2c9dabdddbe 100644
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -155,6 +155,7 @@ EXTRA_JS_MODULES += [
'TabUnloader.jsm',
'ThemeVariableMap.jsm',
'TopSiteAttribution.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..ac1af7b8d65e
--- /dev/null
+++ b/browser/themes/shared/onionPattern.css
@@ -0,0 +1,121 @@
+/* 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;
+ 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 */
+}
+
+.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..95f073e673b4
--- /dev/null
+++ b/browser/themes/shared/onionPattern.inc.xhtml
@@ -0,0 +1,207 @@
+<!--
+ - 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">
+ <div class="onion-pattern-crop">
+ <div class="onion-pattern-column">
+ <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/toolkit/modules/RemotePageAccessManager.jsm b/toolkit/modules/RemotePageAccessManager.jsm
index eceaa7c857de..8a6c0911a060 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,25 @@ let RemotePageAccessManager = {
RPMAddMessageListener: ["*"],
RPMRemoveMessageListener: ["*"],
},
+ "about:torconnect": {
+ RPMAddMessageListener: ["*"],
+ RPMSendAsyncMessage: [
+ "GoToBrowserHome",
+ "OpenTorAdvancedPreferences",
+ "TorRetrieveBootstrapStatus",
+ "TorStopBootstrap",
+ ],
+ RPMSendQuery: [
+ "GetDirection",
+ "GetLocalizedBootstrapStatus",
+ "GetTorStrings",
+ "TorBootstrapErrorOccurred",
+ "TorConnect",
+ "TorCopyLog",
+ "TorIsNetworkDisabled",
+ "TorLogHasWarnOrErr",
+ ],
+ },
},
/**
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
[torbutton/master] Bug 27476: misc about:torconnect fixes and polish
by sysrqb@torproject.org 17 May '21
by sysrqb@torproject.org 17 May '21
17 May '21
commit 4eafa99d5a0f93184b674b099a49946f8846f766
Author: Richard Pospesel <richard(a)torproject.org>
Date: Mon Feb 15 19:18:29 2021 +0100
Bug 27476: misc about:torconnect fixes and polish
- about:tor fix to prevent showing 'something went wrong page' after about:torconnect bootstrap
- directly including tor-browser's onion-pattern xhtml/css rather than duplicating
- about:tor polish: replaced png with svg icons for ddg (from ddg), mail and arrow (photon UI included from firefox)
---
chrome/content/aboutTor/aboutTor.xhtml | 195 +--------------------------------
chrome/content/torbutton.js | 4 +-
chrome/skin/aboutTor.css | 101 ++---------------
chrome/skin/dax-logo.svg | 1 +
chrome/skin/forwardArrow.png | Bin 258 -> 0 bytes
chrome/skin/searchLogo.png | Bin 1912 -> 0 bytes
jar.mn | 15 ++-
7 files changed, 31 insertions(+), 285 deletions(-)
diff --git a/chrome/content/aboutTor/aboutTor.xhtml b/chrome/content/aboutTor/aboutTor.xhtml
index 6c712a67..f3a9032f 100644
--- a/chrome/content/aboutTor/aboutTor.xhtml
+++ b/chrome/content/aboutTor/aboutTor.xhtml
@@ -23,8 +23,8 @@
<meta http-equiv="Content-Security-Policy" content="default-src resource:; object-src 'none'" />
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>&aboutTor.title;</title>
- <link rel="stylesheet" type="text/css" media="all"
- href="resource://torbutton-assets/aboutTor.css"/>
+ <link rel="stylesheet" href="chrome://browser/skin/onionPattern.css" type="text/css" media="all" />
+ <link rel="stylesheet" href="resource://torbutton-assets/aboutTor.css" type="text/css" media="all" />
<script type="text/javascript" src="resource://torbutton-abouttor/aboutTor.js"></script>
</head>
<body dir="&locale.dir;">
@@ -55,7 +55,7 @@
<div class="searchbox hideIfTorOff"> <!-- begin form based search -->
<form action="&aboutTor.searchDDGPost.link;" method="get">
<div class="searchwrapper">
- <label class="searchlabel" for="search-text"> </label>
+ <label class="searchlabel" for="search-text"></label>
<input name="q" id="search-text" placeholder="&aboutTor.search.label;"
autocomplete="off" type="text"/>
<input id="search-button" value=""
@@ -71,198 +71,13 @@
</p>
<p id="manual" class="showForManual moreInfoLink">&aboutTor.torbrowser_user_manual_questions.label;
<a id="manualLink" target="_blank">&aboutTor.torbrowser_user_manual_link.label;</a></p>
- <p id="newsletter" class="moreInfoLink"><img class="imageStyle" src="resource://torbutton-assets/icon-newsletter.png"/><br/>&aboutTor.newsletter.tagline;<br/>
+ <p id="newsletter" class="moreInfoLink"><img class="imageStyle" src="chrome://browser/skin/mail.svg"/><br/>&aboutTor.newsletter.tagline;<br/>
<a href="https://newsletter.torproject.org">&aboutTor.newsletter.link_text; »</a>
</p>
<p id="mission">&aboutTor.tor_mission.label;
<a id="getInvolvedLink">&aboutTor.getInvolved.label;</a></p>
</div>
</div>
-
-<!--
- - 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">
- <div class="onion-pattern-row">
- <div class="circle solid"></div>
-
- <div class="circle border"></div>
-
- <div class="circle border">
- <div class="inner border"></div>
- <div class="inner border"></div>
- <div class="inner border"></div>
- </div>
-
- <div class="circle">
- <div class="half solid"></div>
- <div class="half dotted"></div>
- </div>
-
- <div class="circle dotted"></div>
-
- <div class="circle dotted">
- <div class="inner dotted"></div>
- <div class="inner dotted"></div>
- <div class="inner dotted"></div>
- </div>
-
- <div class="circle dashed"></div>
-
- <div class="circle dashed">
- <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 dotted">
- <div class="inner dotted"></div>
- <div class="inner dotted"></div>
- <div class="inner dotted"></div>
- </div>
-
- <div class="circle border">
- <div class="inner border"></div>
- <div class="inner border"></div>
- <div class="inner border"></div>
- </div>
-
- <div class="circle">
- <div class="half solid"></div>
- <div class="half solid"></div>
- </div>
-
- <div class="circle dashed">
- <div class="inner dashed"></div>
- <div class="inner dashed"></div>
- <div class="inner dashed"></div>
- </div>
-
- <div class="circle dotted"></div>
-
- <div class="circle dotted">
- <div class="inner dotted"></div>
- <div class="inner dotted"></div>
- <div class="inner dotted"></div>
- </div>
-
- <div class="circle dashed"></div>
-
- <div class="circle dashed">
- <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>
-
- <div class="onion-pattern-row onion-pattern-offset-row">
- <div class="circle dashed">
- <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 dotted">
- <div class="inner dotted"></div>
- <div class="inner dotted"></div>
- <div class="inner dotted"></div>
- </div>
-
- <div class="circle border">
- <div class="inner border"></div>
- <div class="inner border"></div>
- <div class="inner border"></div>
- </div>
-
- <div class="circle">
- <div class="half solid"></div>
- <div class="half solid"></div>
- </div>
-
- <div class="circle dashed">
- <div class="inner dashed"></div>
- <div class="inner dashed"></div>
- <div class="inner dashed"></div>
- </div>
-
- <div class="circle solid"></div>
-
- <div class="circle border"></div>
-
- <div class="circle border">
- <div class="inner border"></div>
- <div class="inner border"></div>
- <div class="inner border"></div>
- </div>
-
- <div class="circle">
- <div class="half solid"></div>
- <div class="half dotted"></div>
- </div>
-
- <div class="circle dotted"></div>
-
- <div class="circle dotted">
- <div class="inner dotted"></div>
- <div class="inner dotted"></div>
- <div class="inner dotted"></div>
- </div>
-
- <div class="circle dashed"></div>
-
- <div class="circle solid"></div>
-
- <div class="circle dashed">
- <div class="inner dashed"></div>
- <div class="inner dashed"></div>
- <div class="inner dashed"></div>
- </div>
-
- <div class="circle border">
- <div class="inner border"></div>
- <div class="inner border"></div>
- <div class="inner border"></div>
- </div>
-
- <div class="circle">
- <div class="half solid"></div>
- <div class="half solid"></div>
- </div>
-
- <div class="circle dotted">
- <div class="inner dotted"></div>
- <div class="inner dotted"></div>
- <div class="inner dotted"></div>
- </div>
-
- <div class="circle">
- <div class="half solid"></div>
- <div class="half dotted"></div>
- </div>
-
- <div class="circle dotted"></div>
- </div>
- </div>
+#include ../../../../../../browser/themes/shared/onionPattern.inc.xhtml
</body>
</html>
diff --git a/chrome/content/torbutton.js b/chrome/content/torbutton.js
index 39c1abeb..48539a96 100644
--- a/chrome/content/torbutton.js
+++ b/chrome/content/torbutton.js
@@ -934,8 +934,7 @@ function torbutton_do_tor_check()
{
let checkSvc = Cc["@torproject.org/torbutton-torCheckService;1"]
.getService(Ci.nsISupports).wrappedJSObject;
- if (checkSvc.kCheckNotInitiated != checkSvc.statusOfTorCheck ||
- m_tb_prefs.getBoolPref("extensions.torbutton.use_nontor_proxy") ||
+ if (m_tb_prefs.getBoolPref("extensions.torbutton.use_nontor_proxy") ||
!m_tb_prefs.getBoolPref("extensions.torbutton.test_enabled"))
return; // Only do the check once.
@@ -1119,6 +1118,7 @@ function torbutton_initiate_remote_tor_check() {
function torbutton_tor_check_ok()
{
+ torbutton_do_tor_check();
let checkSvc = Cc["@torproject.org/torbutton-torCheckService;1"]
.getService(Ci.nsISupports).wrappedJSObject;
return (checkSvc.kCheckFailed != checkSvc.statusOfTorCheck);
diff --git a/chrome/skin/aboutTor.css b/chrome/skin/aboutTor.css
index 8d5c4a83..38486241 100644
--- a/chrome/skin/aboutTor.css
+++ b/chrome/skin/aboutTor.css
@@ -9,6 +9,9 @@
--abouttor-text-color: white;
--abouttor-bg-toron-color: #420C5D;
--abouttor-bg-toroff-color: #A4000F;
+ --onion-opacity: 0.2;
+ --onion-color: #fff;
+ --onion-radius: 50px;
}
* {
@@ -23,6 +26,7 @@ html {
body {
display: flex;
flex-direction: column;
+ justify-content: space-between;
width: 100%;
height: 100%;
margin: 0px auto;
@@ -159,7 +163,11 @@ body:not([showmanual]) .showForManual {
}
#bottom img.imageStyle {
- padding-inline-end: 10px;
+ padding-inline-end: 0.5em;
+ height: 1.5em;
+ vertical-align: bottom;
+ -moz-context-properties: fill;
+ fill: white;
}
/* Hide the linebreaks on large enough screens (desktops, laptops, and
@@ -195,7 +203,7 @@ body:not([showmanual]) .showForManual {
height: auto;
width: 50px;
display: inline-block;
- background: url('searchLogo.png') no-repeat center center;
+ background: url('dax-logo.svg') no-repeat center center;
background-size: 30px 30px;
}
@@ -203,8 +211,8 @@ body:not([showmanual]) .showForManual {
height: auto;
width: 36px;
border: 0;
- background: url('forwardArrow.png') no-repeat center center;
- background-size: 16px 14px;
+ background: url('chrome://browser/skin/forward.svg') no-repeat center center;
+ background-size: 16px 16px;
cursor: pointer;
}
@@ -220,91 +228,6 @@ body:not([showmanual]) .showForManual {
margin: 0;
font-size: 15px;
}
-
-.onion-pattern-container {
- flex: auto; /* grow to consume remaining space on the page */
- display: flex;
- flex-direction: column;
- justify-content: end; /* position circles at the bottom */
- margin: 0px auto;
- width: 100%;
- max-width: 2200px; /* room for our 20 circles */
- min-height: 232px; /* room for 2 rows of circles */
- overflow-x: hidden; /* clip extra circles on the sides */
- direction: ltr;
-}
-
-.onion-pattern-row {
- width: 2200px;
- display: flex;
- flex-direction: row;
- position: relative;
-}
-
-.onion-pattern-offset-row {
- left: -40px;
-}
-
-/* With borders, circles range in size from 100 x 100px to 116 x 116px. */
-.circle {
- opacity: 0.2;
- position: relative;
- width: 100px;
- height: 100px;
- border-radius: 50%;
-}
-
-.inner {
- position: absolute;
-}
-
-.inner:nth-child(1){
- transform: translate(calc(12.5% - 2px),calc(12.5% - 2px));
- width: calc(100% * 0.75);
- height: calc(100% * 0.75);
- border-radius: 50%;
-}
-
-.inner:nth-child(2){
- transform: translate(calc(40% - 2px),calc(40% - 2px));
- width: calc(100% * 0.5);
- height: calc(100% * 0.5);
- border-radius: 50%;
-}
-
-.inner:nth-child(3){
- transform: translate(calc(108% - 2px),calc(108% - 2px));
- width: calc(100% * 0.25);
- height: calc(100% * 0.25);
- border-radius: 50%;
-}
-
-.solid {
- background-color: #fff;
-}
-
-.border {
- border: 4px solid #fff;
-}
-
-.dashed {
- border: 4px dashed #fff;
-}
-
-.dotted {
- border: 4px dotted #fff;
-}
-
-.bold {
- border: 8px solid #fff;
-}
-
-.half {
- width: 100px;
- height: 50px;
- border-radius: 50px 50px 0 0;
-}
-
/*
* Mobile specific css
*/
diff --git a/chrome/skin/dax-logo.svg b/chrome/skin/dax-logo.svg
new file mode 100644
index 00000000..94ad7c35
--- /dev/null
+++ b/chrome/skin/dax-logo.svg
@@ -0,0 +1 @@
+<svg width="120" height="120" viewbox="0 0 120 120" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><circle id="a" cx="50.833" cy="50.833" r="50.25"/><linearGradient x1="3.084%" y1="49.368%" x2="100.592%" y2="49.368%" id="c"><stop stop-color="#6176B9" offset=".56%"/><stop stop-color="#394A9F" offset="69.1%"/></linearGradient><linearGradient x1="-.006%" y1="49.006%" x2="98.932%" y2="49.006%" id="d"><stop stop-color="#6176B9" offset=".56%"/><stop stop-color="#394A9F" offset="69.1%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><circle fill="#FFF" cx="60" cy="60" r="57.5"/><ellipse fill="#DE5833" cx="60" cy="60" rx="50.25" ry="50.25"/><path d="M60 120C26.917 120 0 93.083 0 60S26.917 0 60 0s60 26.917 60 60-26.917 60-60 60zM60 4.917C29.667 4.917 4.917 29.583 4.917 60c0 30.333 24.666 55.083 55.083 55.083 30.417 0 55.083-24.666 55.083-55.083 0-30.333-24.75-55.083-55.083-55.083z" fill="#DE5833"/><g transform="translate(9.167 9.167)"><mask id
="b" fill="#fff"><use xlink:href="#a"/></mask><use fill="#DE5833" xlink:href="#a"/><g mask="url(#b)"><path d="M71.917 127.25c-1.75-8.25-12.25-27.167-16.334-35.083-3.916-7.917-7.916-19.084-6.083-26.417.417-1.417-3.333-11.417-2.333-12 8.5-5.5 10.666.583 14-1.75 1.75-1.167 4.166 1 4.75-1 2.166-7.667-2.917-20.917-8.834-26.583-2-2-4.75-3.167-8.083-3.75-1.167-1.75-3.333-3.334-6.083-4.917-3.167-1.75-10.25-3.917-13.834-4.5-2.583-.417-3.166.167-4.166.417 1 0 5.75 2.333 6.666 2.583-1 .583-3.583 0-5.333.75-.75.417-1.583 2-1.583 2.583 4.916-.583 12.583 0 17.166 2-3.583.417-9.083.75-11.416 2.167-6.917 3.583-9.834 12-8.084 22.25 1.75 10.083 9.834 47.083 12.25 59.333 2.584 12.25-5.5 20.334-10.416 22.5l5.5.417-1.75 3.917c6.5.75 13.833-1.417 13.833-1.417-1.417 3.917-11.25 5.5-11.25 5.5s4.75 1.417 12.25-1.417c7.667-2.916 12.25-4.75 12.25-4.75l7.5 9.417 2.917-6.917 6.916 7.25c-.25-.5 1.334-2.25-.416-10.583z" fill="#D5D7D8"/><path d="M74.083 125.5c-1.75-8.25-12.25-27.167-16.333-35.083C53.833 82.5 49.83
3 71.333 51.667 64c.416-1.417.416-6.667 1.416-7.5 8.5-5.5 7.917-.167 11.25-2.583 1.75-1.167 3.167-2.75 3.75-4.917 2.167-7.667-2.916-20.917-8.833-26.583-2-2-4.75-3.167-8.083-3.75-1.167-1.75-3.334-3.334-6.084-4.917-5.333-2.917-12-3.917-18.333-2.917 1 0 3.333 2.167 4.167 2.334-1.417 1-5.084.75-5.084 2.916 4.917-.416 10.25.167 15 2.334-3.583.416-6.916 1.416-9.25 2.583-6.916 3.583-8.666 10.833-6.916 20.917C26.417 52 34.5 89 36.917 101.25c2.583 12.25-5.5 20.333-10.417 22.5l5.5.417-1.75 3.916c6.5.75 13.833-1.416 13.833-1.416-1.416 3.916-11.25 5.5-11.25 5.5s4.75 1.416 12.25-1.417c7.667-2.917 12.25-4.75 12.25-4.75l3.584 9.417 6.916-6.917 2.917 7.25c-.417 0 5.083-1.75 3.333-10.25z" fill="#FFF"/><path d="M32.5 42.583c0-2.166 1.75-3.75 3.75-3.75 2.167 0 3.75 1.75 3.75 3.75 0 2.167-1.75 3.75-3.75 3.75-2.167 0-3.75-1.583-3.75-3.75z" fill="#2D4F8E"/><path d="M36.833 41.167c0-.584.417-1 1-1 .584 0 1 .416 1 1 0 .583-.416 1-1 1-.416 0-1-.417-1-1z" fill="#FFF"/><path d="M58.333 40.167c0-1.75 1.417-3.3
34 3.334-3.334 1.75 0 3.333 1.417 3.333 3.334 0 1.75-1.417 3.333-3.333 3.333-1.75.083-3.334-1.333-3.334-3.333z" fill="#2D4F8E"/><path d="M62.25 39.167c0-.417.417-.75.75-.75.417 0 .75.416.75.75 0 .416-.417.75-.75.75-.333.083-.75-.334-.75-.75z" fill="#FFF"/><path d="M15.583 21.5s-2.916-1.417-5.75.417c-2.75 1.75-2.75 3.583-2.75 3.583S5.5 22.167 9.417 20.583c4.416-1.583 6.166.917 6.166.917z" fill="url(#c)" transform="translate(21.667 10)"/><path d="M42 21.333s-2-1.166-3.75-1.166c-3.333 0-4.167 1.583-4.167 1.583s.584-3.583 4.75-2.75c2.334.167 3.167 2.333 3.167 2.333z" fill="url(#d)" transform="translate(21.667 10)"/><path d="M47.917 57.167c.416-2.334 6.333-6.667 10.416-6.917 4.167-.167 5.5-.167 9.084-1C71 48.5 80 46.083 82.583 44.917c2.584-1.167 13.167.583 5.75 4.75-3.166 1.75-12 5.083-18.333 7.083-6.333 1.75-10.083-1.75-12 1.417-1.583 2.333-.417 5.75 7.083 6.5 10.084 1 19.667-4.5 20.667-1.584 1 2.917-8.667 6.5-14.583 6.667-5.917.167-17.917-3.917-19.667-5.083-1.833-1.584-4.25-4.417-3.583
-7.5z" fill="#FDD20A"/></g></g><path d="M61.583 94.917s-14.166-7.5-14.416-4.5C47 93.583 47.167 106 48.75 107c1.583 1 13.417-6.083 13.417-6.083l-.584-6zm5.5-.667S76.75 87 78.917 87.333c2.166.417 2.583 15.584.75 16.334-1.917.833-13-3.667-13-3.667l.416-5.75z" fill="#65BC46"/><path d="M58.25 95.667c0 4.916-.75 7.083 1.417 7.5 2.166.416 6.083 0 7.5-1 1.416-1 .166-7.25-.167-8.5-.667-1.167-8.75-.167-8.75 2z" fill="#43A244"/><path d="M59 94.5c0 4.917-.75 7.083 1.417 7.5 2.166.417 6.083 0 7.5-1 1.416-1 .166-7.25-.167-8.5-.5-1-8.75-.167-8.75 2z" fill="#65BC46"/></g></svg>
\ No newline at end of file
diff --git a/chrome/skin/forwardArrow.png b/chrome/skin/forwardArrow.png
deleted file mode 100644
index ceea950f..00000000
Binary files a/chrome/skin/forwardArrow.png and /dev/null differ
diff --git a/chrome/skin/searchLogo.png b/chrome/skin/searchLogo.png
deleted file mode 100644
index 98ae319e..00000000
Binary files a/chrome/skin/searchLogo.png and /dev/null differ
diff --git a/jar.mn b/jar.mn
index c8fd813f..6476f8ff 100644
--- a/jar.mn
+++ b/jar.mn
@@ -4,10 +4,17 @@ torbutton.jar:
% content torbutton %content/
- content/ (chrome/content/*)
- components/ (components/*)
- modules/ (modules/*)
- skin/ (chrome/skin/*)
+ content/torbutton.js (chrome/content/torbutton.js)
+ content/tor-circuit-display.js (chrome/content/tor-circuit-display.js)
+ content/preferences.xhtml (chrome/content/preferences.xhtml)
+ content/aboutTor/aboutTor-content.js (chrome/content/aboutTor/aboutTor-content.js)
+* content/aboutTor/aboutTor.xhtml (chrome/content/aboutTor/aboutTor.xhtml)
+ content/aboutTor/resources/aboutTor.js (chrome/content/aboutTor/resources/aboutTor.js)
+ content/preferences-mobile.js (chrome/content/preferences-mobile.js)
+
+ components/ (components/*)
+ modules/ (modules/*)
+ skin/ (chrome/skin/*)
% resource torbutton %
% resource torbutton-abouttor resource://torbutton/content/aboutTor/resources/ contentaccessible=yes
1
0
[torbutton/master] Merge remote-tracking branch 'richardgl/27476_rev'
by sysrqb@torproject.org 17 May '21
by sysrqb@torproject.org 17 May '21
17 May '21
commit 5a2ad51c81ade35f471f971da81ff0698bf710a8
Merge: 2c03b2c3 4eafa99d
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Mon May 17 19:27:10 2021 +0000
Merge remote-tracking branch 'richardgl/27476_rev'
chrome/content/aboutTor/aboutTor.xhtml | 195 +--------------------------------
chrome/content/torbutton.js | 4 +-
chrome/skin/aboutTor.css | 101 ++---------------
chrome/skin/dax-logo.svg | 1 +
chrome/skin/forwardArrow.png | Bin 258 -> 0 bytes
chrome/skin/searchLogo.png | Bin 1912 -> 0 bytes
jar.mn | 15 ++-
7 files changed, 31 insertions(+), 285 deletions(-)
1
0
[tor-browser-build/master] Bug 40297: Use the right commits for get_gradle_dependencies_list
by sysrqb@torproject.org 17 May '21
by sysrqb@torproject.org 17 May '21
17 May '21
commit d6fbd77f14e646c7030577cea1b10429129850b4
Author: Nicolas Vigier <boklm(a)torproject.org>
Date: Fri May 14 11:07:33 2021 +0200
Bug 40297: Use the right commits for get_gradle_dependencies_list
---
projects/android-components/config | 4 +++-
projects/fenix/config | 4 +++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/projects/android-components/config b/projects/android-components/config
index 3b709a6..1f98428 100644
--- a/projects/android-components/config
+++ b/projects/android-components/config
@@ -16,10 +16,11 @@ var:
gradle_dependencies_version: 24
gradle_version: 6.6.1
glean_parser: 2.2.0
+ git_branch: '[% project %]-[% c("var/android_components_version") %]-[% c("var/torbrowser_branch") %]-1'
targets:
nightly:
- git_hash: '[% project %]-[% c("var/android_components_version") %]-[% c("var/torbrowser_branch") %]-1'
+ git_hash: '[% c("var/git_branch") %]'
tag_gpg_id: 0
input_files:
@@ -81,5 +82,6 @@ steps:
get_gradle_dependencies_list:
filename: 'gradle-dependencies-list-[% c("var/android_components_version") %].txt'
get_gradle_dependencies_list: '[% INCLUDE build %]'
+ git_hash: '[% c("var/git_branch") %]^{/Bug 40023: Stop PrivateNotificationService}'
var:
fetch_gradle_dependencies: 1
diff --git a/projects/fenix/config b/projects/fenix/config
index 9a54715..6f349ac 100644
--- a/projects/fenix/config
+++ b/projects/fenix/config
@@ -10,6 +10,7 @@ variant: Beta
var:
fenix_version: 88.1.3
torbrowser_branch: 10.5
+ git_branch: 'tor-browser-[% c("var/fenix_version") %]-[% c("var/torbrowser_branch") %]-1'
copyright_year: '[% exec("git show -s --format=%ci").remove("-.*") %]'
container:
use_container: 1
@@ -20,7 +21,7 @@ var:
targets:
nightly:
- git_hash: 'tor-browser-[% c("var/fenix_version") %]-[% c("var/torbrowser_branch") %]-1'
+ git_hash: '[% c("var/git_branch") %]'
tag_gpg_id: 0
variant: Nightly
@@ -64,6 +65,7 @@ steps:
use_container: 0
get_gradle_dependencies_list:
+ git_hash: '[% c("var/git_branch") %]^{/Add Tor integration and UI}'
filename: 'gradle-dependencies-list-[% c("var/fenix_version") %].txt'
get_gradle_dependencies_list: '[% INCLUDE build %]'
var:
1
0
[torbutton/master] fixup! Bug 40035: Localize Cryptocurrency Safety messages
by sysrqb@torproject.org 13 May '21
by sysrqb@torproject.org 13 May '21
13 May '21
commit 2c03b2c398e111fa185f34a616ceb7448c9a0c26
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Thu May 13 16:18:23 2021 +0000
fixup! Bug 40035: Localize Cryptocurrency Safety messages
---
chrome/locale/en-US/torbutton.properties | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/chrome/locale/en-US/torbutton.properties b/chrome/locale/en-US/torbutton.properties
index 4c153158..0f4594bc 100644
--- a/chrome/locale/en-US/torbutton.properties
+++ b/chrome/locale/en-US/torbutton.properties
@@ -139,7 +139,7 @@ onionLocation.askEverytime=Ask every time
onionLocation.prioritizeOnionsDescription=Prioritize .onion sites when known.
onionLocation.onionServicesTitle=Onion Services
-# LOCALIZATION NOTE: %S will be replaced with the crytocurrency address.
+# LOCALIZATION NOTE: %S will be replaced with the cryptocurrency address.
cryptoSafetyPrompt.cryptoWarning=A cryptocurrency address (%S) has been copied from an insecure website. It could have been modified.
cryptoSafetyPrompt.whatCanHeading=What can you do about it?
cryptoSafetyPrompt.whatCanBody=You can try reconnecting with a new circuit to establish a secure connection, or accept the risk and dismiss this warning.
1
0
[tor-launcher/master] fixup! Bug 27476: about:torconnect fixes and new strings
by sysrqb@torproject.org 13 May '21
by sysrqb@torproject.org 13 May '21
13 May '21
commit 4763691a739ce2cb2b8cfda07eb76ccf2e51f41a
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Thu May 13 16:16:36 2021 +0000
fixup! Bug 27476: about:torconnect fixes and new strings
---
src/chrome/locale/en-US/torlauncher.properties | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/chrome/locale/en-US/torlauncher.properties b/src/chrome/locale/en-US/torlauncher.properties
index 7787698..e0b07f0 100644
--- a/src/chrome/locale/en-US/torlauncher.properties
+++ b/src/chrome/locale/en-US/torlauncher.properties
@@ -94,4 +94,4 @@ torlauncher.nsresult.NS_ERROR_NET_RESET=The connection to the server was lost.
torlauncher.nsresult.NS_ERROR_CONNECTION_REFUSED=Could not connect to the server.
torlauncher.nsresult.NS_ERROR_PROXY_CONNECTION_REFUSED=Could not connect to the proxy.
-torlauncher.copiedNLogMessages=Copied %S Logs
+torlauncher.copiedNLogMessagesShort=Copied %S Logs
1
0
commit b89f42cdb5117d082d945816ce132da0499173af
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Fri Apr 30 22:45:36 2021 +0000
Bug 40017: Add FF88 audit
---
audits/FF88_NETWORK_AUDIT | 141 ++++++++++++++++++++++++++++++++++++++++++++++
audits/code_audit.sh | 6 +-
2 files changed, 146 insertions(+), 1 deletion(-)
diff --git a/audits/FF88_NETWORK_AUDIT b/audits/FF88_NETWORK_AUDIT
new file mode 100644
index 0000000..6462aad
--- /dev/null
+++ b/audits/FF88_NETWORK_AUDIT
@@ -0,0 +1,141 @@
+=============== Firefox General =============
+
+Start: 4068febfd76d9ec557591240d7496be42c27c17f # FIREFOX_87_0_BUILD3
+End: 676143236541851e068696fa4528d87a9bb0088d # FIREFOX_88_0_BUILD1
+
+=============== Firefox Native DNS Portion =============
+
+PR_GetHostByName
+PR_GetIPNodeByName
+PR_GetAddrInfoByName
+PR_StringToNetAddr (itself is good as it passes AI_NUMERICHOST to getaddrinfo. No resolution.)
+
+MDNS
+TRR (DNS Trusted Recursive Resolver)
+Direct Paths to DNS resolution:
+nsDNSService::Resolve
+nsDNSService::AsyncResolve
+nsHostResolver::ResolveHost
+
+# FF88: Nothing of interest
+
+============ Firefox Misc Socket Portion ==============
+
+SOCK_
+SOCKET_
+_SOCKET
+
+UDPSocket
+TCPSocket
+ PR_NewTCPSocket
+ AsyncTCPSocket
+
+Misc PR_Socket
+
+# FF88: Nothing of interest
+
+=========== Firefox Misc XPCOM Portion ================
+
+Misc XPCOM (including commands for pre-diff review approach)
+ *SocketProvider
+ grep -R udp-socket .
+ grep -R tcp-socket .
+ grep for tcpsocket
+ grep -R "NS_" | grep SOCKET | grep "_C"
+ grep -R "@mozilla.org/network/" . | grep socket | grep -v udp-socket
+
+# FF88: Nothing of interest
+
+============ Firefox Rust Portion ================
+
+Rust
+
+# FF88: Nothing of interest (using `java_audit.sh`)
+
+============ Firefox Android Portion =============
+
+Android Java calls
+ - URLConnection
+ - XXX: getInputStream? other methods?
+ - HttpURLConnection
+ - UrlConnectionDownloader
+ - ch.boye.httpclientandroidlib.impl.client.* (look for execute() calls)
+ - grep -n openConnection\( mobile/android/thirdparty/
+ - java.net.URL -- has SEVERAL proxy bypass URL fetching methods :/
+ - java.net
+ - javax.net
+ - ch.boye.httpclientandroidlib.conn.* (esp ssl)
+ - ch.boye.httpclientandroidlib.impl.conn.* (esp ssl)
+ - Sudden appearance of thirdparty libs:
+ - OkHttp
+ - Retrofit
+ - Glide
+ - com.amitshekhar.android
+ - IntentHelper
+ - openUriExternal (can come from GeckoAppShell too)
+ - getHandlersForMimeType
+ - getHandlersForURL
+ - getHandlersForIntent
+ - android.content.Intent - too common; instead find launch methods:
+ - startActivity
+ - startActivities
+ - sendBroadcast
+ - sendOrderedBroadcast
+ - startService
+ - bindService
+ - android.app.PendingIntent
+ - android.app.DownloadManager
+ - ActivityHandlerHelper.startIntentAndCatch
+
+# FF88
+# Bug 1694481
+# - Removes unused code
+
+============ Application Services Portion =============
+
+Start: 1ee6b32f3ee569036fdf1015cf7ffc01ded2860f # v71.0.0
+End: ad7b64fa03eeeb00815125e635d1fb8809befd40 # v74.0.1
+
+# FF88: Nothing related to networking in Java/Koltlin/Rust code (using `code_audit.sh`)
+
+============ Android Components Portion =============
+
+Start: bea80bbaccc431994a534a087b223563826ac256 # v73.0.11
+End: e09d8a00b5eae63767d905a74966be301b5dd059 # v74.0.11
+
+# FF88 (using `code_audit.sh`)
+# Issue #9823
+# - Make users aware that download was not performed because of a denied permission
+# - Review Result: Safe
+# - Comments:
+# - Calls startActivity(), but the target is hard-coded as the Android Settings
+
+# Issue #9757
+# - Remove downloads notification when private tabs are closed
+# - Review Result: Safe
+# - Comment:
+# - Calls startService(), but the target is hard-coded as the internal Downloads Service
+
+# Issue #9713
+# - Autofill: Support alternative authentication methods
+# - Review Result: Conditionally Safe
+# - Comment:
+# - Calls startActivityForResult() with an arbitrary target Activity.
+# - Fenix instantiates the configuration using itself as the target.
+
+============ Fenix Portion =============
+
+Start: 9d91b8eeb9d287ee95937b5edfffde383982267a # v87.0.0-rc.1
+End: 5f98c4ec98d663c763dc4ec5ea84a14cdf342d04 # v88.1.1
+
+# FF88: (using `java_audit.sh`)
+# - 8856a3c1d769586bfd6daa7b3b2df48fb26f1bc3
+# - Integrate Android Autofill support into Nightly and debug builds.
+# - Review Result: Safe (but see fenix#40160)
+
+============ Regression/Prior Vuln Review =========
+
+Review proxy bypass bugs; check for new vectors to look for:
+ - https://trac.torproject.org/projects/tor/query?keywords=~tbb-proxy
+ - Look for new features like these. Especially external app launch vectors
+
diff --git a/audits/code_audit.sh b/audits/code_audit.sh
index c7c0848..d260d15 100755
--- a/audits/code_audit.sh
+++ b/audits/code_audit.sh
@@ -55,6 +55,10 @@ initialize_java_symbols() {
KEYWORDS+=(ActivityDelegate)
# Added in FF87 audit
KEYWORDS+=(AutofillService)
+ # Added in FF88 audit
+ KEYWORDS+=(AutofillConfiguration)
+ KEYWORDS+=(Authenticator)
+ KEYWORDS+=(AutofillUnlockActivity)
}
initialize_rust_symbols() {
@@ -155,7 +159,7 @@ done
echo "Diffing patches-${OLD}-${NEW}-${SCOPE}.diff from all ${path[*]} files"
# Exclude Deleted and Unmerged files from diff
DIFF_FILTER=ACMRTXB
-git diff --color=always --color-moved --diff-filter="${DIFF_FILTER}" -U20 -G"${GREP_LINE}" "$OLD" "$NEW" -- "${path[@]}" > "patches-${OLD}-${NEW}-${SCOPE}.diff"
+git diff --stat --color=always --color-moved --diff-filter="${DIFF_FILTER}" -U20 -G"${GREP_LINE}" "$OLD" "$NEW" -- "${path[@]}" > "patches-${OLD}-${NEW}-${SCOPE}.diff"
# Step 4: Highlight the keyword with an annoying, flashing color
export GREP_COLOR="05;37;41"
1
0
[tor-browser/tor-browser-78.10.0esr-10.5-1] squash! 40209: Implement Basic Crypto Safety
by sysrqb@torproject.org 13 May '21
by sysrqb@torproject.org 13 May '21
13 May '21
commit 627d83ded2fb977f68da7fcaad0ee763ec5223ec
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Wed May 5 16:53:11 2021 +0000
squash! 40209: Implement Basic Crypto Safety
Bug 40428: Fix string attribute names
---
browser/modules/TorStrings.jsm | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/browser/modules/TorStrings.jsm b/browser/modules/TorStrings.jsm
index bf522234d588..1e08b168e4af 100644
--- a/browser/modules/TorStrings.jsm
+++ b/browser/modules/TorStrings.jsm
@@ -115,33 +115,33 @@ var TorStrings = {
let retval = {
cryptoWarning: getString(
- "cryptoSafetyPrompt.cryptoWarning",
+ "cryptoWarning",
"A cryptocurrency address (%S) has been copied from an insecure website. It could have been modified."
),
whatCanHeading: getString(
- "cryptoSafetyPrompt.whatCanHeading",
+ "whatCanHeading",
"What can you do about it?"
),
whatCanBody: getString(
- "cryptoSafetyPrompt.whatCanBody",
+ "whatCanBody",
"You can try reconnecting with a new circuit to establish a secure connection, or accept the risk and dismiss this warning."
),
- learnMore: getString("cryptoSafetyPrompt.learnMore", "Learn more"),
+ learnMore: getString("learnMore", "Learn more"),
learnMoreURL: `https://support.torproject.org/${getLocale()}/`,
primaryAction: getString(
- "cryptoSafetyPrompt.primaryAction",
+ "primaryAction",
"Reload Tab with a New Circuit"
),
primaryActionAccessKey: getString(
- "cryptoSafetyPrompt.primaryActionAccessKey",
+ "primaryActionAccessKey",
"R"
),
secondaryAction: getString(
- "cryptoSafetyPrompt.secondaryAction",
+ "secondaryAction",
"Dismiss Warning"
),
secondaryActionAccessKey: getString(
- "cryptoSafetyPrompt.secondaryActionAccessKey",
+ "secondaryActionAccessKey",
"D"
),
};
1
0
12 May '21
commit f3cfdde8282b078341840388670f51e5665cb823
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Fri Apr 9 17:38:31 2021 +0000
Release preparations for 0.2.28
Version bump
---
src/install.rdf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/install.rdf b/src/install.rdf
index 510052a..c438e7b 100644
--- a/src/install.rdf
+++ b/src/install.rdf
@@ -7,7 +7,7 @@
<em:creator>The Tor Project, Inc.</em:creator>
<em:contributor>Pearl Crescent, LLC</em:contributor>
<em:id>tor-launcher(a)torproject.org</em:id>
- <em:version>0.2.27</em:version>
+ <em:version>0.2.28</em:version>
<em:multiprocessCompatible>true</em:multiprocessCompatible>
<em:homepageURL>https://www.torproject.org/projects/torbrowser.html</em:homepageURL>
<em:updateURL>data:text/plain,</em:updateURL>
1
0