tor-commits
Threads by month
- ----- 2025 -----
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
August 2021
- 15 participants
- 1353 discussions

[tor-browser/tor-browser-78.13.0esr-11.0-2] Bug 40475: Include clearing CORS preflight cache
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit edc57b8ea477545503d21ac366da1591e8c45a34
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Sun Jun 6 20:32:23 2021 +0000
Bug 40475: Include clearing CORS preflight cache
---
netwerk/protocol/http/nsCORSListenerProxy.cpp | 7 +++++++
netwerk/protocol/http/nsCORSListenerProxy.h | 1 +
netwerk/protocol/http/nsHttpHandler.cpp | 2 ++
3 files changed, 10 insertions(+)
diff --git a/netwerk/protocol/http/nsCORSListenerProxy.cpp b/netwerk/protocol/http/nsCORSListenerProxy.cpp
index 76870e6cea3f..6d2e160c2a9b 100644
--- a/netwerk/protocol/http/nsCORSListenerProxy.cpp
+++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp
@@ -346,6 +346,13 @@ void nsCORSListenerProxy::Shutdown() {
sPreflightCache = nullptr;
}
+/* static */
+void nsCORSListenerProxy::Clear() {
+ if (sPreflightCache) {
+ sPreflightCache->Clear();
+ }
+}
+
nsCORSListenerProxy::nsCORSListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal,
bool aWithCredentials)
diff --git a/netwerk/protocol/http/nsCORSListenerProxy.h b/netwerk/protocol/http/nsCORSListenerProxy.h
index 8c0df2e0ff28..3f76be33f209 100644
--- a/netwerk/protocol/http/nsCORSListenerProxy.h
+++ b/netwerk/protocol/http/nsCORSListenerProxy.h
@@ -54,6 +54,7 @@ class nsCORSListenerProxy final : public nsIStreamListener,
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
static void Shutdown();
+ static void Clear();
[[nodiscard]] nsresult Init(nsIChannel* aChannel,
DataURIHandling aAllowDataURI);
diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp
index d5e2c61dbec9..c6cb95ca7fcc 100644
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -10,6 +10,7 @@
#include "prsystem.h"
#include "AltServiceChild.h"
+#include "nsCORSListenerProxy.h"
#include "nsError.h"
#include "nsHttp.h"
#include "nsHttpHandler.h"
@@ -2290,6 +2291,7 @@ nsHttpHandler::Observe(nsISupports* subject, const char* topic,
mAltSvcCache->ClearAltServiceMappings();
}
}
+ nsCORSListenerProxy::Clear();
} else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
nsAutoCString converted = NS_ConvertUTF16toUTF8(data);
if (!strcmp(converted.get(), NS_NETWORK_LINK_DATA_CHANGED)) {
1
0

[tor-browser/tor-browser-78.13.0esr-11.0-2] Bug 40166: Disable security.certerrors.mitm.auto_enable_enterprise_roots
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit f35559de5f03e40762f0c350a2e0a2f493f37581
Author: Alex Catarineu <acat(a)torproject.org>
Date: Fri Oct 9 12:55:35 2020 +0200
Bug 40166: Disable security.certerrors.mitm.auto_enable_enterprise_roots
---
browser/app/profile/000-tor-browser.js | 3 +++
browser/components/BrowserGlue.jsm | 14 ++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/browser/app/profile/000-tor-browser.js b/browser/app/profile/000-tor-browser.js
index 2db11b1ea3d7..760c405d06a6 100644
--- a/browser/app/profile/000-tor-browser.js
+++ b/browser/app/profile/000-tor-browser.js
@@ -325,6 +325,9 @@ pref("security.enterprise_roots.enabled", false);
// Don't ping Mozilla for MitM detection, see bug 32321
pref("security.certerrors.mitm.priming.enabled", false);
+// Don't automatically enable enterprise roots, see bug 40166
+pref("security.certerrors.mitm.auto_enable_enterprise_roots", false);
+
// Disable the language pack signing check for now on macOS, see #31942
#ifdef XP_MACOSX
pref("extensions.langpacks.signatures.required", false);
diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm
index 057a2121533c..3750230a250b 100644
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -1319,6 +1319,20 @@ BrowserGlue.prototype = {
// handle any UI migration
this._migrateUI();
+ // Clear possibly auto enabled enterprise_roots prefs (see bug 40166)
+ if (
+ !Services.prefs.getBoolPref(
+ "security.certerrors.mitm.auto_enable_enterprise_roots"
+ ) &&
+ Services.prefs.getBoolPref(
+ "security.enterprise_roots.auto-enabled",
+ false
+ )
+ ) {
+ Services.prefs.clearUserPref("security.enterprise_roots.enabled");
+ Services.prefs.clearUserPref("security.enterprise_roots.auto-enabled");
+ }
+
if (!Services.prefs.prefHasUserValue(PREF_PDFJS_ISDEFAULT_CACHE_STATE)) {
PdfJs.checkIsDefault(this._isNewProfile);
}
1
0

[tor-browser/tor-browser-78.13.0esr-11.0-2] Adding issue template for bugs.
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit 8d05e1da99b0770b2052a821ba9def711af2c2a7
Author: Gaba <gaba(a)torproject.org>
Date: Mon Jun 28 11:44:16 2021 -0700
Adding issue template for bugs.
---
.gitlab/issue_templates/UXBug.md | 29 +++++++++++++++++++++++++++++
.gitlab/issue_templates/bug.md | 32 ++++++++++++++++++++++++++++++++
2 files changed, 61 insertions(+)
diff --git a/.gitlab/issue_templates/UXBug.md b/.gitlab/issue_templates/UXBug.md
new file mode 100644
index 000000000000..8e7cb2a5e163
--- /dev/null
+++ b/.gitlab/issue_templates/UXBug.md
@@ -0,0 +1,29 @@
+<!--
+* Use this issue template for reporting a new UX bug.
+-->
+
+### Summary
+**Summarize the bug encountered concisely.**
+
+
+### Steps to reproduce:
+**How one can reproduce the issue - this is very important.**
+
+1. Step 1
+2. Step 2
+3. ...
+
+### What is the current bug behavior?
+**What actually happens.**
+
+
+### What is the expected behavior?
+**What you want to see instead**
+
+
+
+## Relevant logs and/or screenshots
+**Do you have screenshots? Attach them to this ticket please.**
+
+/label ~tor-ux ~needs-investigation ~bug
+/assign @nah
diff --git a/.gitlab/issue_templates/bug.md b/.gitlab/issue_templates/bug.md
new file mode 100644
index 000000000000..6ce85a4864be
--- /dev/null
+++ b/.gitlab/issue_templates/bug.md
@@ -0,0 +1,32 @@
+<!--
+* Use this issue template for reporting a new bug.
+-->
+
+### Summary
+**Summarize the bug encountered concisely.**
+
+
+### Steps to reproduce:
+**How one can reproduce the issue - this is very important.**
+
+1. Step 1
+2. Step 2
+3. ...
+
+### What is the current bug behavior?
+**What actually happens.**
+
+
+### What is the expected behavior?
+**What you want to see instead**
+
+
+
+### Environment
+**Which operating system are you using? For example: Debian GNU/Linux 10.1, Windows 10, Ubuntu Xenial, FreeBSD 12.2, etc.**
+**Which installation method did you use? Distribution package (apt, pkg, homebrew), from source tarball, from Git, etc.**
+
+### Relevant logs and/or screenshots
+
+
+/label ~bug
1
0

[tor-browser/tor-browser-78.13.0esr-11.0-2] 40209: Implement Basic Crypto Safety
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit 531722317f1ed71c8ccb891acba949aac6bf3c5d
Author: sanketh <me(a)snkth.com>
Date: Mon Feb 8 20:12:44 2021 -0500
40209: Implement Basic Crypto Safety
Adds a CryptoSafety actor which detects when you've copied a crypto
address from a HTTP webpage and shows a warning.
Closes #40209.
Bug 40428: Fix string attribute names
---
browser/actors/CryptoSafetyChild.jsm | 87 ++++++++++++++++
browser/actors/CryptoSafetyParent.jsm | 142 +++++++++++++++++++++++++++
browser/actors/moz.build | 2 +
browser/base/content/popup-notifications.inc | 14 +++
browser/components/BrowserGlue.jsm | 17 ++++
browser/modules/TorStrings.jsm | 48 +++++++++
browser/themes/shared/browser.inc.css | 5 +
toolkit/content/license.html | 32 ++++++
toolkit/modules/Bech32Decode.jsm | 103 +++++++++++++++++++
toolkit/modules/moz.build | 1 +
10 files changed, 451 insertions(+)
diff --git a/browser/actors/CryptoSafetyChild.jsm b/browser/actors/CryptoSafetyChild.jsm
new file mode 100644
index 000000000000..87ff261d4915
--- /dev/null
+++ b/browser/actors/CryptoSafetyChild.jsm
@@ -0,0 +1,87 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* Copyright (c) 2020, The Tor Project, Inc.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var EXPORTED_SYMBOLS = ["CryptoSafetyChild"];
+
+const { Bech32Decode } = ChromeUtils.import(
+ "resource://gre/modules/Bech32Decode.jsm"
+);
+
+const { XPCOMUtils } = ChromeUtils.import(
+ "resource://gre/modules/XPCOMUtils.jsm"
+);
+
+const kPrefCryptoSafety = "security.cryptoSafety";
+
+XPCOMUtils.defineLazyPreferenceGetter(
+ this,
+ "isCryptoSafetyEnabled",
+ kPrefCryptoSafety,
+ true /* defaults to true */
+);
+
+function looksLikeCryptoAddress(s) {
+ // P2PKH and P2SH addresses
+ // https://stackoverflow.com/a/24205650
+ const bitcoinAddr = /^[13][a-km-zA-HJ-NP-Z1-9]{25,39}$/;
+ if (bitcoinAddr.test(s)) {
+ return true;
+ }
+
+ // Bech32 addresses
+ if (Bech32Decode(s) !== null) {
+ return true;
+ }
+
+ // regular addresses
+ const etherAddr = /^0x[a-fA-F0-9]{40}$/;
+ if (etherAddr.test(s)) {
+ return true;
+ }
+
+ // t-addresses
+ // https://www.reddit.com/r/zec/comments/8mxj6x/simple_regex_to_validate_a_zca…
+ const zcashAddr = /^t1[a-zA-Z0-9]{33}$/;
+ if (zcashAddr.test(s)) {
+ return true;
+ }
+
+ // Standard, Integrated, and 256-bit Integrated addresses
+ // https://monero.stackexchange.com/a/10627
+ const moneroAddr = /^4(?:[0-9AB]|[1-9A-HJ-NP-Za-km-z]{12}(?:[1-9A-HJ-NP-Za-km-z]{30})?)[1-9A-HJ-NP-Za-km-z]{93}$/;
+ if (moneroAddr.test(s)) {
+ return true;
+ }
+
+ return false;
+}
+
+class CryptoSafetyChild extends JSWindowActorChild {
+ handleEvent(event) {
+ if (isCryptoSafetyEnabled) {
+ // Ignore non-HTTP addresses
+ if (!this.document.documentURIObject.schemeIs("http")) {
+ return;
+ }
+ // Ignore onion addresses
+ if (this.document.documentURIObject.host.endsWith(".onion")) {
+ return;
+ }
+
+ if (event.type == "copy" || event.type == "cut") {
+ this.contentWindow.navigator.clipboard.readText().then(clipText => {
+ const selection = clipText.trim();
+ if (looksLikeCryptoAddress(selection)) {
+ this.sendAsyncMessage("CryptoSafety:CopiedText", {
+ selection,
+ });
+ }
+ });
+ }
+ }
+ }
+}
diff --git a/browser/actors/CryptoSafetyParent.jsm b/browser/actors/CryptoSafetyParent.jsm
new file mode 100644
index 000000000000..bac151df5511
--- /dev/null
+++ b/browser/actors/CryptoSafetyParent.jsm
@@ -0,0 +1,142 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* Copyright (c) 2020, The Tor Project, Inc.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var EXPORTED_SYMBOLS = ["CryptoSafetyParent"];
+
+const { XPCOMUtils } = ChromeUtils.import(
+ "resource://gre/modules/XPCOMUtils.jsm"
+);
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+ TorStrings: "resource:///modules/TorStrings.jsm",
+});
+
+const kPrefCryptoSafety = "security.cryptoSafety";
+
+XPCOMUtils.defineLazyPreferenceGetter(
+ this,
+ "isCryptoSafetyEnabled",
+ kPrefCryptoSafety,
+ true /* defaults to true */
+);
+
+class CryptoSafetyParent extends JSWindowActorParent {
+ getBrowser() {
+ return this.browsingContext.top.embedderElement;
+ }
+
+ receiveMessage(aMessage) {
+ if (isCryptoSafetyEnabled) {
+ if (aMessage.name == "CryptoSafety:CopiedText") {
+ showPopup(this.getBrowser(), aMessage.data.selection);
+ }
+ }
+ }
+}
+
+function trimAddress(cryptoAddr) {
+ if (cryptoAddr.length <= 32) {
+ return cryptoAddr;
+ }
+ return cryptoAddr.substring(0, 32) + "...";
+}
+
+function showPopup(aBrowser, cryptoAddr) {
+ const chromeDoc = aBrowser.ownerDocument;
+ if (chromeDoc) {
+ const win = chromeDoc.defaultView;
+ const cryptoSafetyPrompt = new CryptoSafetyPrompt(
+ aBrowser,
+ win,
+ cryptoAddr
+ );
+ cryptoSafetyPrompt.show();
+ }
+}
+
+class CryptoSafetyPrompt {
+ constructor(aBrowser, aWin, cryptoAddr) {
+ this._browser = aBrowser;
+ this._win = aWin;
+ this._cryptoAddr = cryptoAddr;
+ }
+
+ show() {
+ const primaryAction = {
+ label: TorStrings.cryptoSafetyPrompt.primaryAction,
+ accessKey: TorStrings.cryptoSafetyPrompt.primaryActionAccessKey,
+ callback: () => {
+ this._win.torbutton_new_circuit();
+ },
+ };
+
+ const secondaryAction = {
+ label: TorStrings.cryptoSafetyPrompt.secondaryAction,
+ accessKey: TorStrings.cryptoSafetyPrompt.secondaryActionAccessKey,
+ callback: () => {},
+ };
+
+ let _this = this;
+ const options = {
+ popupIconURL: "chrome://browser/skin/cert-error.svg",
+ eventCallback(aTopic) {
+ if (aTopic === "showing") {
+ _this._onPromptShowing();
+ }
+ },
+ };
+
+ const cryptoWarningText = TorStrings.cryptoSafetyPrompt.cryptoWarning.replace(
+ "%S",
+ trimAddress(this._cryptoAddr)
+ );
+
+ if (this._win.PopupNotifications) {
+ this._prompt = this._win.PopupNotifications.show(
+ this._browser,
+ "crypto-safety-warning",
+ cryptoWarningText,
+ null /* anchor ID */,
+ primaryAction,
+ [secondaryAction],
+ options
+ );
+ }
+ }
+
+ _onPromptShowing() {
+ let xulDoc = this._browser.ownerDocument;
+
+ let whatCanHeading = xulDoc.getElementById(
+ "crypto-safety-warning-notification-what-can-heading"
+ );
+ if (whatCanHeading) {
+ whatCanHeading.textContent = TorStrings.cryptoSafetyPrompt.whatCanHeading;
+ }
+
+ let whatCanBody = xulDoc.getElementById(
+ "crypto-safety-warning-notification-what-can-body"
+ );
+ if (whatCanBody) {
+ whatCanBody.textContent = TorStrings.cryptoSafetyPrompt.whatCanBody;
+ }
+
+ let learnMoreElem = xulDoc.getElementById(
+ "crypto-safety-warning-notification-learnmore"
+ );
+ if (learnMoreElem) {
+ learnMoreElem.setAttribute(
+ "value",
+ TorStrings.cryptoSafetyPrompt.learnMore
+ );
+ learnMoreElem.setAttribute(
+ "href",
+ TorStrings.cryptoSafetyPrompt.learnMoreURL
+ );
+ }
+ }
+}
diff --git a/browser/actors/moz.build b/browser/actors/moz.build
index e70f0f09fe3a..9eb5ca397060 100644
--- a/browser/actors/moz.build
+++ b/browser/actors/moz.build
@@ -50,6 +50,8 @@ FINAL_TARGET_FILES.actors += [
'ContentSearchParent.jsm',
'ContextMenuChild.jsm',
'ContextMenuParent.jsm',
+ 'CryptoSafetyChild.jsm',
+ 'CryptoSafetyParent.jsm',
'DOMFullscreenChild.jsm',
'DOMFullscreenParent.jsm',
'FormValidationChild.jsm',
diff --git a/browser/base/content/popup-notifications.inc b/browser/base/content/popup-notifications.inc
index 42e17e90c648..ff6f8cdeca80 100644
--- a/browser/base/content/popup-notifications.inc
+++ b/browser/base/content/popup-notifications.inc
@@ -114,3 +114,17 @@
</vbox>
</popupnotificationfooter>
</popupnotification>
+
+ <popupnotification id="crypto-safety-warning-notification" hidden="true">
+ <popupnotificationcontent orient="vertical">
+ <description id="crypto-safety-warning-notification-desc"/>
+ <html:div id="crypto-safety-warning-notification-what-can">
+ <html:strong id="crypto-safety-warning-notification-what-can-heading" />
+ <html:br/>
+ <html:span id="crypto-safety-warning-notification-what-can-body" />
+ </html:div>
+ <label id="crypto-safety-warning-notification-learnmore"
+ class="popup-notification-learnmore-link"
+ is="text-link"/>
+ </popupnotificationcontent>
+ </popupnotification>
diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm
index 3750230a250b..5f708fca3d5c 100644
--- a/browser/components/BrowserGlue.jsm
+++ b/browser/components/BrowserGlue.jsm
@@ -297,6 +297,23 @@ let JSWINDOWACTORS = {
allFrames: true,
},
+ CryptoSafety: {
+ parent: {
+ moduleURI: "resource:///actors/CryptoSafetyParent.jsm",
+ },
+
+ child: {
+ moduleURI: "resource:///actors/CryptoSafetyChild.jsm",
+ group: "browsers",
+ events: {
+ copy: { mozSystemGroup: true },
+ cut: { mozSystemGroup: true },
+ },
+ },
+
+ allFrames: true,
+ },
+
DOMFullscreen: {
parent: {
moduleURI: "resource:///actors/DOMFullscreenParent.jsm",
diff --git a/browser/modules/TorStrings.jsm b/browser/modules/TorStrings.jsm
index e8a8d37ae373..1e08b168e4af 100644
--- a/browser/modules/TorStrings.jsm
+++ b/browser/modules/TorStrings.jsm
@@ -101,6 +101,54 @@ class TorPropertyStringBundle {
Security Level Strings
*/
var TorStrings = {
+ /*
+ CryptoSafetyPrompt Strings
+ */
+ cryptoSafetyPrompt: (function() {
+ let tsb = new TorPropertyStringBundle(
+ "chrome://torbutton/locale/torbutton.properties",
+ "cryptoSafetyPrompt."
+ );
+ let getString = function(key, fallback) {
+ return tsb.getString(key, fallback);
+ };
+
+ let retval = {
+ cryptoWarning: getString(
+ "cryptoWarning",
+ "A cryptocurrency address (%S) has been copied from an insecure website. It could have been modified."
+ ),
+ whatCanHeading: getString(
+ "whatCanHeading",
+ "What can you do about it?"
+ ),
+ whatCanBody: getString(
+ "whatCanBody",
+ "You can try reconnecting with a new circuit to establish a secure connection, or accept the risk and dismiss this warning."
+ ),
+ learnMore: getString("learnMore", "Learn more"),
+ learnMoreURL: `https://support.torproject.org/${getLocale()}/`,
+ primaryAction: getString(
+ "primaryAction",
+ "Reload Tab with a New Circuit"
+ ),
+ primaryActionAccessKey: getString(
+ "primaryActionAccessKey",
+ "R"
+ ),
+ secondaryAction: getString(
+ "secondaryAction",
+ "Dismiss Warning"
+ ),
+ secondaryActionAccessKey: getString(
+ "secondaryActionAccessKey",
+ "D"
+ ),
+ };
+
+ return retval;
+ })() /* CryptoSafetyPrompt Strings */,
+
/*
Tor Browser Security Level Strings
*/
diff --git a/browser/themes/shared/browser.inc.css b/browser/themes/shared/browser.inc.css
index 0113466e8e56..4ef27d880754 100644
--- a/browser/themes/shared/browser.inc.css
+++ b/browser/themes/shared/browser.inc.css
@@ -620,3 +620,8 @@ menupopup::part(drop-indicator) {
#sharing-warning-proceed-to-tab:hover {
background-color: rgb(0,62,170);
}
+
+#crypto-safety-warning-notification-what-can {
+ display: block;
+ margin: 5px;
+}
diff --git a/toolkit/content/license.html b/toolkit/content/license.html
index e44c31ec6d4e..90995236b41b 100644
--- a/toolkit/content/license.html
+++ b/toolkit/content/license.html
@@ -72,6 +72,7 @@
<li><a href="about:license#arm">ARM License</a></li>
<li><a href="about:license#babel">Babel License</a></li>
<li><a href="about:license#babylon">Babylon License</a></li>
+ <li><a href="about:license#bech32">Bech32 License</a></li>
<li><a href="about:license#bincode">bincode License</a></li>
<li><a href="about:license#bsd2clause">BSD 2-Clause License</a></li>
<li><a href="about:license#bsd3clause">BSD 3-Clause License</a></li>
@@ -2795,6 +2796,37 @@ furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+</pre>
+
+
+ <hr>
+
+ <h1><a id="bech32"></a>Bech32 License</h1>
+
+ <p>This license applies to the file
+ <code>toolkit/modules/Bech32Decode.jsm</code>.
+ </p>
+
+<pre>
+Copyright (c) 2017 Pieter Wuille
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
diff --git a/toolkit/modules/Bech32Decode.jsm b/toolkit/modules/Bech32Decode.jsm
new file mode 100644
index 000000000000..3a2bc7ae0a10
--- /dev/null
+++ b/toolkit/modules/Bech32Decode.jsm
@@ -0,0 +1,103 @@
+// Adapted from the reference implementation of Bech32
+// https://github.com/sipa/bech32
+
+// Copyright (c) 2017 Pieter Wuille
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+"use strict";
+
+/**
+ * JS module implementation of Bech32 decoding adapted from the reference
+ * implementation https://github.com/sipa/bech32.
+ */
+
+var EXPORTED_SYMBOLS = ["Bech32Decode"];
+
+var CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
+var GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
+
+function polymod(values) {
+ var chk = 1;
+ for (var p = 0; p < values.length; ++p) {
+ var top = chk >> 25;
+ chk = ((chk & 0x1ffffff) << 5) ^ values[p];
+ for (var i = 0; i < 5; ++i) {
+ if ((top >> i) & 1) {
+ chk ^= GENERATOR[i];
+ }
+ }
+ }
+ return chk;
+}
+
+function hrpExpand(hrp) {
+ var ret = [];
+ var p;
+ for (p = 0; p < hrp.length; ++p) {
+ ret.push(hrp.charCodeAt(p) >> 5);
+ }
+ ret.push(0);
+ for (p = 0; p < hrp.length; ++p) {
+ ret.push(hrp.charCodeAt(p) & 31);
+ }
+ return ret;
+}
+
+function verifyChecksum(hrp, data) {
+ return polymod(hrpExpand(hrp).concat(data)) === 1;
+}
+
+function Bech32Decode(bechString) {
+ var p;
+ var has_lower = false;
+ var has_upper = false;
+ for (p = 0; p < bechString.length; ++p) {
+ if (bechString.charCodeAt(p) < 33 || bechString.charCodeAt(p) > 126) {
+ return null;
+ }
+ if (bechString.charCodeAt(p) >= 97 && bechString.charCodeAt(p) <= 122) {
+ has_lower = true;
+ }
+ if (bechString.charCodeAt(p) >= 65 && bechString.charCodeAt(p) <= 90) {
+ has_upper = true;
+ }
+ }
+ if (has_lower && has_upper) {
+ return null;
+ }
+ bechString = bechString.toLowerCase();
+ var pos = bechString.lastIndexOf("1");
+ if (pos < 1 || pos + 7 > bechString.length || bechString.length > 90) {
+ return null;
+ }
+ var hrp = bechString.substring(0, pos);
+ var data = [];
+ for (p = pos + 1; p < bechString.length; ++p) {
+ var d = CHARSET.indexOf(bechString.charAt(p));
+ if (d === -1) {
+ return null;
+ }
+ data.push(d);
+ }
+ if (!verifyChecksum(hrp, data)) {
+ return null;
+ }
+ return { hrp: hrp, data: data.slice(0, data.length - 6) };
+}
diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build
index e1f1eb5759c5..698d2773a7ed 100644
--- a/toolkit/modules/moz.build
+++ b/toolkit/modules/moz.build
@@ -160,6 +160,7 @@ EXTRA_JS_MODULES += [
'ActorManagerParent.jsm',
'AppMenuNotifications.jsm',
'AsyncPrefs.jsm',
+ 'Bech32Decode.jsm',
'BinarySearch.jsm',
'BrowserUtils.jsm',
'CanonicalJSON.jsm',
1
0

[tor-browser/tor-browser-78.13.0esr-11.0-2] Bug 27476: Implement about:torconnect captive portal within Tor Browser
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit bec404f02e81ecabf175f7e24672e61a84efb018
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 | 12 +-
browser/base/content/browser-siteIdentity.js | 2 +-
browser/base/content/browser.js | 66 ++-
browser/base/content/browser.xhtml | 3 +
browser/base/content/utilityOverlay.js | 8 +
.../alpha/content/identity-icons-brand.svg | 26 +-
browser/branding/alpha/content/jar.mn | 1 +
browser/branding/alpha/content/tor-styles.css | 13 +
.../nightly/content/identity-icons-brand.svg | 30 +-
browser/branding/nightly/content/jar.mn | 1 +
browser/branding/nightly/content/tor-styles.css | 13 +
.../official/content/identity-icons-brand.svg | 32 +-
browser/branding/official/content/jar.mn | 1 +
browser/branding/official/content/tor-styles.css | 14 +
browser/branding/tor-styles.inc.css | 87 ++++
browser/components/BrowserGlue.jsm | 37 +-
browser/components/about/AboutRedirector.cpp | 4 +
browser/components/about/components.conf | 1 +
browser/components/moz.build | 1 +
.../onionservices/HttpsEverywhereControl.jsm | 17 +-
browser/components/sessionstore/SessionStore.jsm | 4 +
browser/components/torconnect/TorConnectChild.jsm | 9 +
browser/components/torconnect/TorConnectParent.jsm | 150 +++++++
.../torconnect/content/aboutTorConnect.css | 155 +++++++
.../torconnect/content/aboutTorConnect.js | 304 +++++++++++++
.../torconnect/content/aboutTorConnect.xhtml | 45 ++
.../components/torconnect/content/onion-slash.svg | 7 +
browser/components/torconnect/content/onion.svg | 3 +
.../torconnect/content/torBootstrapUrlbar.js | 93 ++++
.../torconnect/content/torconnect-urlbar.css | 57 +++
.../torconnect/content/torconnect-urlbar.inc.xhtml | 10 +
browser/components/torconnect/jar.mn | 7 +
browser/components/torconnect/moz.build | 6 +
.../components/torpreferences/content/torPane.js | 90 ++++
.../torpreferences/content/torPane.xhtml | 34 ++
.../torpreferences/content/torPreferences.css | 123 +++++
browser/components/urlbar/UrlbarInput.jsm | 31 ++
browser/modules/TorConnect.jsm | 499 +++++++++++++++++++++
browser/modules/TorProcessService.jsm | 12 +
browser/modules/TorProtocolService.jsm | 179 +++++++-
browser/modules/TorStrings.jsm | 80 ++++
browser/modules/moz.build | 2 +
.../shared/identity-block/identity-block.inc.css | 16 +-
browser/themes/shared/jar.inc.mn | 1 +
browser/themes/shared/onionPattern.css | 124 +++++
browser/themes/shared/onionPattern.inc.xhtml | 210 +++++++++
browser/themes/shared/urlbar-searchbar.inc.css | 2 +
dom/base/Document.cpp | 51 ++-
dom/base/nsGlobalWindowOuter.cpp | 2 +
.../processsingleton/MainProcessSingleton.jsm | 5 +
toolkit/modules/AsyncPrefs.jsm | 2 +
toolkit/modules/RemotePageAccessManager.jsm | 16 +
toolkit/mozapps/update/UpdateService.jsm | 68 ++-
.../themes/shared/in-content/info-pages.inc.css | 15 +-
.../lib/environments/browser-window.js | 4 +
56 files changed, 2650 insertions(+), 143 deletions(-)
diff --git a/browser/actors/NetErrorParent.jsm b/browser/actors/NetErrorParent.jsm
index 035195391554..6dce9af5aad0 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 { TorConnect } = ChromeUtils.import(
+ "resource:///modules/TorConnect.jsm"
+);
+
const PREF_SSL_IMPACT_ROOTS = [
"security.tls.version.",
"security.ssl3.",
@@ -318,6 +322,10 @@ class NetErrorParent extends JSWindowActorParent {
break;
}
}
+ break;
+ case "ShouldShowTorConnect":
+ return TorConnect.shouldShowTorConnect;
}
+ return undefined;
}
}
diff --git a/browser/base/content/aboutNetError.js b/browser/base/content/aboutNetError.js
index 60db17f46eb9..32bd5576de3e 100644
--- a/browser/base/content/aboutNetError.js
+++ b/browser/base/content/aboutNetError.js
@@ -194,8 +194,18 @@ async function setErrorPageStrings(err) {
document.l10n.setAttributes(titleElement, title);
}
-function initPage() {
+async function initPage() {
var err = getErrorCode();
+
+ // proxyConnectFailure because no-tor running daemon would return this error
+ if (
+ (err === "proxyConnectFailure") &&
+ (await RPMSendQuery("ShouldShowTorConnect"))
+ ) {
+ // pass orginal destination as redirect param
+ const encodedRedirect = encodeURIComponent(document.location.href);
+ document.location.replace(`about:torconnect?redirect=${encodedRedirect}`);
+ }
// 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..37d67f7680af 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",
+ TorConnect: "resource:///modules/TorConnect.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,32 +2494,48 @@ var gBrowserInit = {
let uri = window.arguments[0];
let defaultArgs = BrowserHandler.defaultArgs;
- // If the given URI is different from the homepage, we want to load it.
- if (uri != defaultArgs) {
- AboutNewTab.noteNonDefaultStartup();
+ // figure out which URI to actually load (or a Promise to get the uri)
+ uri = ((uri) => {
+ // If the given URI is different from the homepage, we want to load it.
+ if (uri != defaultArgs) {
+ AboutNewTab.noteNonDefaultStartup();
+
+ if (uri instanceof Ci.nsIArray) {
+ // Transform the nsIArray of nsISupportsString's into a JS Array of
+ // JS strings.
+ return Array.from(
+ uri.enumerate(Ci.nsISupportsString),
+ supportStr => supportStr.data
+ );
+ } else if (uri instanceof Ci.nsISupportsString) {
+ return uri.data;
+ }
+ return uri;
+ }
- if (uri instanceof Ci.nsIArray) {
- // Transform the nsIArray of nsISupportsString's into a JS Array of
- // JS strings.
- return Array.from(
- uri.enumerate(Ci.nsISupportsString),
- supportStr => supportStr.data
- );
- } else if (uri instanceof Ci.nsISupportsString) {
- return uri.data;
+ // The URI appears to be the the homepage. We want to load it only if
+ // session restore isn't about to override the homepage.
+ let willOverride = SessionStartup.willOverrideHomepage;
+ if (typeof willOverride == "boolean") {
+ return willOverride ? null : uri;
}
- return uri;
- }
+ return willOverride.then(willOverrideHomepage =>
+ willOverrideHomepage ? null : uri
+ );
+ })(uri);
+
+ // if using TorConnect, convert these uris to redirects
+ if (TorConnect.shouldShowTorConnect) {
+ return Promise.resolve(uri).then((uri) => {
+ if (uri == null) {
+ uri = [];
+ }
- // The URI appears to be the the homepage. We want to load it only if
- // session restore isn't about to override the homepage.
- let willOverride = SessionStartup.willOverrideHomepage;
- if (typeof willOverride == "boolean") {
- return willOverride ? null : uri;
+ uri = TorConnect.getURIsToLoad(uri);
+ return uri;
+ });
}
- return willOverride.then(willOverrideHomepage =>
- willOverrideHomepage ? null : uri
- );
+ return uri;
})());
},
@@ -2582,6 +2602,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..134ab8e087e1 100644
--- a/browser/base/content/browser.xhtml
+++ b/browser/base/content/browser.xhtml
@@ -10,6 +10,7 @@
override rules using selectors with the same specificity. This applies to
both "content" and "skin" packages, which bug 1385444 will unify later. -->
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="chrome://branding/content/tor-styles.css" type="text/css"?>
<!-- While these stylesheets are defined in Toolkit, they are only used in the
main browser window, so we can load them here. Bug 1474241 is on file to
@@ -112,6 +113,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 +1057,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/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js
index eb13d5a3435c..0b3bdde4b5d4 100644
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -20,6 +20,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
ExtensionSettingsStore: "resource://gre/modules/ExtensionSettingsStore.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
ShellService: "resource:///modules/ShellService.jsm",
+ TorConnect: "resource:///modules/TorConnect.jsm",
});
XPCOMUtils.defineLazyGetter(this, "ReferrerInfo", () =>
@@ -335,6 +336,13 @@ function openUILinkIn(
aPostData,
aReferrerInfo
) {
+
+ // make sure users are not faced with the scary red 'tor isn't working' screen
+ // if they navigate to about:tor before bootstrapped
+ if (url === "about:tor" && TorConnect.shouldShowTorConnect) {
+ url = `about:torconnect?redirect=${encodeURIComponent("about:tor")}`;
+ }
+
var params;
if (arguments.length == 3 && typeof arguments[2] == "object") {
diff --git a/browser/branding/alpha/content/identity-icons-brand.svg b/browser/branding/alpha/content/identity-icons-brand.svg
index 9bfa43842e2d..30cd52ba5c51 100644
--- a/browser/branding/alpha/content/identity-icons-brand.svg
+++ b/browser/branding/alpha/content/identity-icons-brand.svg
@@ -1,25 +1,3 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="512px" height="512px" viewBox="-17 -17 546 546" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <defs>
- <linearGradient x1="50%" y1="3.27248873%" x2="50%" y2="97.1599968%" id="linearGradient-1">
- <stop stop-color="#00FEFF" offset="0%"></stop>
- <stop stop-color="#0BE67D" offset="100%"></stop>
- </linearGradient>
- <path d="M25,25 C152.50841,25 255.874399,127.979815 255.874399,255.011855 C255.874399,382.043895 152.50841,485.02371 25,485.02371 L25,25 Z" id="path-2"></path>
- <filter x="-20.8%" y="-8.7%" width="134.7%" height="117.4%" filterUnits="objectBoundingBox" id="filter-3">
- <feOffset dx="-8" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
- <feGaussianBlur stdDeviation="12" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
- <feColorMatrix values="0 0 0 0 0.0872579578 0 0 0 0 0.00490370801 0 0 0 0 0.234933036 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
- </filter>
- </defs>
- <g id="Alpha" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
- <g>
- <circle id="background" fill-opacity="0.9" fill="#030004" fill-rule="nonzero" cx="256" cy="256" r="246"></circle>
- <path d="M256.525143,465.439707 L256.525143,434.406609 C354.826191,434.122748 434.420802,354.364917 434.420802,255.992903 C434.420802,157.627987 354.826191,77.8701558 256.525143,77.5862948 L256.525143,46.5531962 C371.964296,46.8441537 465.446804,140.489882 465.446804,255.992903 C465.446804,371.503022 371.964296,465.155846 256.525143,465.439707 Z M256.525143,356.820314 C311.970283,356.529356 356.8487,311.516106 356.8487,255.992903 C356.8487,200.476798 311.970283,155.463547 256.525143,155.17259 L256.525143,124.146588 C329.115485,124.430449 387.881799,183.338693 387.881799,255.992903 C387.881799,328.654211 329.115485,387.562455 256.525143,387.846316 L256.525143,356.820314 Z M256.525143,201.718689 C286.266674,202.00255 310.3026,226.180407 310.3026,255.992903 C310.3026,285.812497 286.266674,309.990353 256.525143,310.274214 L256.525143,201.718689 Z M0,255.992903 C0,397.384044 114.60886,512 256,512 C397.384044,512 512,397.384044 512,255.992903 C512,114.60886 397.384044,2.842170
94e-14 256,2.84217094e-14 C114.60886,2.84217094e-14 0,114.60886 0,255.992903 Z" id="center" fill="url(#linearGradient-1)"></path>
- <g id="half" transform="translate(140.437200, 255.011855) scale(-1, 1) translate(-140.437200, -255.011855) ">
- <use fill="black" fill-opacity="1" filter="url(#filter-3)" xlink:href="#path-2"></use>
- <use fill="url(#linearGradient-1)" fill-rule="evenodd" xlink:href="#path-2"></use>
- </g>
- </g>
- </g>
+<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/branding/alpha/content/jar.mn b/browser/branding/alpha/content/jar.mn
index de166fe3636f..5dd066c27f9c 100644
--- a/browser/branding/alpha/content/jar.mn
+++ b/browser/branding/alpha/content/jar.mn
@@ -20,3 +20,4 @@ browser.jar:
content/branding/identity-icons-brand.svg
content/branding/aboutDialog.css
content/branding/horizontal-lockup.svg
+* content/branding/tor-styles.css
diff --git a/browser/branding/alpha/content/tor-styles.css b/browser/branding/alpha/content/tor-styles.css
new file mode 100644
index 000000000000..14c1915ef871
--- /dev/null
+++ b/browser/branding/alpha/content/tor-styles.css
@@ -0,0 +1,13 @@
+%include ../../tor-styles.inc.css
+
+/* default theme*/
+:root,
+/* light theme*/
+:root:-moz-lwtheme-darktext {
+ --tor-branding-color: var(--teal-70);
+}
+
+/* dark theme */
+:root:-moz-lwtheme-brighttext {
+ --tor-branding-color: var(--teal-60);
+}
\ No newline at end of file
diff --git a/browser/branding/nightly/content/identity-icons-brand.svg b/browser/branding/nightly/content/identity-icons-brand.svg
index fc1d9c997aeb..30cd52ba5c51 100644
--- a/browser/branding/nightly/content/identity-icons-brand.svg
+++ b/browser/branding/nightly/content/identity-icons-brand.svg
@@ -1,29 +1,3 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="512px" height="512px" viewBox="-17 -17 546 546" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <defs>
- <linearGradient x1="25.1281738%" y1="5.44281006%" x2="54.3792725%" y2="100%" id="linearGradient-1">
- <stop stop-color="#00E1E8" offset="0%"></stop>
- <stop stop-color="#3500FF" offset="100%"></stop>
- </linearGradient>
- <linearGradient x1="25.1281738%" y1="5.44281006%" x2="54.3792725%" y2="100%" id="linearGradient-2">
- <stop stop-color="#00E1E8" offset="0%"></stop>
- <stop stop-color="#3500FF" offset="100%"></stop>
- </linearGradient>
- <path d="M25,25 C152.50841,25 255.874399,127.979815 255.874399,255.011855 C255.874399,382.043895 152.50841,485.02371 25,485.02371 L25,25 Z" id="path-3"></path>
- <filter x="-20.8%" y="-8.7%" width="134.7%" height="117.4%" filterUnits="objectBoundingBox" id="filter-4">
- <feOffset dx="-8" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
- <feGaussianBlur stdDeviation="12" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
- <feColorMatrix values="0 0 0 0 0.0872579578 0 0 0 0 0.00490370801 0 0 0 0 0.234933036 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
- </filter>
- </defs>
- <g id="Nightly" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
- <g>
- <circle id="background" fill-opacity="0.9" fill="#030004" fill-rule="nonzero" cx="256" cy="256" r="246"></circle>
- <path d="M256.525143,465.439707 L256.525143,434.406609 C354.826191,434.122748 434.420802,354.364917 434.420802,255.992903 C434.420802,157.627987 354.826191,77.8701558 256.525143,77.5862948 L256.525143,46.5531962 C371.964296,46.8441537 465.446804,140.489882 465.446804,255.992903 C465.446804,371.503022 371.964296,465.155846 256.525143,465.439707 Z M256.525143,356.820314 C311.970283,356.529356 356.8487,311.516106 356.8487,255.992903 C356.8487,200.476798 311.970283,155.463547 256.525143,155.17259 L256.525143,124.146588 C329.115485,124.430449 387.881799,183.338693 387.881799,255.992903 C387.881799,328.654211 329.115485,387.562455 256.525143,387.846316 L256.525143,356.820314 Z M256.525143,201.718689 C286.266674,202.00255 310.3026,226.180407 310.3026,255.992903 C310.3026,285.812497 286.266674,309.990353 256.525143,310.274214 L256.525143,201.718689 Z M0,255.992903 C0,397.384044 114.60886,512 256,512 C397.384044,512 512,397.384044 512,255.992903 C512,114.60886 397.384044,2.842170
94e-14 256,2.84217094e-14 C114.60886,2.84217094e-14 0,114.60886 0,255.992903 Z" id="center" fill="url(#linearGradient-1)"></path>
- <g id="half" transform="translate(140.437200, 255.011855) scale(-1, 1) translate(-140.437200, -255.011855) ">
- <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-3"></use>
- <use fill="url(#linearGradient-2)" fill-rule="evenodd" xlink:href="#path-3"></use>
- </g>
- </g>
- </g>
+<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/branding/nightly/content/jar.mn b/browser/branding/nightly/content/jar.mn
index de166fe3636f..5dd066c27f9c 100644
--- a/browser/branding/nightly/content/jar.mn
+++ b/browser/branding/nightly/content/jar.mn
@@ -20,3 +20,4 @@ browser.jar:
content/branding/identity-icons-brand.svg
content/branding/aboutDialog.css
content/branding/horizontal-lockup.svg
+* content/branding/tor-styles.css
diff --git a/browser/branding/nightly/content/tor-styles.css b/browser/branding/nightly/content/tor-styles.css
new file mode 100644
index 000000000000..52e1761e5459
--- /dev/null
+++ b/browser/branding/nightly/content/tor-styles.css
@@ -0,0 +1,13 @@
+%include ../../tor-styles.inc.css
+
+/* default theme*/
+:root,
+/* light theme*/
+:root:-moz-lwtheme-darktext {
+ --tor-branding-color: var(--blue-60);
+}
+
+/* dark theme */
+:root:-moz-lwtheme-brighttext {
+ --tor-branding-color: var(--blue-40);
+}
\ No newline at end of file
diff --git a/browser/branding/official/content/identity-icons-brand.svg b/browser/branding/official/content/identity-icons-brand.svg
index 62472ad1826e..30cd52ba5c51 100644
--- a/browser/branding/official/content/identity-icons-brand.svg
+++ b/browser/branding/official/content/identity-icons-brand.svg
@@ -1,31 +1,3 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg width="512px" height="512px" viewBox="-17 -17 546 546" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
- <defs>
- <linearGradient x1="50%" y1="100%" x2="50%" y2="0%" id="linearGradient-1">
- <stop stop-color="#420C5D" offset="0%"></stop>
- <stop stop-color="#951AD1" offset="100%"></stop>
- </linearGradient>
- <path d="M25,29 C152.577777,29 256,131.974508 256,259 C256,386.025492 152.577777,489 25,489 L25,29 Z" id="path-2"></path>
- <filter x="-18.2%" y="-7.4%" width="129.4%" height="114.8%" filterUnits="objectBoundingBox" id="filter-3">
- <feOffset dx="-8" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
- <feGaussianBlur stdDeviation="10" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
- <feColorMatrix values="0 0 0 0 0.250980392 0 0 0 0 0.250980392 0 0 0 0 0.250980392 0 0 0 0.2 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
- </filter>
- </defs>
- <g id="Assets" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
- <g id="icon_512x512">
- <g id="Group">
- <g id="tb_icon/Stable">
- <g id="Stable">
- <circle id="background" fill="#F2E4FF" fill-rule="nonzero" cx="256" cy="256" r="246"></circle>
- <path d="M256.525143,465.439707 L256.525143,434.406609 C354.826191,434.122748 434.420802,354.364917 434.420802,255.992903 C434.420802,157.627987 354.826191,77.8701558 256.525143,77.5862948 L256.525143,46.5531962 C371.964296,46.8441537 465.446804,140.489882 465.446804,255.992903 C465.446804,371.503022 371.964296,465.155846 256.525143,465.439707 Z M256.525143,356.820314 C311.970283,356.529356 356.8487,311.516106 356.8487,255.992903 C356.8487,200.476798 311.970283,155.463547 256.525143,155.17259 L256.525143,124.146588 C329.115485,124.430449 387.881799,183.338693 387.881799,255.992903 C387.881799,328.654211 329.115485,387.562455 256.525143,387.846316 L256.525143,356.820314 Z M256.525143,201.718689 C286.266674,202.00255 310.3026,226.180407 310.3026,255.992903 C310.3026,285.812497 286.266674,309.990353 256.525143,310.274214 L256.525143,201.718689 Z M0,255.992903 C0,397.384044 114.60886,512 256,512 C397.384044,512 512,397.384044 512,255.992903 C512,114.60886 397.384
044,0 256,0 C114.60886,0 0,114.60886 0,255.992903 Z" id="center" fill="url(#linearGradient-1)"></path>
- <g id="half" transform="translate(140.500000, 259.000000) scale(-1, 1) translate(-140.500000, -259.000000) ">
- <use fill="black" fill-opacity="1" filter="url(#filter-3)" xlink:href="#path-2"></use>
- <use fill="url(#linearGradient-1)" fill-rule="evenodd" xlink:href="#path-2"></use>
- </g>
- </g>
- </g>
- </g>
- </g>
- </g>
+<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/branding/official/content/jar.mn b/browser/branding/official/content/jar.mn
index de166fe3636f..5dd066c27f9c 100644
--- a/browser/branding/official/content/jar.mn
+++ b/browser/branding/official/content/jar.mn
@@ -20,3 +20,4 @@ browser.jar:
content/branding/identity-icons-brand.svg
content/branding/aboutDialog.css
content/branding/horizontal-lockup.svg
+* content/branding/tor-styles.css
diff --git a/browser/branding/official/content/tor-styles.css b/browser/branding/official/content/tor-styles.css
new file mode 100644
index 000000000000..e4ccb5c767a9
--- /dev/null
+++ b/browser/branding/official/content/tor-styles.css
@@ -0,0 +1,14 @@
+%include ../../tor-styles.inc.css
+
+/* default theme*/
+:root,
+/* light theme*/
+:root:-moz-lwtheme-darktext {
+ --tor-branding-color: var(--purple-60);
+}
+
+/* dark theme */
+:root:-moz-lwtheme-brighttext {
+ --tor-branding-color: var(--purple-30);
+}
+
diff --git a/browser/branding/tor-styles.inc.css b/browser/branding/tor-styles.inc.css
new file mode 100644
index 000000000000..55dc9b6238b3
--- /dev/null
+++ b/browser/branding/tor-styles.inc.css
@@ -0,0 +1,87 @@
+:root {
+ /* photon colors, not all of them are available for whatever reason
+ in firefox, so here they are */
+
+ --magenta-50: #ff1ad9;
+ --magenta-60: #ed00b5;
+ --magenta-70: #b5007f;
+ --magenta-80: #7d004f;
+ --magenta-90: #440027;
+
+ --purple-30: #c069ff;
+ --purple-40: #ad3bff;
+ --purple-50: #9400ff;
+ --purple-60: #8000d7;
+ --purple-70: #6200a4;
+ --purple-80: #440071;
+ --purple-90: #25003e;
+
+ --blue-40: #45a1ff;
+ --blue-50: #0a84ff;
+ --blue-50-a30: rgba(10, 132, 255, 0.3);
+ --blue-60: #0060df;
+ --blue-70: #003eaa;
+ --blue-80: #002275;
+ --blue-90: #000f40;
+
+ --teal-50: #00feff;
+ --teal-60: #00c8d7;
+ --teal-70: #008ea4;
+ --teal-80: #005a71;
+ --teal-90: #002d3e;
+
+ --green-50: #30e60b;
+ --green-60: #12bc00;
+ --green-70: #058b00;
+ --green-80: #006504;
+ --green-90: #003706;
+
+ --yellow-50: #ffe900;
+ --yellow-60: #d7b600;
+ --yellow-70: #a47f00;
+ --yellow-80: #715100;
+ --yellow-90: #3e2800;
+
+ --red-50: #ff0039;
+ --red-60: #d70022;
+ --red-70: #a4000f;
+ --red-80: #5a0002;
+ --red-90: #3e0200;
+
+ --orange-50: #ff9400;
+ --orange-60: #d76e00;
+ --orange-70: #a44900;
+ --orange-80: #712b00;
+ --orange-90: #3e1300;
+
+ --grey-10: #f9f9fa;
+ --grey-10-a10: rgba(249, 249, 250, 0.1);
+ --grey-10-a20: rgba(249, 249, 250, 0.2);
+ --grey-10-a40: rgba(249, 249, 250, 0.4);
+ --grey-10-a60: rgba(249, 249, 250, 0.6);
+ --grey-10-a80: rgba(249, 249, 250, 0.8);
+ --grey-20: #ededf0;
+ --grey-30: #d7d7db;
+ --grey-40: #b1b1b3;
+ --grey-50: #737373;
+ --grey-60: #4a4a4f;
+ --grey-70: #38383d;
+ --grey-80: #2a2a2e;
+ --grey-90: #0c0c0d;
+ --grey-90-a05: rgba(12, 12, 13, 0.05);
+ --grey-90-a10: rgba(12, 12, 13, 0.1);
+ --grey-90-a20: rgba(12, 12, 13, 0.2);
+ --grey-90-a30: rgba(12, 12, 13, 0.3);
+ --grey-90-a40: rgba(12, 12, 13, 0.4);
+ --grey-90-a50: rgba(12, 12, 13, 0.5);
+ --grey-90-a60: rgba(12, 12, 13, 0.6);
+ --grey-90-a70: rgba(12, 12, 13, 0.7);
+ --grey-90-a80: rgba(12, 12, 13, 0.8);
+ --grey-90-a90: rgba(12, 12, 13, 0.9);
+
+ --ink-70: #363959;
+ --ink-80: #202340;
+ --ink-90: #0f1126;
+
+ --white-100: #ffffff;
+}
\ No newline at end of file
diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm
index 5f708fca3d5c..aae76c7be6bc 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","about:torconnect?*"],
+ },
+
Translation: {
parent: {
moduleURI: "resource:///modules/translation/TranslationParent.jsm",
@@ -2492,7 +2506,28 @@ BrowserGlue.prototype = {
{
task: () => {
- OnionAliasStore.init();
+ const { TorConnect, TorConnectTopics } = ChromeUtils.import(
+ "resource:///modules/TorConnect.jsm"
+ );
+ if (!TorConnect.shouldShowTorConnect) {
+ // we will take this path when the user is using the legacy tor launcher or
+ // when Tor Browser didn't launch its own tor.
+ OnionAliasStore.init();
+ } else {
+ // this path is taken when using about:torconnect, we wait to init
+ // after we are bootstrapped and connected to tor
+ const topic = TorConnectTopics.BootstrapComplete;
+ let bootstrapObserver = {
+ observe(aSubject, aTopic, aData) {
+ if (aTopic === topic) {
+ OnionAliasStore.init();
+ // we only need to init once, so remove ourselves as an obvserver
+ Services.obs.removeObserver(this, topic);
+ }
+ }
+ };
+ Services.obs.addObserver(bootstrapObserver, topic);
+ }
},
},
diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp
index e7c377d655e7..db5f3ead4bb8 100644
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -120,6 +120,10 @@ static const RedirEntry kRedirMap[] = {
nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT |
nsIAboutModule::HIDE_FROM_ABOUTABOUT},
#endif
+ {"torconnect", "chrome://browser/content/torconnect/aboutTorConnect.xhtml",
+ nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
+ nsIAboutModule::URI_CAN_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT |
+ nsIAboutModule::HIDE_FROM_ABOUTABOUT},
};
static nsAutoCString GetAboutModuleName(nsIURI* aURI) {
diff --git a/browser/components/about/components.conf b/browser/components/about/components.conf
index 8e04467c05da..01c99ad4ed0c 100644
--- a/browser/components/about/components.conf
+++ b/browser/components/about/components.conf
@@ -26,6 +26,7 @@ pages = [
'robots',
'sessionrestore',
'tabcrashed',
+ 'torconnect',
'welcome',
'welcomeback',
]
diff --git a/browser/components/moz.build b/browser/components/moz.build
index b660be047b14..fb90c499c616 100644
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -59,6 +59,7 @@ DIRS += [
'syncedtabs',
'uitour',
'urlbar',
+ 'torconnect',
'torpreferences',
'translation',
]
diff --git a/browser/components/onionservices/HttpsEverywhereControl.jsm b/browser/components/onionservices/HttpsEverywhereControl.jsm
index 525ed5233be7..d673de4cd6e5 100644
--- a/browser/components/onionservices/HttpsEverywhereControl.jsm
+++ b/browser/components/onionservices/HttpsEverywhereControl.jsm
@@ -41,6 +41,7 @@ const SECUREDROP_TOR_ONION_CHANNEL = {
class HttpsEverywhereControl {
constructor() {
this._extensionMessaging = null;
+ this._init();
}
async _sendMessage(type, object) {
@@ -61,7 +62,6 @@ class HttpsEverywhereControl {
* Installs the .tor.onion update channel in https-everywhere
*/
async installTorOnionUpdateChannel(retries = 5) {
- this._init();
// TODO: https-everywhere store is initialized asynchronously, so sending a message
// immediately results in a `store.get is undefined` error.
@@ -143,5 +143,20 @@ class HttpsEverywhereControl {
if (!this._extensionMessaging) {
this._extensionMessaging = new ExtensionMessaging();
}
+
+ // update all of the existing https-everywhere channels
+ setTimeout(async () => {
+ let pinnedChannels = await this._sendMessage("get_pinned_update_channels");
+ for(let channel of pinnedChannels.update_channels) {
+ this._sendMessage("update_update_channel", channel);
+ }
+
+ let storedChannels = await this._sendMessage("get_stored_update_channels");
+ for(let channel of storedChannels.update_channels) {
+ this._sendMessage("update_update_channel", channel);
+ }
+ }, 0);
+
+
}
}
diff --git a/browser/components/sessionstore/SessionStore.jsm b/browser/components/sessionstore/SessionStore.jsm
index 6ab86fd5913e..bf9919041f6b 100644
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -213,6 +213,10 @@ ChromeUtils.defineModuleGetter(
"resource://gre/modules/sessionstore/SessionHistory.jsm"
);
+const { TorProtocolService } = ChromeUtils.import(
+ "resource:///modules/TorProtocolService.jsm"
+);
+
XPCOMUtils.defineLazyServiceGetters(this, {
gScreenManager: ["@mozilla.org/gfx/screenmanager;1", "nsIScreenManager"],
Telemetry: ["@mozilla.org/base/telemetry;1", "nsITelemetry"],
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..792f2af10ea6
--- /dev/null
+++ b/browser/components/torconnect/TorConnectParent.jsm
@@ -0,0 +1,150 @@
+// Copyright (c) 2021, The Tor Project, Inc.
+
+var EXPORTED_SYMBOLS = ["TorConnectParent"];
+
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm");
+const { TorConnect, TorConnectTopics, TorConnectState } = ChromeUtils.import(
+ "resource:///modules/TorConnect.jsm"
+);
+
+const TorLauncherPrefs = Object.freeze({
+ quickstart: "extensions.torlauncher.quickstart",
+});
+
+/*
+This object is basically a marshalling interface between the TorConnect module
+and a particular about:torconnect page
+*/
+
+class TorConnectParent extends JSWindowActorParent {
+ constructor(...args) {
+ super(...args);
+
+ const self = this;
+
+ this.state = {
+ State: TorConnect.state,
+ StateChanged: false,
+ Exit: false,
+ ErrorMessage: TorConnect.errorMessage,
+ ErrorDetails: TorConnect.errorDetails,
+ BootstrapProgress: TorConnect.bootstrapProgress,
+ BootstrapStatus: TorConnect.bootstrapStatus,
+ ShowCopyLog: TorConnect.logHasWarningOrError,
+ QuickStartEnabled: Services.prefs.getBoolPref(TorLauncherPrefs.quickstart, false),
+ };
+
+ // JSWindowActiveParent derived objects cannot observe directly, so create a member
+ // object to do our observing for us
+ //
+ // This object converts the various lifecycle events from the TorConnect module, and
+ // maintains a state object which we pass down to our about:torconnect page, which uses
+ // the state object to update its UI
+ this.torConnectObserver = {
+ observe(aSubject, aTopic, aData) {
+ let obj = aSubject?.wrappedJSObject;
+
+ // update our state struct based on received torconnect topics and forward on
+ // to aboutTorConnect.js
+ self.state.StateChanged = false;
+ switch(aTopic) {
+ case TorConnectTopics.StateChange: {
+ self.state.State = obj.state;
+ self.state.StateChanged = true;
+ // clear any previous error information if we are bootstrapping
+ if (self.state.State === TorConnectState.Bootstrapping) {
+ self.state.ErrorMessage = null;
+ self.state.ErrorDetails = null;
+ }
+ break;
+ }
+ case TorConnectTopics.BootstrapProgress: {
+ self.state.BootstrapProgress = obj.progress;
+ self.state.BootstrapStatus = obj.status;
+ self.state.ShowCopyLog = obj.hasWarnings;
+ break;
+ }
+ case TorConnectTopics.BootstrapComplete: {
+ // tells about:torconnect pages to close or redirect themselves
+ // this flag will only be set if an about:torconnect page
+ // reaches the Bootstrapped state, so if a user
+ // navigates to about:torconnect manually after bootstrap, the page
+ // will not auto-close on them
+ self.state.Exit = true;
+ break;
+ }
+ case TorConnectTopics.BootstrapError: {
+ self.state.ErrorMessage = obj.message;
+ self.state.ErrorDetails = obj.details;
+ self.state.ShowCopyLog = true;
+ break;
+ }
+ case TorConnectTopics.FatalError: {
+ // TODO: handle
+ break;
+ }
+ case "nsPref:changed": {
+ if (aData === TorLauncherPrefs.quickstart) {
+ self.state.QuickStartEnabled = Services.prefs.getBoolPref(TorLauncherPrefs.quickstart);
+ }
+ break;
+ }
+ default: {
+ console.log(`TorConnect: unhandled observe topic '${aTopic}'`);
+ }
+ }
+
+ self.sendAsyncMessage("torconnect:state-change", self.state);
+ },
+ };
+
+ // observe all of the torconnect:.* topics
+ for (const key in TorConnectTopics) {
+ const topic = TorConnectTopics[key];
+ Services.obs.addObserver(this.torConnectObserver, topic);
+ }
+ Services.prefs.addObserver(TorLauncherPrefs.quickstart, this.torConnectObserver);
+ }
+
+ willDestroy() {
+ // stop observing all of our torconnect:.* topics
+ for (const key in TorConnectTopics) {
+ const topic = TorConnectTopics[key];
+ Services.obs.removeObserver(this.torConnectObserver, topic);
+ }
+ Services.prefs.removeObserver(TorLauncherPrefs.quickstart, this.torConnectObserver);
+ }
+
+ receiveMessage(message) {
+ switch (message.name) {
+ case "torconnect:set-quickstart":
+ Services.prefs.setBoolPref(TorLauncherPrefs.quickstart, message.data);
+ break;
+ case "torconnect:open-tor-preferences":
+ TorConnect.openTorPreferences();
+ break;
+ case "torconnect:copy-tor-logs":
+ return TorConnect.copyTorLogs();
+ case "torconnect:cancel-bootstrap":
+ TorConnect.cancelBootstrap();
+ break;
+ case "torconnect:begin-bootstrap":
+ TorConnect.beginBootstrap();
+ break;
+ case "torconnect:get-init-args":
+ // called on AboutTorConnect.init(), pass down all state data it needs to init
+
+ // pretend this is a state transition on init
+ // so we always get fresh UI
+ this.state.StateChanged = true;
+ return {
+ TorStrings: TorStrings,
+ TorConnectState: TorConnectState,
+ Direction: Services.locale.isAppLocaleRTL ? "rtl" : "ltr",
+ State: this.state,
+ };
+ }
+ return undefined;
+ }
+}
diff --git a/browser/components/torconnect/content/aboutTorConnect.css b/browser/components/torconnect/content/aboutTorConnect.css
new file mode 100644
index 000000000000..3bdc6ff22192
--- /dev/null
+++ b/browser/components/torconnect/content/aboutTorConnect.css
@@ -0,0 +1,155 @@
+
+/* Copyright (c) 2021, The Tor Project, Inc. */
+
+@import url("chrome://browser/skin/error-pages.css");
+@import url("chrome://branding/content/tor-styles.css");
+
+:root {
+ --onion-opacity: 1;
+ --onion-color: var(--card-outline-color);
+ --onion-radius: 50px;
+}
+
+/* override firefox's default blue focus coloring */
+:focus {
+ outline: none!important;
+ box-shadow: 0 0 0 3px var(--purple-30) !important;
+ border: 1px var(--purple-80) solid !important;
+}
+
+@media (prefers-color-scheme: dark)
+{
+ :focus {
+ box-shadow: 0 0 0 3px var(--purple-50)!important;
+ }
+}
+
+/* override firefox's default blue border on hover */
+input[type="checkbox"]:not(:disabled):hover {
+ border-color: var(--purple-70);
+}
+
+/* fix checkbox visibility when dark mode enabled */
+input[type="checkbox"]:checked {
+ fill: var(--in-content-page-color);
+}
+
+#connectButton {
+ background-color: var(--purple-60);
+}
+
+#connectButton:hover {
+ background-color: var(--purple-70);
+}
+
+#connectButton:active {
+ background-color: var(--purple-80);
+}
+
+#progressBackground {
+ position:fixed;
+ padding:0;
+ margin:0;
+ top:0;
+ left:0;
+ width: 0%;
+ height: 7px;
+ background-image: linear-gradient(90deg, rgb(20, 218, 221) 0%, rgb(128, 109, 236) 100%);
+ border-radius: 0;
+}
+
+#connectPageContainer {
+ margin-top: 10vh;
+ width: 50%;
+}
+
+#quickstartCheckbox, #quickstartCheckboxLabel {
+ vertical-align: middle;
+}
+
+#copyLogButton {
+ position: relative;
+}
+
+/* mirrors p element spacing */
+#copyLogContainer {
+ margin: 1em 0;
+ height: 1.2em;
+ min-height: 1.2em;
+}
+
+#copyLogLink {
+ position: relative;
+ display: inline-block;
+ color: var(--in-content-link-color);
+}
+
+/* hidden apparently only works if no display is set; who knew? */
+#copyLogLink[hidden="true"] {
+ display: none;
+}
+
+#copyLogLink:hover {
+ cursor:pointer;
+}
+
+/* This div:
+ - is centered over its parent
+ - centers its child
+ - has z-index above parent
+ - ignores mouse events from parent
+*/
+#copyLogTooltip {
+ pointer-events: none;
+ visibility: hidden;
+ display: flex;
+ justify-content: center;
+ white-space: nowrap;
+ width: 0;
+ position: absolute;
+
+ z-index: 1;
+ left: 50%;
+ bottom: calc(100% + 0.25em);
+}
+
+/* tooltip content (any content could go here) */
+#copyLogTooltipText {
+ background-color: var(--green-50);
+ color: var(--green-90);
+ border-radius: 2px;
+ padding: 4px;
+ line-height: 13px;
+ font: 11px sans-serif;
+ font-weight: 400;
+}
+
+/* our speech bubble tail */
+#copyLogTooltipText::after {
+ content: "";
+ position: absolute;
+ top: 100%;
+ left: 50%;
+ margin-left: -4px;
+ border-width: 4px;
+ border-style: solid;
+ border-color: var(--green-50) transparent transparent transparent;
+}
+
+body {
+ padding: 0px !important;
+ justify-content: space-between;
+ background-color: var(--in-content-page-background);
+}
+
+.title {
+ background-image: url("chrome://browser/content/torconnect/onion.svg");
+ -moz-context-properties: fill, fill-opacity;
+ fill-opacity: 1;
+ fill: var(--onion-color);
+}
+
+.title.error {
+ background-image: url("chrome://browser/content/torconnect/onion-slash.svg");
+}
+
diff --git a/browser/components/torconnect/content/aboutTorConnect.js b/browser/components/torconnect/content/aboutTorConnect.js
new file mode 100644
index 000000000000..4eed3cf6a5c3
--- /dev/null
+++ b/browser/components/torconnect/content/aboutTorConnect.js
@@ -0,0 +1,304 @@
+// Copyright (c) 2021, The Tor Project, Inc.
+
+/* eslint-env mozilla/frame-script */
+
+// populated in AboutTorConnect.init()
+let TorStrings = {};
+let TorConnectState = {};
+
+class AboutTorConnect {
+ selectors = Object.freeze({
+ textContainer: {
+ title: "div.title",
+ titleText: "h1.title-text",
+ },
+ progress: {
+ description: "p#connectShortDescText",
+ meter: "div#progressBackground",
+ },
+ copyLog: {
+ link: "span#copyLogLink",
+ tooltip: "div#copyLogTooltip",
+ tooltipText: "span#copyLogTooltipText",
+ },
+ quickstart: {
+ checkbox: "input#quickstartCheckbox",
+ label: "label#quickstartCheckboxLabel",
+ },
+ buttons: {
+ connect: "button#connectButton",
+ cancel: "button#cancelButton",
+ advanced: "button#advancedButton",
+ },
+ })
+
+ elements = Object.freeze({
+ title: document.querySelector(this.selectors.textContainer.title),
+ titleText: document.querySelector(this.selectors.textContainer.titleText),
+ progressDescription: document.querySelector(this.selectors.progress.description),
+ progressMeter: document.querySelector(this.selectors.progress.meter),
+ copyLogLink: document.querySelector(this.selectors.copyLog.link),
+ copyLogTooltip: document.querySelector(this.selectors.copyLog.tooltip),
+ copyLogTooltipText: document.querySelector(this.selectors.copyLog.tooltipText),
+ quickstartCheckbox: document.querySelector(this.selectors.quickstart.checkbox),
+ quickstartLabel: document.querySelector(this.selectors.quickstart.label),
+ connectButton: document.querySelector(this.selectors.buttons.connect),
+ cancelButton: document.querySelector(this.selectors.buttons.cancel),
+ advancedButton: document.querySelector(this.selectors.buttons.advanced),
+ })
+
+ // a redirect url can be passed as a query parameter for the page to
+ // forward us to once bootstrap completes (otherwise the window will just close)
+ redirect = null
+
+ beginBootstrap() {
+ this.hide(this.elements.connectButton);
+ this.show(this.elements.cancelButton);
+ this.elements.cancelButton.focus();
+ RPMSendAsyncMessage("torconnect:begin-bootstrap");
+ }
+
+ cancelBootstrap() {
+ RPMSendAsyncMessage("torconnect:cancel-bootstrap");
+ }
+
+ /*
+ Element helper methods
+ */
+
+ show(element) {
+ element.removeAttribute("hidden");
+ }
+
+ hide(element) {
+ element.setAttribute("hidden", "true");
+ }
+
+ setTitle(title, error) {
+ this.elements.titleText.textContent = title;
+ document.title = title;
+
+ if (error) {
+ this.elements.title.classList.add("error");
+ } else {
+ this.elements.title.classList.remove("error");
+ }
+ }
+
+ setProgress(description, visible, percent) {
+ this.elements.progressDescription.textContent = description;
+ if (visible) {
+ this.show(this.elements.progressMeter);
+ this.elements.progressMeter.style.width = `${percent}%`;
+ } else {
+ this.hide(this.elements.progressMeter);
+ }
+ }
+
+ /*
+ These methods update the UI based on the current TorConnect state
+ */
+
+ updateUI(state) {
+ console.log(state);
+
+ // calls update_$state()
+ this[`update_${state.State}`](state);
+ this.elements.quickstartCheckbox.checked = state.QuickStartEnabled;
+ }
+
+ /* Per-state updates */
+
+ update_Initial(state) {
+ const hasError = false;
+ const showProgressbar = false;
+
+ this.setTitle(TorStrings.torConnect.torConnect, hasError);
+ this.setProgress(TorStrings.settings.torPreferencesDescription, showProgressbar);
+ this.hide(this.elements.copyLogLink);
+ this.hide(this.elements.connectButton);
+ this.hide(this.elements.advancedButton);
+ this.hide(this.elements.cancelButton);
+ }
+
+ update_Configuring(state) {
+ const hasError = state.ErrorMessage != null;
+ const showProgressbar = false;
+
+ if (hasError) {
+ this.setTitle(state.ErrorMessage, hasError);
+ this.setProgress(state.ErrorDetails, showProgressbar);
+ this.show(this.elements.copyLogLink);
+ this.elements.connectButton.textContent = TorStrings.torConnect.tryAgain;
+ } else {
+ this.setTitle(TorStrings.torConnect.torConnect, hasError);
+ this.setProgress(TorStrings.settings.torPreferencesDescription, showProgressbar);
+ this.hide(this.elements.copyLogLink);
+ this.elements.connectButton.textContent = TorStrings.torConnect.torConnectButton;
+ }
+ this.show(this.elements.connectButton);
+ if (state.StateChanged) {
+ this.elements.connectButton.focus();
+ }
+ this.show(this.elements.advancedButton);
+ this.hide(this.elements.cancelButton);
+ }
+
+ update_AutoConfiguring(state) {
+ // TODO: noop until this state is used
+ }
+
+ update_Bootstrapping(state) {
+ const hasError = false;
+ const showProgressbar = true;
+
+ this.setTitle(state.BootstrapStatus ? state.BootstrapStatus : TorStrings.torConnect.torConnecting, hasError);
+ this.setProgress(TorStrings.settings.torPreferencesDescription, showProgressbar, state.BootstrapProgress);
+ if (state.ShowCopyLog) {
+ this.show(this.elements.copyLogLink);
+ } else {
+ this.hide(this.elements.copyLogLink);
+ }
+ this.hide(this.elements.connectButton);
+ this.hide(this.elements.advancedButton);
+ this.show(this.elements.cancelButton);
+ if (state.StateChanged) {
+ this.elements.cancelButton.focus();
+ }
+ }
+
+ update_Error(state) {
+ const hasError = true;
+ const showProgressbar = false;
+
+ this.setTitle(state.ErrorMessage, hasError);
+ this.setProgress(state.ErrorDetails, showProgressbar);
+ this.show(this.elements.copyLogLink);
+ this.elements.connectButton.textContent = TorStrings.torConnect.tryAgain;
+ this.show(this.elements.connectButton);
+ this.show(this.elements.advancedButton);
+ this.hide(this.elements.cancelButton);
+ }
+
+ update_FatalError(state) {
+ // TODO: noop until this state is used
+ }
+
+ update_Bootstrapped(state) {
+ const hasError = false;
+ const showProgressbar = true;
+
+ this.setTitle(TorStrings.torConnect.torConnected, hasError);
+ this.setProgress(TorStrings.settings.torPreferencesDescription, showProgressbar, 100);
+ this.hide(this.elements.connectButton);
+ this.hide(this.elements.advancedButton);
+ this.hide(this.elements.cancelButton);
+
+ // only exit about:torconnect if TorConnectParent directs us to
+ if (state.Exit) {
+ if (this.redirect) {
+ // first try to forward to final destination
+ document.location = this.redirect;
+ } else {
+ // or else close the window
+ window.close();
+ }
+ }
+ }
+
+ update_Disabled(state) {
+ // TODO: we should probably have some UX here if a user goes to about:torconnect when
+ // it isn't in use (eg using tor-launcher or system tor)
+ }
+
+ async initElements(direction) {
+
+ document.documentElement.setAttribute("dir", direction);
+
+ // sets the text content while keeping the child elements intact
+ this.elements.copyLogLink.childNodes[0].nodeValue =
+ TorStrings.torConnect.copyLog;
+ this.elements.copyLogLink.addEventListener("click", async (event) => {
+ const copiedMessage = await RPMSendQuery("torconnect:copy-tor-logs");
+ this.elements.copyLogTooltipText.textContent = copiedMessage;
+ this.elements.copyLogTooltipText.style.visibility = "visible";
+
+ // clear previous timeout if one already exists
+ if (this.copyLogTimeoutId) {
+ clearTimeout(this.copyLogTimeoutId);
+ }
+
+ // hide tooltip after X ms
+ const TOOLTIP_TIMEOUT = 2000;
+ this.copyLogTimeoutId = setTimeout(() => {
+ this.elements.copyLogTooltipText.style.visibility = "hidden";
+ this.copyLogTimeoutId = 0;
+ }, TOOLTIP_TIMEOUT);
+ });
+
+ this.elements.quickstartCheckbox.addEventListener("change", () => {
+ const quickstart = this.elements.quickstartCheckbox.checked;
+ RPMSendAsyncMessage("torconnect:set-quickstart", quickstart);
+ });
+ this.elements.quickstartLabel.textContent = TorStrings.settings.quickstartCheckbox;
+
+ this.elements.connectButton.textContent =
+ TorStrings.torConnect.torConnectButton;
+ this.elements.connectButton.addEventListener("click", () => {
+ this.beginBootstrap();
+ });
+
+ this.elements.advancedButton.textContent = TorStrings.torConnect.torConfigure;
+ this.elements.advancedButton.addEventListener("click", () => {
+ RPMSendAsyncMessage("torconnect:open-tor-preferences");
+ });
+
+ this.elements.cancelButton.textContent = TorStrings.torConnect.cancel;
+ this.elements.cancelButton.addEventListener("click", () => {
+ this.cancelBootstrap();
+ });
+ }
+
+ initObservers() {
+ // TorConnectParent feeds us state blobs to we use to update our UI
+ RPMAddMessageListener("torconnect:state-change", ({ data }) => {
+ this.updateUI(data);
+ });
+ }
+
+ initKeyboardShortcuts() {
+ document.onkeydown = (evt) => {
+ // unfortunately it looks like we still haven't standardized keycodes to
+ // integers, so we must resort to a string compare here :(
+ // see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code for relevant documentation
+ if (evt.code === "Escape") {
+ this.cancelBootstrap();
+ }
+ };
+ }
+
+ async init() {
+ // see if a user has a final destination after bootstrapping
+ let params = new URLSearchParams(new URL(document.location.href).search);
+ if (params.has("redirect")) {
+ const encodedRedirect = params.get("redirect");
+ this.redirect = decodeURIComponent(encodedRedirect);
+ }
+
+ let args = await RPMSendQuery("torconnect:get-init-args");
+
+ // various constants
+ TorStrings = Object.freeze(args.TorStrings);
+ TorConnectState = Object.freeze(args.TorConnectState);
+
+ this.initElements(args.Direction);
+ this.initObservers();
+ this.initKeyboardShortcuts();
+
+ // populate UI based on current state
+ this.updateUI(args.State);
+ }
+}
+
+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..595bbdf9a70a
--- /dev/null
+++ b/browser/components/torconnect/content/aboutTorConnect.xhtml
@@ -0,0 +1,45 @@
+<!-- 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="copyLogContainer">
+ <span id="copyLogLink" hidden="true">
+ <div id="copyLogTooltip">
+ <span id="copyLogTooltipText"/>
+ </div>
+ </span>
+ </div>
+
+ <div id="quickstartContainer">
+ <input id="quickstartCheckbox" type="checkbox" />
+ <label id="quickstartCheckboxLabel" for="quickstartCheckbox"/>
+ </div>
+
+ <div id="connectButtonContainer" class="button-container">
+ <button id="advancedButton" hidden="true"></button>
+ <button id="cancelButton" hidden="true"></button>
+ <button id="connectButton" class="primary try-again" hidden="true"></button>
+ </div>
+ </div>
+ </div>
+#include ../../../themes/shared/onionPattern.inc.xhtml
+ </body>
+ <script src="chrome://browser/content/torconnect/aboutTorConnect.js"/>
+</html>
diff --git a/browser/components/torconnect/content/onion-slash.svg b/browser/components/torconnect/content/onion-slash.svg
new file mode 100644
index 000000000000..efb09700ec0b
--- /dev/null
+++ b/browser/components/torconnect/content/onion-slash.svg
@@ -0,0 +1,7 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+ <g fill-opacity="context-fill-opacity" fill="context-fill">
+ <path d="M3.409559 13.112147C3.409559 13.112147 8.200807 8.103115 8.200807 8.103115C8.200807 8.103115 8.200807 6.516403 8.200807 6.516403C8.620819 6.516403 9.009719 6.703075 9.274171 6.998639C9.274171 6.998639 10.160863 6.080835 10.160863 6.080835C9.663071 5.567487 8.978607 5.256367 8.200807 5.256367C8.200807 5.256367 8.200807 4.400787 8.200807 4.400787C9.196391 4.400787 10.098639 4.805243 10.736435 5.458595C10.736435 5.458595 11.623127 4.540791 11.623127 4.540791C10.751991 3.669655 9.538623 3.125195 8.200807 3.125195C8.200807 3.125195 8.200807 2.269615 8.200807 2.269615C9.756407 2.269615 11.172003 2.907411 12.214255 3.918551C12.214255 3.918551 13.100947 3.000747 13.100947 3.000747C11.825355 1.756267 10.098639 0.994023 8.185251 0.994023C4.311807 0.994023 1.185051 4.120779 1.185051 7.994223C1.185051 10.016503 2.040631 11.836555 3.409559 13.112147C3.409559 13.112147 3.409559 13.112147 3.409559 13.112147"/>
+ <path d="M14.205423 4.416343C14.205423 4.416343 13.287619 5.380815 13.287619 5.380815C13.692075 6.158615 13.909859 7.045307 13.909859 7.994223C13.909859 11.152091 11.358675 13.718831 8.200807 13.718831C8.200807 13.718831 8.200807 12.863251 8.200807 12.863251C10.891995 12.863251 13.069835 10.669855 13.069835 7.978667C13.069835 7.278647 12.929831 6.625295 12.665379 6.018611C12.665379 6.018611 11.685351 7.045307 11.685351 7.045307C11.763131 7.340871 11.809799 7.651991 11.809799 7.963111C11.809799 9.954279 10.207531 11.556547 8.216363 11.572103C8.216363 11.572103 8.216363 10.716523 8.216363 10.716523C9.725295 10.700967 10.954219 9.472043 10.954219 7.963111C10.954219 7.916443 10.954219 7.854219 10.954219 7.807551C10.954219 7.807551 4.887379 14.169955 4.887379 14.169955C5.867407 14.698859 6.987439 14.994423 8.185251 14.994423C12.058695 14.994423 15.185451 11.867667 15.185451 7.994223C15.185451 6.687519 14.827663 5.474151 14.205423 4.416343C14.205423 4.416343 14.205423 4.416343 14.20542
3 4.416343"/>
+ <path d="M1.791735 15.461103C1.402835 15.461103 1.045047 15.212207 0.889487 14.838863C0.733927 14.465519 0.827267 14.014395 1.107271 13.734387C1.107271 13.734387 13.458735 0.822907 13.458735 0.822907C13.847635 0.434007 14.454319 0.449563 14.827663 0.838467C15.201007 1.227367 15.216563 1.865163 14.843223 2.269619C14.843223 2.269619 2.491759 15.181099 2.491759 15.181099C2.289531 15.352215 2.040635 15.461107 1.791739 15.461107C1.791739 15.461107 1.791735 15.461103 1.791735 15.461103"/>
+ </g>
+</svg>
diff --git a/browser/components/torconnect/content/onion.svg b/browser/components/torconnect/content/onion.svg
new file mode 100644
index 000000000000..30cd52ba5c51
--- /dev/null
+++ b/browser/components/torconnect/content/onion.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <path fill="context-fill" fill-opacity="context-fill-opacity" d="M12.0246161,21.8174863 L12.0246161,20.3628098 C16.6324777,20.3495038 20.3634751,16.6108555 20.3634751,11.9996673 C20.3634751,7.38881189 16.6324777,3.65016355 12.0246161,3.63685757 L12.0246161,2.18218107 C17.4358264,2.1958197 21.8178189,6.58546322 21.8178189,11.9996673 C21.8178189,17.4142042 17.4358264,21.8041803 12.0246161,21.8174863 L12.0246161,21.8174863 Z M12.0246161,16.7259522 C14.623607,16.7123136 16.7272828,14.6023175 16.7272828,11.9996673 C16.7272828,9.39734991 14.623607,7.28735377 12.0246161,7.27371516 L12.0246161,5.81937131 C15.4272884,5.8326773 18.1819593,8.59400123 18.1819593,11.9996673 C18.1819593,15.4056661 15.4272884,18.1669901 12.0246161,18.1802961 L12.0246161,16.7259522 Z M12.0246161,9.45556355 C13.4187503,9.46886953 14.5454344,10.6022066 14.5454344,11.9996673 C14.5454344,13.3974608 13.4187503,14.5307978 12.0246161,14.5441038 L12.0246161,9.45556355 Z M0,11.9996673 C0,18.6273771 5.37229031,24 12,24 C18
.6273771,24 24,18.6273771 24,11.9996673 C24,5.37229031 18.6273771,0 12,0 C5.37229031,0 0,5.37229031 0,11.9996673 Z"/>
+</svg>
\ No newline at end of file
diff --git a/browser/components/torconnect/content/torBootstrapUrlbar.js b/browser/components/torconnect/content/torBootstrapUrlbar.js
new file mode 100644
index 000000000000..7843b80be8b9
--- /dev/null
+++ b/browser/components/torconnect/content/torBootstrapUrlbar.js
@@ -0,0 +1,93 @@
+// Copyright (c) 2021, The Tor Project, Inc.
+
+"use strict";
+
+const { TorConnect, TorConnectTopics, TorConnectState } = ChromeUtils.import(
+ "resource:///modules/TorConnect.jsm"
+);
+const { TorStrings } = ChromeUtils.import(
+ "resource:///modules/TorStrings.jsm"
+);
+
+var TorBootstrapUrlbar = {
+ selectors: Object.freeze({
+ torConnect: {
+ box: "hbox#torconnect-box",
+ label: "label#torconnect-label",
+ },
+ }),
+
+ elements: null,
+
+ updateTorConnectBox: function(state) {
+ switch(state)
+ {
+ case TorConnectState.Initial:
+ case TorConnectState.Configuring:
+ case TorConnectState.AutoConfiguring:
+ case TorConnectState.Error:
+ case TorConnectState.FatalError: {
+ this.elements.torConnectBox.removeAttribute("hidden");
+ this.elements.torConnectLabel.textContent =
+ TorStrings.torConnect.torNotConnectedConcise;
+ this.elements.inputContainer.setAttribute("torconnect", "offline");
+ break;
+ }
+ case TorConnectState.Bootstrapping: {
+ this.elements.torConnectBox.removeAttribute("hidden");
+ this.elements.torConnectLabel.textContent =
+ TorStrings.torConnect.torConnectingConcise;
+ this.elements.inputContainer.setAttribute("torconnect", "connecting");
+ break;
+ }
+ case TorConnectState.Bootstrapped: {
+ this.elements.torConnectBox.removeAttribute("hidden");
+ this.elements.torConnectLabel.textContent =
+ TorStrings.torConnect.torConnectedConcise;
+ this.elements.inputContainer.setAttribute("torconnect", "connected");
+ // hide torconnect box after 5 seconds
+ setTimeout(() => {
+ this.elements.torConnectBox.setAttribute("hidden", "true");
+ }, 5000);
+ break;
+ }
+ case TorConnectState.Disabled: {
+ this.elements.torConnectBox.setAttribute("hidden", "true");
+ break;
+ }
+ default:
+ break;
+ }
+ },
+
+ observe: function(aSubject, aTopic, aData) {
+ if (aTopic === TorConnectTopics.StateChange) {
+ const obj = aSubject?.wrappedJSObject;
+ this.updateTorConnectBox(obj?.state);
+ }
+ },
+
+ init: function() {
+ if (TorConnect.shouldShowTorConnect) {
+ // browser isn't populated until init
+ this.elements = Object.freeze({
+ torConnectBox: browser.ownerGlobal.document.querySelector(this.selectors.torConnect.box),
+ torConnectLabel: browser.ownerGlobal.document.querySelector(this.selectors.torConnect.label),
+ inputContainer: gURLBar._inputContainer,
+ })
+ this.elements.torConnectBox.addEventListener("click", () => {
+ window.openTrustedLinkIn("about:torconnect", "tab");
+ });
+ Services.obs.addObserver(this, TorConnectTopics.StateChange);
+ this.observing = true;
+ this.updateTorConnectBox(TorConnect.state);
+ }
+ },
+
+ uninit: function() {
+ if (this.observing) {
+ Services.obs.removeObserver(this, TorConnectTopics.StateChange);
+ }
+ },
+};
+
diff --git a/browser/components/torconnect/content/torconnect-urlbar.css b/browser/components/torconnect/content/torconnect-urlbar.css
new file mode 100644
index 000000000000..5aabcffedbd0
--- /dev/null
+++ b/browser/components/torconnect/content/torconnect-urlbar.css
@@ -0,0 +1,57 @@
+/*
+ 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;
+}
+
+label#torconnect-label {
+ line-height: 28px;
+ margin: 0;
+ opacity: 0.6;
+ padding: 0 0.5em;
+}
+
+/* set appropriate sizes for the non-standard ui densities */
+:root[uidensity=compact] hbox.urlbar-page-action#torconnect-box {
+ height: 24px;
+}
+:root[uidensity=compact] label#torconnect-label {
+ line-height: 24px;
+}
+
+
+:root[uidensity=touch] hbox.urlbar-page-action#torconnect-box {
+ height: 30px;
+}
+:root[uidensity=touch] label#torconnect-label {
+ line-height: 30px;
+}
+
+
+/* hide when hidden attribute is set */
+hbox.urlbar-page-action#torconnect-box[hidden="true"],
+/* hide when user is typing in URL bar */
+#urlbar[usertyping] > #urlbar-input-container > #page-action-buttons > #torconnect-box {
+ display: none!important;
+}
+
+/* hide urlbar's placeholder text when not connectd to tor */
+hbox#urlbar-input-container[torconnect="offline"] input#urlbar-input::placeholder,
+hbox#urlbar-input-container[torconnect="connecting"] input#urlbar-input::placeholder {
+ opacity: 0;
+}
+
+/* hide search suggestions when not connected to tor */
+hbox#urlbar-input-container[torconnect="offline"] + vbox.urlbarView,
+hbox#urlbar-input-container[torconnect="connecting"] + vbox.urlbarView {
+ display: none!important;
+}
+
+/* hide search icon when we are not connected to tor */
+hbox#urlbar-input-container[torconnect="offline"] > #identity-box[pageproxystate="invalid"] > #identity-icon,
+hbox#urlbar-input-container[torconnect="connecting"] > #identity-box[pageproxystate="invalid"] > #identity-icon
+{
+ display: none!important;
+}
diff --git a/browser/components/torconnect/content/torconnect-urlbar.inc.xhtml b/browser/components/torconnect/content/torconnect-urlbar.inc.xhtml
new file mode 100644
index 000000000000..60e985a72691
--- /dev/null
+++ b/browser/components/torconnect/content/torconnect-urlbar.inc.xhtml
@@ -0,0 +1,10 @@
+# Copyright (c) 2021, The Tor Project, Inc.
+
+<hbox id="torconnect-box"
+ class="urlbar-icon-wrapper urlbar-page-action"
+ role="status"
+ hidden="true">
+ <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..59ecdec6d1d9 100644
--- a/browser/components/torpreferences/content/torPane.js
+++ b/browser/components/torpreferences/content/torPane.js
@@ -1,9 +1,15 @@
"use strict";
+/* global Services */
+
const { TorProtocolService } = ChromeUtils.import(
"resource:///modules/TorProtocolService.jsm"
);
+const { TorConnect } = ChromeUtils.import(
+ "resource:///modules/TorConnect.jsm"
+);
+
const {
TorBridgeSource,
TorBridgeSettings,
@@ -51,6 +57,10 @@ const { parsePort, parseBridgeStrings, parsePortList } = ChromeUtils.import(
"chrome://browser/content/torpreferences/parseFunctions.jsm"
);
+const TorLauncherPrefs = {
+ quickstart: "extensions.torlauncher.quickstart",
+}
+
/*
Tor Pane
@@ -62,11 +72,21 @@ const gTorPane = (function() {
category: {
title: "label#torPreferences-labelCategory",
},
+ messageBox: {
+ box: "div#torPreferences-connectMessageBox",
+ message: "td#torPreferences-connectMessageBox-message",
+ button: "button#torPreferences-connectMessageBox-button",
+ },
torPreferences: {
header: "h1#torPreferences-header",
description: "span#torPreferences-description",
learnMore: "label#torPreferences-learnMore",
},
+ quickstart: {
+ header: "h2#torPreferences-quickstart-header",
+ description: "span#torPreferences-quickstart-description",
+ enableQuickstartCheckbox: "checkbox#torPreferences-quickstart-toggle",
+ },
bridges: {
header: "h2#torPreferences-bridges-header",
description: "span#torPreferences-bridges-description",
@@ -112,6 +132,10 @@ const gTorPane = (function() {
let retval = {
// cached frequently accessed DOM elements
+ _messageBox: null,
+ _messageBoxMessage: null,
+ _messageBoxButton: null,
+ _enableQuickstartCheckbox: null,
_useBridgeCheckbox: null,
_bridgeSelectionRadiogroup: null,
_builtinBridgeOption: null,
@@ -161,6 +185,43 @@ const gTorPane = (function() {
let prefpane = document.getElementById("mainPrefPane");
+ // 'Connect to Tor' Message Bar
+
+ this._messageBox = prefpane.querySelector(selectors.messageBox.box);
+ this._messageBoxMessage = prefpane.querySelector(selectors.messageBox.message);
+ this._messageBoxButton = prefpane.querySelector(selectors.messageBox.button);
+ // wire up connect button
+ this._messageBoxButton.addEventListener("click", () => {
+ TorConnect.beginBootstrap();
+ let win = Services.wm.getMostRecentWindow("navigator:browser");
+ // switch to existing about:torconnect tab or create a new one
+ win.switchToTabHavingURI("about:torconnect", true);
+ });
+
+ let populateMessagebox = () => {
+ if (TorConnect.shouldShowTorConnect) {
+ // set messagebox style and text
+ if (TorProtocolService.torBootstrapErrorOccurred()) {
+ this._messageBox.className = "error";
+ this._messageBoxMessage.innerText = TorStrings.torConnect.tryAgainMessage;
+ this._messageBoxButton.innerText = TorStrings.torConnect.tryAgain;
+ } else {
+ this._messageBox.className = "warning";
+ this._messageBoxMessage.innerText = TorStrings.torConnect.connectMessage;
+ this._messageBoxButton.innerText = TorStrings.torConnect.torConnectButton;
+ }
+ } else {
+ this._messageBox.className = "hidden";
+ this._messageBoxMessage.innerText = "";
+ this._messageBoxButton.innerText = "";
+ }
+ }
+ populateMessagebox();
+ // update the messagebox whenever we come back to the page
+ window.addEventListener("focus", val => {
+ populateMessagebox();
+ });
+
// Heading
prefpane.querySelector(selectors.torPreferences.header).innerText =
TorStrings.settings.torPreferencesHeading;
@@ -177,6 +238,26 @@ const gTorPane = (function() {
);
}
+ // Quickstart
+ prefpane.querySelector(selectors.quickstart.header).innerText =
+ TorStrings.settings.quickstartHeading;
+ prefpane.querySelector(selectors.quickstart.description).textContent =
+ TorStrings.settings.quickstartDescription;
+
+ this._enableQuickstartCheckbox = prefpane.querySelector(
+ selectors.quickstart.enableQuickstartCheckbox
+ );
+ this._enableQuickstartCheckbox.setAttribute(
+ "label",
+ TorStrings.settings.quickstartCheckbox
+ );
+ this._enableQuickstartCheckbox.addEventListener("command", e => {
+ const checked = this._enableQuickstartCheckbox.checked;
+ Services.prefs.setBoolPref(TorLauncherPrefs.quickstart, checked);
+ });
+ this._enableQuickstartCheckbox.checked = Services.prefs.getBoolPref(TorLauncherPrefs.quickstart);
+ Services.prefs.addObserver(TorLauncherPrefs.quickstart, this);
+
// Bridge setup
prefpane.querySelector(selectors.bridges.header).innerText =
TorStrings.settings.bridgesHeading;
@@ -537,6 +618,15 @@ const gTorPane = (function() {
// Callbacks
//
+ // callback for when the quickstart pref changes
+ observe(subject, topic, data) {
+ if (topic != "nsPref:changed") return;
+ if (data === TorLauncherPrefs.quickstart) {
+ this._enableQuickstartCheckbox.checked =
+ Services.prefs.getBoolPref(TorLauncherPrefs.quickstart);
+ }
+ },
+
// callback when using bridges toggled
onToggleBridge(enabled) {
this._useBridgeCheckbox.checked = enabled;
diff --git a/browser/components/torpreferences/content/torPane.xhtml b/browser/components/torpreferences/content/torPane.xhtml
index 3c966b2b3726..7c8071f2cf10 100644
--- a/browser/components/torpreferences/content/torPane.xhtml
+++ b/browser/components/torpreferences/content/torPane.xhtml
@@ -3,6 +3,29 @@
<script type="application/javascript"
src="chrome://browser/content/torpreferences/torPane.js"/>
<html:template id="template-paneTor">
+
+<!-- Tor Connect Message Box -->
+<groupbox data-category="paneTor" hidden="true">
+ <html:div id="torPreferences-connectMessageBox"
+ class="subcategory"
+ data-category="paneTor"
+ hidden="true">
+ <html:table >
+ <html:tr>
+ <html:td>
+ <html:div id="torPreferences-connectMessageBox-icon"/>
+ </html:td>
+ <html:td id="torPreferences-connectMessageBox-message">
+ </html:td>
+ <html:td>
+ <html:button id="torPreferences-connectMessageBox-button">
+ </html:button>
+ </html:td>
+ </html:tr>
+ </html:table>
+ </html:div>
+</groupbox>
+
<hbox id="torPreferencesCategory"
class="subcategory"
data-category="paneTor"
@@ -18,6 +41,17 @@
</description>
</groupbox>
+<!-- Quickstart -->
+<groupbox id="torPreferences-quickstart-group"
+ data-category="paneTor"
+ hidden="true">
+ <html:h2 id="torPreferences-quickstart-header"/>
+ <description flex="1">
+ <html:span id="torPreferences-quickstart-description"/>
+ </description>
+ <checkbox id="torPreferences-quickstart-toggle"/>
+</groupbox>
+
<!-- Bridges -->
<groupbox id="torPreferences-bridges-group"
data-category="paneTor"
diff --git a/browser/components/torpreferences/content/torPreferences.css b/browser/components/torpreferences/content/torPreferences.css
index 4dac2c457823..47b8ff18e0af 100644
--- a/browser/components/torpreferences/content/torPreferences.css
+++ b/browser/components/torpreferences/content/torPreferences.css
@@ -1,7 +1,130 @@
+@import url("chrome://branding/content/tor-styles.css");
+
#category-tor > .category-icon {
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(--purple-50);
+ color: white;
+}
+
+#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://browser/skin/onion.svg");
+ background-color: white;
+}
+
+#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(--purple-70);
+}
+
+#torPreferences-connectMessageBox.warning #torPreferences-connectMessageBox-button:hover {
+ background-color: var(--purple-80);
+ color: white!important;
+}
+
+#torPreferences-connectMessageBox.warning #torPreferences-connectMessageBox-button:active {
+ background-color: var(--purple-90);
+ color: white!important;
+}
+
+/* Advanced Settings */
+
#torPreferences-advanced-grid {
display: grid;
grid-template-columns: auto 1fr;
diff --git a/browser/components/urlbar/UrlbarInput.jsm b/browser/components/urlbar/UrlbarInput.jsm
index 13b1279105f2..60b5b9163d67 100644
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -10,6 +10,33 @@ const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
+const { TorConnect } = ChromeUtils.import(
+ "resource:///modules/TorConnect.jsm"
+);
+
+// in certain scenarios we want user input uris to open in a new tab if they do so from the
+// about:torconnect tab
+function maybeUpdateOpenLocationForTorConnect(openUILinkWhere, currentURI, destinationURI) {
+ try {
+ // only open in new tab if:
+ if (// user is navigating away from about:torconnect
+ currentURI === "about:torconnect" &&
+ // we are trying to open in same tab
+ openUILinkWhere === "current" &&
+ // only if user still has not bootstrapped
+ TorConnect.shouldShowTorConnect &&
+ // and user is not just navigating to about:torconnect
+ destinationURI !== "about:torconnect") {
+ return "tab";
+ }
+ } catch (e) {
+ // swallow exception and fall through returning original so we don't accidentally break
+ // anything if an exception is thrown
+ }
+
+ return openUILinkWhere;
+};
+
XPCOMUtils.defineLazyModuleGetters(this, {
AppConstants: "resource://gre/modules/AppConstants.jsm",
BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
@@ -1832,6 +1859,10 @@ class UrlbarInput {
// area when the current tab is re-selected.
browser.focus();
+ openUILinkWhere = maybeUpdateOpenLocationForTorConnect(
+ openUILinkWhere,
+ this.window.gBrowser.currentURI.asciiSpec,
+ url);
if (openUILinkWhere != "current") {
this.handleRevert();
}
diff --git a/browser/modules/TorConnect.jsm b/browser/modules/TorConnect.jsm
new file mode 100644
index 000000000000..bd5c998a6063
--- /dev/null
+++ b/browser/modules/TorConnect.jsm
@@ -0,0 +1,499 @@
+"use strict";
+
+var EXPORTED_SYMBOLS = ["TorConnect", "TorConnectTopics", "TorConnectState"];
+
+const { Services } = ChromeUtils.import(
+ "resource://gre/modules/Services.jsm"
+);
+
+const { BrowserWindowTracker } = ChromeUtils.import(
+ "resource:///modules/BrowserWindowTracker.jsm"
+);
+
+const { TorProtocolService, TorProcessStatus } = ChromeUtils.import(
+ "resource:///modules/TorProtocolService.jsm"
+);
+
+const { TorLauncherUtil } = ChromeUtils.import(
+ "resource://torlauncher/modules/tl-util.jsm"
+);
+
+/* Browser observer topis */
+const BrowserTopics = Object.freeze({
+ ProfileAfterChange: "profile-after-change",
+});
+
+/* tor-launcher observer topics */
+const TorTopics = Object.freeze({
+ ProcessIsReady: "TorProcessIsReady",
+ BootstrapStatus: "TorBootstrapStatus",
+ BootstrapError: "TorBootstrapError",
+ ProcessExited: "TorProcessExited",
+ LogHasWarnOrErr: "TorLogHasWarnOrErr",
+});
+
+/* Relevant prefs used by tor-launcher */
+const TorLauncherPrefs = Object.freeze({
+ quickstart: "extensions.torlauncher.quickstart",
+ prompt_at_startup: "extensions.torlauncher.prompt_at_startup",
+});
+
+const TorConnectState = Object.freeze({
+ /* Our initial state */
+ Initial: "Initial",
+ /* In-between initial boot and bootstrapping, users can change tor network settings during this state */
+ Configuring: "Configuring",
+ /* Geo-location and setting bridges/etc */
+ AutoConfiguring: "AutoConfiguring",
+ /* Tor is bootstrapping */
+ Bootstrapping: "Bootstrapping",
+ /* Passthrough state back to Configuring or Fatal */
+ Error: "Error",
+ /* An unrecoverable error */
+ FatalError: "FatalError",
+ /* Final state, after successful bootstrap */
+ Bootstrapped: "Bootstrapped",
+ /* If we are using System tor or the legacy Tor-Launcher */
+ Disabled: "Disabled",
+});
+
+/*
+
+ TorConnect State Transitions
+
+ ┌──────────────────────┐
+ │ Disabled │
+ └──────────────────────┘
+ ▲
+ │ legacyOrSystemTor()
+ │
+ ┌──────────────────────┐
+ ┌────────────────────── │ Initial │ ───────────────────────────┐
+ │ └──────────────────────┘ │
+ │ │ │
+ │ │ beginBootstrap() │
+ │ ▼ │
+┌────────────────┐ │ bootstrapComplete() ┌────────────────────────────────────────────────┐ │ beginBootstrap()
+│ Bootstrapped │ ◀──┼────────────────────── │ Bootstrapping │ ◀┼─────────────────┐
+└────────────────┘ │ └────────────────────────────────────────────────┘ │ │
+ │ │ ▲ │ │ │
+ │ │ cancelBootstrap() │ beginBootstrap() └────┼─────────────┐ │
+ │ ▼ │ │ │ │
+ │ beginConfigure() ┌────────────────────────────────────────────────┐ │ │ │
+ └─────────────────────▶ │ │ │ │ │
+ │ │ │ │ │
+ beginConfigure() │ │ │ │ │
+ ┌──────────────────────────▶ │ Configuring │ │ │ │
+ │ │ │ │ │ │
+ │ │ │ │ │ │
+ │ ┌─────────────────────▶ │ │ │ │ │
+ │ │ └────────────────────────────────────────────────┘ │ │ │
+ │ │ │ │ │ │ │
+ │ │ cancelAutoconfigure() │ autoConfigure() │ ┌────┼─────────────┼───┘
+ │ │ ▼ │ │ │ │
+ │ │ ┌──────────────────────┐ │ │ │ │
+ │ └────────────────────── │ AutoConfiguring │ ─┼────────────────────┘ │ │
+ │ └──────────────────────┘ │ │ │
+ │ │ │ │ onError() │
+ │ │ onError() │ onError() │ │
+ │ ▼ ▼ │ │
+ │ ┌────────────────────────────────────────────────┐ │ │
+ └─────────────────────────── │ Error │ ◀┘ │
+ └────────────────────────────────────────────────┘ │
+ │ ▲ onError() │
+ │ onFatalError() └──────────────────┘
+ ▼
+ ┌──────────────────────┐
+ │ FatalError │
+ └──────────────────────┘
+
+*/
+
+
+/* Maps allowed state transitions
+ TorConnectStateTransitions[state] maps to an array of allowed states to transition to
+*/
+const TorConnectStateTransitions =
+ Object.freeze(new Map([
+ [TorConnectState.Initial,
+ [TorConnectState.Disabled,
+ TorConnectState.Bootstrapping,
+ TorConnectState.Configuring,
+ TorConnectState.Error]],
+ [TorConnectState.Configuring,
+ [TorConnectState.AutoConfiguring,
+ TorConnectState.Bootstrapping,
+ TorConnectState.Error]],
+ [TorConnectState.AutoConfiguring,
+ [TorConnectState.Configuring,
+ TorConnectState.Bootstrapping,
+ TorConnectState.Error]],
+ [TorConnectState.Bootstrapping,
+ [TorConnectState.Configuring,
+ TorConnectState.Bootstrapped,
+ TorConnectState.Error]],
+ [TorConnectState.Error,
+ [TorConnectState.Configuring,
+ TorConnectState.FatalError]],
+ // terminal states
+ [TorConnectState.FatalError, []],
+ [TorConnectState.Bootstrapped, []],
+ [TorConnectState.Disabled, []],
+ ]));
+
+/* Topics Notified by the TorConnect module */
+const TorConnectTopics = Object.freeze({
+ StateChange: "torconnect:state-change",
+ BootstrapProgress: "torconnect:bootstrap-progress",
+ BootstrapComplete: "torconnect:bootstrap-complete",
+ BootstrapError: "torconnect:bootstrap-error",
+ FatalError: "torconnect:fatal-error",
+});
+
+const TorConnect = (() => {
+ let retval = {
+
+ _state: TorConnectState.Initial,
+ _bootstrapProgress: 0,
+ _bootstrapStatus: null,
+ _errorMessage: null,
+ _errorDetails: null,
+ _logHasWarningOrError: false,
+
+ /* These functions are called after transitioning to a new state */
+ _transitionCallbacks: Object.freeze(new Map([
+ /* Initial is never transitioned to */
+ [TorConnectState.Initial, null],
+ /* Configuring */
+ [TorConnectState.Configuring, (self, prevState) => {
+ // TODO move this to the transition function
+ if (prevState === TorConnectState.Bootstrapping) {
+ TorProtocolService.torStopBootstrap();
+ }
+ }],
+ /* AutoConfiguring */
+ [TorConnectState.AutoConfiguring, (self, prevState) => {
+
+ }],
+ /* Bootstrapping */
+ [TorConnectState.Bootstrapping, (self, prevState) => {
+ let error = TorProtocolService.connect();
+ if (error) {
+ self.onError(error.message, error.details);
+ } else {
+ self._errorMessage = self._errorDetails = null;
+ }
+ }],
+ /* Bootstrapped */
+ [TorConnectState.Bootstrapped, (self,prevState) => {
+ // notify observers of bootstrap completion
+ Services.obs.notifyObservers(null, TorConnectTopics.BootstrapComplete);
+ }],
+ /* Error */
+ [TorConnectState.Error, (self, prevState, errorMessage, errorDetails, fatal) => {
+ self._errorMessage = errorMessage;
+ self._errorDetails = errorDetails;
+
+ Services.obs.notifyObservers({message: errorMessage, details: errorDetails}, TorConnectTopics.BootstrapError);
+ if (fatal) {
+ self.onFatalError();
+ } else {
+ self.beginConfigure();
+ }
+ }],
+ /* FatalError */
+ [TorConnectState.FatalError, (self, prevState) => {
+ Services.obs.notifyObservers(null, TorConnectTopics.FatalError);
+ }],
+ /* Disabled */
+ [TorConnectState.Disabled, (self, prevState) => {
+
+ }],
+ ])),
+
+ _changeState: function(newState, ...args) {
+ const prevState = this._state;
+
+ // ensure this is a valid state transition
+ if (!TorConnectStateTransitions.get(prevState)?.includes(newState)) {
+ throw Error(`TorConnect: Attempted invalid state transition from ${prevState} to ${newState}`);
+ }
+
+ console.log(`TorConnect: transitioning state from ${prevState} to ${newState}`);
+
+ // set our new state first so that state transitions can themselves trigger
+ // a state transition
+ this._state = newState;
+
+ // call our transition function and forward any args
+ this._transitionCallbacks.get(newState)(this, prevState, ...args);
+
+ Services.obs.notifyObservers({state: newState}, TorConnectTopics.StateChange);
+ },
+
+ // init should be called on app-startup in MainProcessingSingleton.jsm
+ init : function() {
+ console.log("TorConnect: Init");
+
+ // delay remaining init until after profile-after-change
+ Services.obs.addObserver(this, BrowserTopics.ProfileAfterChange);
+ },
+
+ observe: function(subject, topic, data) {
+ console.log(`TorConnect: observed ${topic}`);
+
+ switch(topic) {
+
+ /* Determine which state to move to from Initial */
+ case BrowserTopics.ProfileAfterChange: {
+ if (TorLauncherUtil.useLegacyLauncher || !TorProtocolService.ownsTorDaemon) {
+ // Disabled
+ this.legacyOrSystemTor();
+ } else {
+ // register the Tor topics we always care about
+ for (const topicKey in TorTopics) {
+ const topic = TorTopics[topicKey];
+ Services.obs.addObserver(this, topic);
+ console.log(`TorConnect: observing topic '${topic}'`);
+ }
+
+ if (TorProtocolService.torProcessStatus == TorProcessStatus.Running) {
+ if (this.shouldQuickStart) {
+ // Quickstart
+ this.beginBootstrap();
+ } else {
+ // Configuring
+ this.beginConfigure();
+ }
+ }
+ }
+
+ Services.obs.removeObserver(this, topic);
+ break;
+ }
+ /* Transition out of Initial if Tor daemon wasn't running yet in BrowserTopics.ProfileAfterChange */
+ case TorTopics.ProcessIsReady: {
+ if (this.state === TorConnectState.Initial)
+ {
+ if (this.shouldQuickStart) {
+ // Quickstart
+ this.beginBootstrap();
+ } else {
+ // Configuring
+ this.beginConfigure();
+ }
+ }
+ break;
+ }
+ /* Updates our bootstrap status */
+ case TorTopics.BootstrapStatus: {
+ if (this._state != TorConnectState.Bootstrapping) {
+ console.log(`TorConnect: observed ${TorTopics.BootstrapStatus} topic while in state TorConnectState.${this._state}`);
+ break;
+ }
+
+ const obj = subject?.wrappedJSObject;
+ if (obj) {
+ this._bootstrapProgress= obj.PROGRESS;
+ this._bootstrapStatus = TorLauncherUtil.getLocalizedBootstrapStatus(obj, "TAG");
+
+ console.log(`TorConnect: Bootstrapping ${this._bootstrapProgress}% complete (${this._bootstrapStatus})`);
+ Services.obs.notifyObservers({
+ progress: this._bootstrapProgress,
+ status: this._bootstrapStatus,
+ hasWarnings: this._logHasWarningOrError
+ }, TorConnectTopics.BootstrapProgress);
+
+ if (this._bootstrapProgress === 100) {
+ this.bootstrapComplete();
+ }
+ }
+ break;
+ }
+ /* Handle bootstrap error*/
+ case TorTopics.BootstrapError: {
+ const obj = subject?.wrappedJSObject;
+ TorProtocolService.torStopBootstrap();
+ this.onError(obj.message, obj.details);
+ break;
+ }
+ case TorTopics.LogHasWarnOrErr: {
+ this._logHasWarningOrError = true;
+ break;
+ }
+ default:
+ // ignore
+ break;
+ }
+ },
+
+ /*
+ Various getters
+ */
+
+ get shouldShowTorConnect() {
+ // TorBrowser must control the daemon
+ return (TorProtocolService.ownsTorDaemon &&
+ // and we're not using the legacy launcher
+ !TorLauncherUtil.useLegacyLauncher &&
+ // legacy checks, TODO: maybe this should be in terms of our own state?
+ (TorProtocolService.isNetworkDisabled() || !TorProtocolService.isBootstrapDone()));
+ },
+
+ get shouldQuickStart() {
+ // quickstart must be enabled
+ return Services.prefs.getBoolPref(TorLauncherPrefs.quickstart, false) &&
+ // and the previous bootstrap attempt must have succeeded
+ !Services.prefs.getBoolPref(TorLauncherPrefs.prompt_at_startup, true);
+ },
+
+ get state() {
+ return this._state;
+ },
+
+ get bootstrapProgress() {
+ return this._bootstrapProgress;
+ },
+
+ get bootstrapStatus() {
+ return this._bootstrapStatus;
+ },
+
+ get errorMessage() {
+ return this._errorMessage;
+ },
+
+ get errorDetails() {
+ return this._errorDetails;
+ },
+
+ get logHasWarningOrError() {
+ return this._logHasWarningOrError;
+ },
+
+ /*
+ These functions tell TorConnect to transition states
+ */
+
+ legacyOrSystemTor: function() {
+ console.log("TorConnect: legacyOrSystemTor()");
+ this._changeState(TorConnectState.Disabled);
+ },
+
+ beginBootstrap: function() {
+ console.log("TorConnect: beginBootstrap()");
+ this._changeState(TorConnectState.Bootstrapping);
+ },
+
+ beginConfigure: function() {
+ console.log("TorConnect: beginConfigure()");
+ this._changeState(TorConnectState.Configuring);
+ },
+
+ autoConfigure: function() {
+ console.log("TorConnect: autoConfigure()");
+ // TODO: implement
+ throw Error("TorConnect: not implemented");
+ },
+
+ cancelAutoConfigure: function() {
+ console.log("TorConnect: cancelAutoConfigure()");
+ // TODO: implement
+ throw Error("TorConnect: not implemented");
+ },
+
+ cancelBootstrap: function() {
+ console.log("TorConnect: cancelBootstrap()");
+ this._changeState(TorConnectState.Configuring);
+ },
+
+ bootstrapComplete: function() {
+ console.log("TorConnect: bootstrapComplete()");
+ this._changeState(TorConnectState.Bootstrapped);
+ },
+
+ onError: function(message, details) {
+ console.log("TorConnect: onError()");
+ this._changeState(TorConnectState.Error, message, details, false);
+ },
+
+ onFatalError: function() {
+ console.log("TorConnect: onFatalError()");
+ // TODO: implement
+ throw Error("TorConnect: not implemented");
+ },
+
+ /*
+ Further external commands and helper methods
+ */
+ openTorPreferences: function() {
+ const win = BrowserWindowTracker.getTopWindow()
+ win.openTrustedLinkIn("about:preferences#tor", "tab");
+ },
+
+ copyTorLogs: function() {
+ // 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
+ );
+ },
+
+ // called from browser.js on browser startup, passed in either the user's homepage(s)
+ // or uris passed via command-line; we want to replace them with about:torconnect uris
+ // which redirect after bootstrapping
+ getURIsToLoad: function(uriVariant) {
+ // convert the object we get from browser.js
+ let uriStrings = ((v) => {
+ // an interop array
+ if (v instanceof Ci.nsIArray) {
+ // Transform the nsIArray of nsISupportsString's into a JS Array of
+ // JS strings.
+ return Array.from(
+ v.enumerate(Ci.nsISupportsString),
+ supportStr => supportStr.data
+ );
+ // an interop string
+ } else if (v instanceof Ci.nsISupportsString) {
+ return [v.data];
+ // a js string
+ } else if (typeof v === "string") {
+ return v.split("|");
+ // a js array of js strings
+ } else if (Array.isArray(v) &&
+ v.reduce((allStrings, entry) => {return allStrings && (typeof entry === "string");}, true)) {
+ return v;
+ }
+ // about:tor as safe fallback
+ console.log(`TorConnect: getURIsToLoad() received unknown variant '${JSON.stringify(v)}'`);
+ return ["about:tor"];
+ })(uriVariant);
+
+ // will attempt to convert user-supplied string to a uri, fallback to about:tor if cannot convert
+ // to valid uri object
+ let uriStringToUri = (uriString) => {
+ let uri = Services.uriFixup.createFixupURI(uriString, 0);
+ return uri ? uri : Services.io.newURI("about:tor");
+ };
+ let uris = uriStrings.map(uriStringToUri);
+
+ // assume we have a valid uri and generate an about:torconnect redirect uri
+ let uriToRedirectUri = (uri) => {
+ return`about:torconnect?redirect=${encodeURIComponent(uri.spec)}`;
+ };
+ let redirectUris = uris.map(uriToRedirectUri);
+
+ console.log(`TorConnect: will load after bootstrap => [${uris.map((uri) => {return uri.spec;}).join(", ")}]`);
+ return redirectUris;
+ },
+ };
+ retval.init();
+ return retval;
+})(); /* TorConnect */
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..e6c78b9a0eb1 100644
--- a/browser/modules/TorProtocolService.jsm
+++ b/browser/modules/TorProtocolService.jsm
@@ -1,21 +1,60 @@
+// Copyright (c) 2021, The Tor Project, Inc.
+
"use strict";
-var EXPORTED_SYMBOLS = ["TorProtocolService"];
+var EXPORTED_SYMBOLS = ["TorProtocolService", "TorProcessStatus"];
-const { TorLauncherUtil } = ChromeUtils.import(
- "resource://torlauncher/modules/tl-util.jsm"
+const { Services } = ChromeUtils.import(
+ "resource://gre/modules/Services.jsm"
);
+// see tl-process.js
+const TorProcessStatus = Object.freeze({
+ Unknown: 0,
+ Starting: 1,
+ Running: 2,
+ Exited: 3,
+});
+
+/* Browser observer topis */
+const BrowserTopics = Object.freeze({
+ ProfileAfterChange: "profile-after-change",
+});
+
var TorProtocolService = {
- _tlps: Cc["@torproject.org/torlauncher-protocol-service;1"].getService(
- Ci.nsISupports
- ).wrappedJSObject,
+ _TorLauncherUtil: function() {
+ let { TorLauncherUtil } = ChromeUtils.import(
+ "resource://torlauncher/modules/tl-util.jsm"
+ );
+ return TorLauncherUtil;
+ }(),
+ _TorLauncherProtocolService: null,
+ _TorProcessService: null,
// 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
_settingsCache: new Map(),
+ init() {
+ Services.obs.addObserver(this, BrowserTopics.ProfileAfterChange);
+ },
+
+ observe(subject, topic, data) {
+ if (topic === BrowserTopics.ProfileAfterChange) {
+ // we have to delay init'ing this or else the crypto service inits too early without a profile
+ // which breaks the password manager
+ this._TorLauncherProtocolService = Cc["@torproject.org/torlauncher-protocol-service;1"].getService(
+ Ci.nsISupports
+ ).wrappedJSObject;
+ this._TorProcessService = Cc["@torproject.org/torlauncher-process-service;1"].getService(
+ Ci.nsISupports
+ ).wrappedJSObject,
+
+ Services.obs.removeObserver(this, topic);
+ }
+ },
+
_typeof(aValue) {
switch (typeof aValue) {
case "boolean":
@@ -118,7 +157,7 @@ var TorProtocolService = {
}
let errorObject = {};
- if (!this._tlps.TorSetConfWithReply(settingsObject, errorObject)) {
+ if (!this._TorLauncherProtocolService.TorSetConfWithReply(settingsObject, errorObject)) {
throw new Error(errorObject.details);
}
@@ -131,8 +170,8 @@ var TorProtocolService = {
_readSetting(aSetting) {
this._assertValidSettingKey(aSetting);
- let reply = this._tlps.TorGetConf(aSetting);
- if (this._tlps.TorCommandSucceeded(reply)) {
+ let reply = this._TorLauncherProtocolService.TorGetConf(aSetting);
+ if (this._TorLauncherProtocolService.TorCommandSucceeded(reply)) {
return reply.lineArray;
}
throw new Error(reply.lineArray.join("\n"));
@@ -196,17 +235,129 @@ var TorProtocolService = {
// writes current tor settings to disk
flushSettings() {
- this._tlps.TorSendCommand("SAVECONF");
+ this.sendCommand("SAVECONF");
},
- getLog() {
- let countObj = { value: 0 };
- let torLog = this._tlps.TorGetLog(countObj);
+ getLog(countObj) {
+ countObj = countObj || { value: 0 };
+ let torLog = this._TorLauncherProtocolService.TorGetLog(countObj);
return torLog;
},
// true if we launched and control tor, false if using system tor
get ownsTorDaemon() {
- return TorLauncherUtil.shouldStartAndOwnTor;
+ return this._TorLauncherUtil.shouldStartAndOwnTor;
+ },
+
+ // Assumes `ownsTorDaemon` is true
+ isNetworkDisabled() {
+ const reply = TorProtocolService._TorLauncherProtocolService.TorGetConfBool(
+ "DisableNetwork",
+ true
+ );
+ if (TorProtocolService._TorLauncherProtocolService.TorCommandSucceeded(reply)) {
+ return reply.retVal;
+ }
+ return true;
+ },
+
+ enableNetwork() {
+ let settings = {};
+ settings.DisableNetwork = false;
+ let errorObject = {};
+ if (!this._TorLauncherProtocolService.TorSetConfWithReply(settings, errorObject)) {
+ throw new Error(errorObject.details);
+ }
+ },
+
+ sendCommand(cmd) {
+ return this._TorLauncherProtocolService.TorSendCommand(cmd);
+ },
+
+ retrieveBootstrapStatus() {
+ return this._TorLauncherProtocolService.TorRetrieveBootstrapStatus();
+ },
+
+ _GetSaveSettingsErrorMessage(aDetails) {
+ try {
+ return this._TorLauncherUtil.getSaveSettingsErrorMessage(aDetails);
+ } catch (e) {
+ console.log("GetSaveSettingsErrorMessage error", e);
+ return "Unexpected Error";
+ }
+ },
+
+ setConfWithReply(settings) {
+ let result = false;
+ const error = {};
+ try {
+ result = this._TorLauncherProtocolService.TorSetConfWithReply(settings, error);
+ } catch (e) {
+ console.log("TorSetConfWithReply error", e);
+ error.details = this._GetSaveSettingsErrorMessage(e.message);
+ }
+ return { result, error };
+ },
+
+ isBootstrapDone() {
+ return this._TorProcessService.mIsBootstrapDone;
+ },
+
+ clearBootstrapError() {
+ return this._TorProcessService.TorClearBootstrapError();
+ },
+
+ torBootstrapErrorOccurred() {
+ return this._TorProcessService.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._TorLauncherProtocolService.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();
+ },
+
+ get torProcessStatus() {
+ if (this._TorProcessService) {
+ return this._TorProcessService.TorProcessStatus;
+ }
+ return TorProcessStatus.Unknown;
},
};
+TorProtocolService.init();
\ No newline at end of file
diff --git a/browser/modules/TorStrings.jsm b/browser/modules/TorStrings.jsm
index 1e08b168e4af..c0691ff078ce 100644
--- a/browser/modules/TorStrings.jsm
+++ b/browser/modules/TorStrings.jsm
@@ -257,6 +257,9 @@ var TorStrings = {
"Tor Browser routes your traffic over the Tor Network, run by thousands of volunteers around the world."
),
learnMore: getString("torPreferences.learnMore", "Learn More"),
+ quickstartHeading: getString("torPreferences.quickstart", "Quickstart"),
+ quickstartDescription: getString("torPreferences.quickstartDescription", "Quickstart allows Tor Browser to connect automatically."),
+ quickstartCheckbox : getString("torPreferences.quickstartCheckbox", "Always connect automatically"),
bridgesHeading: getString("torPreferences.bridges", "Bridges"),
bridgesDescription: getString(
"torPreferences.bridgesDescription",
@@ -364,6 +367,83 @@ 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"
+ ),
+
+ torNotConnectedConcise: getStringNet(
+ "torConnect.notConnectedConcise",
+ "Not Connected"
+ ),
+
+ torConnectingConcise: getStringNet(
+ "torConnect.connectingConcise",
+ "Connecting…"
+ ),
+
+ torBootstrapFailed: getStringLauncher(
+ "tor_bootstrap_failed",
+ "Tor failed to establish a Tor network connection."
+ ),
+
+ torConfigure: getStringNet(
+ "torsettings.wizard.title.configure",
+ "Tor Network Settings"
+ ),
+
+ copyLog: getStringNet(
+ "torConnect.copyLog",
+ "Copy Tor Logs"
+ ),
+
+ torConnectButton: getStringNet("torSettings.connect", "Connect"),
+
+ cancel: getStringCommon("Cancel", "Cancel"),
+
+ torConnected: getStringLauncher(
+ "torlauncher.bootstrapStatus.done",
+ "Connected to the Tor network"
+ ),
+
+ torConnectedConcise: getStringLauncher(
+ "torConnect.connectedConcise",
+ "Connected"
+ ),
+
+ tryAgain: getStringNet("torConnect.tryAgain", "Try connecting again"),
+ offline: getStringNet("torConnect.offline", "Offline"),
+
+ // tor connect strings for message box in about:preferences#tor
+ connectMessage: getStringNet("torConnect.connectMessage", "Changes to Tor Settings will not take effect until you connect to the Tor Network"),
+ tryAgainMessage: getStringNet("torConnect.tryAgainMessage", "Tor Browser has failed to establish a connection to the Tor Network"),
+ };
+ })(),
+
/*
Tor Onion Services Strings, e.g., for the authentication prompt.
*/
diff --git a/browser/modules/moz.build b/browser/modules/moz.build
index 5fb78d1c07a8..7f091e0e7711 100644
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -155,6 +155,8 @@ EXTRA_JS_MODULES += [
'TabUnloader.jsm',
'ThemeVariableMap.jsm',
'TopSiteAttribution.jsm',
+ 'TorConnect.jsm',
+ 'TorProcessService.jsm',
'TorProtocolService.jsm',
'TorStrings.jsm',
'TransientPrefs.jsm',
diff --git a/browser/themes/shared/identity-block/identity-block.inc.css b/browser/themes/shared/identity-block/identity-block.inc.css
index 011fb9f3081c..9a70125495d7 100644
--- a/browser/themes/shared/identity-block/identity-block.inc.css
+++ b/browser/themes/shared/identity-block/identity-block.inc.css
@@ -61,19 +61,9 @@
-moz-outline-radius: var(--toolbarbutton-border-radius);
}
-%ifdef MOZ_OFFICIAL_BRANDING
#identity-box[pageproxystate="valid"].chromeUI > #identity-icon-label {
- color: #420C5D;
-}
-
-toolbar[brighttext] #identity-box[pageproxystate="valid"].chromeUI > #identity-icon-label {
- color: #CC80FF;
-}
-%endif
-
-#identity-box[pageproxystate="valid"].chromeUI > #identity-icon-label,
-.urlbar-label {
- opacity: .6;
+ color: var(--tor-branding-color);
+ opacity: 1;
}
#identity-icon-label {
@@ -132,6 +122,8 @@ toolbar[brighttext] #identity-box[pageproxystate="valid"].chromeUI > #identity-i
#identity-box[pageproxystate="valid"].chromeUI > #identity-icon {
list-style-image: url(chrome://branding/content/identity-icons-brand.svg);
+ fill: var(--tor-branding-color);
+ fill-opacity: 1;
}
#urlbar:not(.searchButton) > #urlbar-input-container > #identity-box[pageproxystate="invalid"] > #identity-icon {
diff --git a/browser/themes/shared/jar.inc.mn b/browser/themes/shared/jar.inc.mn
index e4a3c8d2d41c..d38e1001282b 100644
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -8,6 +8,7 @@
# to the location of the actual manifest.
skin/classic/browser/aboutNetError.css (../shared/aboutNetError.css)
+ skin/classic/browser/onionPattern.css (../shared/onionPattern.css)
skin/classic/browser/blockedSite.css (../shared/blockedSite.css)
skin/classic/browser/error-pages.css (../shared/error-pages.css)
skin/classic/browser/aboutRestartRequired.css (../shared/aboutRestartRequired.css)
diff --git a/browser/themes/shared/onionPattern.css b/browser/themes/shared/onionPattern.css
new file mode 100644
index 000000000000..c605a4b4f59e
--- /dev/null
+++ b/browser/themes/shared/onionPattern.css
@@ -0,0 +1,124 @@
+/* Onion pattern */
+
+:root {
+ --sqrt3: 1.73205080757;
+}
+
+.onion-pattern-container {
+ opacity: var(--onion-opacity, 1);
+ flex: auto; /* grow to consume remaining space on the page */
+ display: flex;
+ margin: 0 auto;
+ width: 100%;
+ height: calc((2 + var(--sqrt3)) * var(--onion-radius, 50px)); /* room for 2 rows of circles */
+ max-height: calc((2 + var(--sqrt3)) * var(--onion-radius, 50px));
+ direction: ltr;
+}
+
+.onion-pattern-crop {
+ display: flex;
+ justify-content: center;
+ overflow-x: hidden;
+ pointer-events: none; /* for some reason, elements with overflow-x: hidden set become focusable */
+
+ margin: 0 auto;
+}
+
+/* Centers horizontally within the root container*/
+.onion-pattern-column {
+ width: calc(40 * var(--onion-radius, 50px)); /* room for 20 circles in a row */
+ height: calc((2 + var(--sqrt3)) * var(--onion-radius, 50px)); /* room for 2 rows of circles */
+ flex-shrink: 0;
+ overflow-x: hidden; /* clip extra circles on the sides */
+ pointer-events: none; /* for some reason, elements with overflow-x: hidden set become focusable */
+}
+
+.onion-pattern-row {
+ width: calc(40 * var(--onion-radius, 50px)); /* room for 20 circles in a row */
+ display: flex;
+ flex-direction: row;
+ position: relative;
+}
+
+.onion-pattern-offset-row {
+ left: calc(-1 * var(--onion-radius, 50px));
+ margin-top: calc((var(--sqrt3) - 2.0) * var(--onion-radius, 50px));
+}
+
+/* With borders, circles are 100x100 pixels*/
+.circle {
+ position: relative;
+ min-width: calc(2 * var(--onion-radius, 50px));
+ min-height: calc(2 * var(--onion-radius, 50px));
+ border-radius: 50%;
+ box-sizing: border-box;
+}
+
+.inner {
+ position: absolute;
+ box-sizing: border-box;
+ border-radius: 50%;
+}
+
+.inner:nth-child(1){
+ width: 100%;
+ height: 100%;
+}
+
+.inner:nth-child(2){
+ transform: translate(20%, 20%);
+ width: calc(100% * 5/7);
+ height: calc(100% * 5/7);
+}
+
+.inner:nth-child(3){
+ transform: translate(calc(100% * 2/3), calc(100% * 2/3));
+ width: calc(100% * 3/7);
+ height: calc(100% * 3/7);
+}
+
+.inner:nth-child(4){
+ transform: translate(300%, 300%);
+ width: calc(100% * 1/7);
+ height: calc(100% * 1/7);
+}
+
+.solid {
+ background-color: var(--onion-color, #000);
+}
+
+.border {
+ border: 4px solid var(--onion-color, #000);
+}
+
+.dashed {
+ border: 4px dashed var(--onion-color, #000);
+}
+
+.dotted {
+ border: 4px dotted var(--onion-color, #000);
+}
+
+.bold {
+ border: 8px solid var(--onion-color, #000);
+}
+
+.top-half {
+ width: calc(2 * var(--onion-radius, 50px));
+ height: var(--onion-radius, 50px);
+ border-radius: var(--onion-radius, 50px) var(--onion-radius, 50px) 0 0;
+ box-sizing: border-box;
+}
+
+.bottom-half {
+ width: calc(2 * var(--onion-radius, 50px));
+ height: var(--onion-radius, 50px);
+ border-radius: 0 0 var(--onion-radius, 50px) var(--onion-radius, 50px);
+ box-sizing: border-box;
+}
+
+.scaler {
+ position: absolute;
+ left:0;
+ bottom:0;
+}
\ No newline at end of file
diff --git a/browser/themes/shared/onionPattern.inc.xhtml b/browser/themes/shared/onionPattern.inc.xhtml
new file mode 100644
index 000000000000..6bbde93684a2
--- /dev/null
+++ b/browser/themes/shared/onionPattern.inc.xhtml
@@ -0,0 +1,210 @@
+<!--
+ - The abstract onion pattern begins here. There are two
+ - "onion-pattern-row" elements, each containing 14 circles. The width
+ - of "onion-pattern-row" is fixed at a value that is wide enough so the
+ - circles are not distorted by the flex-based layout. The parent
+ - "onion-pattern-container" element has overflow-x: hidden and is designed
+ - to expand to the width of the page, until it reaches a maximum width
+ - that can accommodate all 14 circles. Since the rows are wider than
+ - most browser windows, typically the two rows of onions will fill the
+ - bottom of the page. On really wide pages, the onions are centered at
+ - the bottom of the page.
+-->
+
+<div class="onion-pattern-container">
+ <!-- for some reason, these two elements are focusable, seems related to
+ - flex css somehow; disable their tabindex to fix
+ -->
+ <div class="onion-pattern-crop" tabindex="-1">
+ <div class="onion-pattern-column" tabindex="-1">
+ <div class="onion-pattern-row">
+ <div class="circle solid"></div>
+
+ <div class="circle dashed"></div>
+
+ <div class="circle">
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ </div>
+
+ <div class="circle">
+ <div class="bottom-half solid"></div>
+ <div class="bottom-half dotted"></div>
+ </div>
+
+ <div class="circle border"></div>
+
+ <div class="circle">
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ </div>
+
+ <div class="circle solid"></div>
+
+ <div class="circle">
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ </div>
+
+ <div class="circle bold"></div>
+
+ <div class="circle">
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ </div>
+
+ <div class="circle bold"></div>
+
+ <div class="circle">
+ <div class="bottom-half solid"></div>
+ <div class="bottom-half solid"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ </div>
+
+ <div class="circle dotted"></div>
+
+ <div class="circle">
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ </div>
+
+ <div class="circle solid"></div>
+
+ <div class="circle">
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ </div>
+
+ <div class="circle bold"></div>
+
+ <div class="circle dashed"></div>
+ </div>
+
+ <div class="onion-pattern-row onion-pattern-offset-row">
+ <div class="circle">
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ </div>
+
+ <div class="circle bold"></div>
+
+ <div class="circle solid"></div>
+
+ <div class="circle">
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ </div>
+
+ <div class="circle">
+ <div class="top-half solid"></div>
+ <div class="top-half solid"></div>
+ </div>
+
+ <div class="circle border"></div>
+
+ <div class="circle dotted"></div>
+
+ <div class="circle">
+ <div class="top-half border"></div>
+ <div class="top-half dashed"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ </div>
+
+ <div class="circle">
+ <div class="top-half dotted"></div>
+ <div class="top-half solid"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ <div class="inner dashed"></div>
+ </div>
+
+ <div class="circle dotted"></div>
+
+ <div class="circle bold"></div>
+
+ <div class="circle solid"></div>
+
+ <div class="circle">
+ <div class="top-half solid"></div>
+ <div class="top-half dotted"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ <div class="inner dotted"></div>
+ </div>
+
+ <div class="circle">
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ <div class="inner border"></div>
+ </div>
+
+ <div class="circle dotted"></div>
+
+ <div class="circle">
+ <div class="top-half solid"></div>
+ <div class="top-half solid"></div>
+ </div>
+
+ <div class="circle dotted"></div>
+ </div>
+ </div>
+ </div>
+</div>
\ No newline at end of file
diff --git a/browser/themes/shared/urlbar-searchbar.inc.css b/browser/themes/shared/urlbar-searchbar.inc.css
index d3cc6bf7f024..297dbcdf444d 100644
--- a/browser/themes/shared/urlbar-searchbar.inc.css
+++ b/browser/themes/shared/urlbar-searchbar.inc.css
@@ -826,3 +826,5 @@
}
%include ../../components/onionservices/content/onionlocation-urlbar.css
+%include ../../components/torconnect/content/torconnect-urlbar.css
+
diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp
index afc872569519..e74851a6672c 100644
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -16387,9 +16387,56 @@ void Document::RemoveToplevelLoadingDocument(Document* aDoc) {
StylePrefersColorScheme Document::PrefersColorScheme(
IgnoreRFP aIgnoreRFP) const {
+
+ // tor-browser#27476
+ // should this document ignore resist finger-printing settings with regards to
+ // setting the color scheme
+ // currently only enabled for about:torconnect but we could expand to other non-
+ // SystemPrincipal pages if we wish
+ const auto documentUsesPreferredColorScheme = [](auto const* constDocument) -> bool {
+ if (auto* document = const_cast<Document*>(constDocument); document != nullptr) {
+ auto uri = document->GetDocBaseURI();
+
+ // try and extract out our prepath and filepath portions of the uri to C-strings
+ nsAutoCString prePathStr, filePathStr;
+ if(NS_FAILED(uri->GetPrePath(prePathStr)) ||
+ NS_FAILED(uri->GetFilePath(filePathStr))) {
+ return false;
+ }
+
+ // stick them in string view for easy comparisons
+ std::string_view prePath(prePathStr.get(), prePathStr.Length()),
+ filePath(filePathStr.get(), filePathStr.Length());
+
+ // these about URIs will have the user's preferred color scheme exposed to them
+ // we can place other URIs here in the future if we wish
+ // see nsIURI.idl for URI part definitions
+ constexpr struct {
+ std::string_view prePath;
+ std::string_view filePath;
+ } allowedURIs[] = {
+ { "about:", "torconnect" },
+ };
+
+ // check each uri in the allow list against this document's uri
+ // verify the prepath and the file path match
+ for(auto const& uri : allowedURIs) {
+ if (prePath == uri.prePath &&
+ filePath == uri.filePath) {
+ // positive match means we can apply dark-mode to the page
+ return true;
+ }
+ }
+ }
+
+ // do not allow if no match or other error
+ return false;
+ };
+
if (aIgnoreRFP == IgnoreRFP::No &&
- nsContentUtils::ShouldResistFingerprinting(this)) {
- return StylePrefersColorScheme::Light;
+ nsContentUtils::ShouldResistFingerprinting(this) &&
+ !documentUsesPreferredColorScheme(this)) {
+ return StylePrefersColorScheme::Light;
}
if (nsPresContext* pc = GetPresContext()) {
diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp
index abe1e56d9714..759060f131ff 100644
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -6082,6 +6082,8 @@ void nsGlobalWindowOuter::CloseOuter(bool aTrustedCaller) {
NS_ENSURE_SUCCESS_VOID(rv);
if (!StringBeginsWith(url, NS_LITERAL_STRING("about:neterror")) &&
+ // we want about:torconnect pages to be able to close themselves after bootstrap
+ !StringBeginsWith(url, NS_LITERAL_STRING("about:torconnect")) &&
!HadOriginalOpener() && !aTrustedCaller) {
bool allowClose =
mAllowScriptsToClose ||
diff --git a/toolkit/components/processsingleton/MainProcessSingleton.jsm b/toolkit/components/processsingleton/MainProcessSingleton.jsm
index db1e2dc8f568..ea9288dccbb3 100644
--- a/toolkit/components/processsingleton/MainProcessSingleton.jsm
+++ b/toolkit/components/processsingleton/MainProcessSingleton.jsm
@@ -24,6 +24,11 @@ MainProcessSingleton.prototype = {
null
);
+ ChromeUtils.import(
+ "resource:///modules/TorConnect.jsm",
+ null
+ );
+
// Load this script early so that console.* is initialized
// before other frame scripts.
Services.mm.loadFrameScript(
diff --git a/toolkit/modules/AsyncPrefs.jsm b/toolkit/modules/AsyncPrefs.jsm
index aca86556cd5e..b81ff5e22b9b 100644
--- a/toolkit/modules/AsyncPrefs.jsm
+++ b/toolkit/modules/AsyncPrefs.jsm
@@ -18,6 +18,8 @@ const kAllowedPrefs = new Set([
"testing.allowed-prefs.some-char-pref",
"testing.allowed-prefs.some-int-pref",
+ "extensions.torlauncher.quickstart",
+
"narrate.rate",
"narrate.voice",
diff --git a/toolkit/modules/RemotePageAccessManager.jsm b/toolkit/modules/RemotePageAccessManager.jsm
index eceaa7c857de..54230e1175ec 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,21 @@ let RemotePageAccessManager = {
RPMAddMessageListener: ["*"],
RPMRemoveMessageListener: ["*"],
},
+ "about:torconnect": {
+ RPMAddMessageListener: [
+ "torconnect:state-change",
+ ],
+ RPMSendAsyncMessage: [
+ "torconnect:open-tor-preferences",
+ "torconnect:begin-bootstrap",
+ "torconnect:cancel-bootstrap",
+ "torconnect:set-quickstart",
+ ],
+ RPMSendQuery: [
+ "torconnect:get-init-args",
+ "torconnect:copy-tor-logs",
+ ],
+ },
},
/**
diff --git a/toolkit/mozapps/update/UpdateService.jsm b/toolkit/mozapps/update/UpdateService.jsm
index 1fb397373151..79881cba42d6 100644
--- a/toolkit/mozapps/update/UpdateService.jsm
+++ b/toolkit/mozapps/update/UpdateService.jsm
@@ -12,6 +12,17 @@ const { AppConstants } = ChromeUtils.import(
const { AUSTLMY } = ChromeUtils.import(
"resource://gre/modules/UpdateTelemetry.jsm"
);
+
+const { TorProtocolService } = ChromeUtils.import(
+ "resource:///modules/TorProtocolService.jsm"
+);
+
+function _shouldRegisterBootstrapObserver(errorCode) {
+ return errorCode == PROXY_SERVER_CONNECTION_REFUSED &&
+ !TorProtocolService.isBootstrapDone() &&
+ TorProtocolService.ownsTorDaemon;
+};
+
const {
Bits,
BitsRequest,
@@ -201,6 +212,7 @@ const INVALID_UPDATER_STATUS_CODE = 99;
// Custom update error codes
const BACKGROUNDCHECK_MULTIPLE_FAILURES = 110;
const NETWORK_ERROR_OFFLINE = 111;
+const PROXY_SERVER_CONNECTION_REFUSED = 2152398920;
// Error codes should be < 1000. Errors above 1000 represent http status codes
const HTTP_ERROR_OFFSET = 1000;
@@ -2220,6 +2232,9 @@ UpdateService.prototype = {
case "network:offline-status-changed":
this._offlineStatusChanged(data);
break;
+ case "torconnect:bootstrap-complete":
+ this._bootstrapComplete();
+ break;
case "nsPref:changed":
if (data == PREF_APP_UPDATE_LOG || data == PREF_APP_UPDATE_LOG_FILE) {
gLogEnabled; // Assigning this before it is lazy-loaded is an error.
@@ -2640,6 +2655,35 @@ UpdateService.prototype = {
this._attemptResume();
},
+ _registerBootstrapObserver: function AUS__registerBootstrapObserver() {
+ if (this._registeredBootstrapObserver) {
+ LOG(
+ "UpdateService:_registerBootstrapObserver - observer already registered"
+ );
+ return;
+ }
+
+ LOG(
+ "UpdateService:_registerBootstrapObserver - waiting for tor bootstrap to " +
+ "be complete, then forcing another check"
+ );
+
+ Services.obs.addObserver(this, "torconnect:bootstrap-complete");
+ this._registeredBootstrapObserver = true;
+ },
+
+ _bootstrapComplete: function AUS__bootstrapComplete() {
+ Services.obs.removeObserver(this, "torconnect:bootstrap-complete");
+ this._registeredBootstrapObserver = false;
+
+ LOG(
+ "UpdateService:_bootstrapComplete - bootstrapping complete, forcing " +
+ "another background check"
+ );
+
+ this._attemptResume();
+ },
+
onCheckComplete: function AUS_onCheckComplete(request, updates) {
this._selectAndInstallUpdate(updates);
},
@@ -2659,6 +2703,11 @@ UpdateService.prototype = {
AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_OFFLINE);
}
return;
+ } else if (_shouldRegisterBootstrapObserver(update.errorCode)) {
+ // Register boostrap observer to try again, but only when we own the
+ // tor process.
+ this._registerBootstrapObserver();
+ return;
}
// Send the error code to telemetry
@@ -5189,6 +5238,7 @@ Downloader.prototype = {
var state = this._patch.state;
var shouldShowPrompt = false;
var shouldRegisterOnlineObserver = false;
+ var shouldRegisterBootstrapObserver = false;
var shouldRetrySoon = false;
var deleteActiveUpdate = false;
var retryTimeout = Services.prefs.getIntPref(
@@ -5266,7 +5316,18 @@ Downloader.prototype = {
);
shouldRegisterOnlineObserver = true;
deleteActiveUpdate = false;
-
+ } else if(_shouldRegisterBootstrapObserver(status)) {
+ // Register a bootstrap observer to try again.
+ // The bootstrap observer will continue the incremental download by
+ // calling downloadUpdate on the active update which continues
+ // downloading the file from where it was.
+ LOG("Downloader:onStopRequest - not bootstrapped, register bootstrap observer: true");
+ AUSTLMY.pingDownloadCode(
+ this.isCompleteUpdate,
+ AUSTLMY.DWNLD_RETRY_OFFLINE
+ );
+ shouldRegisterBootstrapObserver = true;
+ deleteActiveUpdate = false;
// Each of NS_ERROR_NET_TIMEOUT, ERROR_CONNECTION_REFUSED,
// NS_ERROR_NET_RESET and NS_ERROR_DOCUMENT_NOT_CACHED can be returned
// when disconnecting the internet while a download of a MAR is in
@@ -5384,7 +5445,7 @@ Downloader.prototype = {
// Only notify listeners about the stopped state if we
// aren't handling an internal retry.
- if (!shouldRetrySoon && !shouldRegisterOnlineObserver) {
+ if (!shouldRetrySoon && !shouldRegisterOnlineObserver && !shouldRegisterBootstrapObserver) {
// Make shallow copy in case listeners remove themselves when called.
var listeners = this._listeners.concat();
var listenerCount = listeners.length;
@@ -5532,6 +5593,9 @@ Downloader.prototype = {
if (shouldRegisterOnlineObserver) {
LOG("Downloader:onStopRequest - Registering online observer");
this.updateService._registerOnlineObserver();
+ } else if (shouldRegisterBootstrapObserver) {
+ LOG("Downloader:onStopRequest - Registering bootstrap observer");
+ this.updateService._registerBootstrapObserver();
} else if (shouldRetrySoon) {
LOG("Downloader:onStopRequest - Retrying soon");
this.updateService._consecutiveSocketErrors++;
diff --git a/toolkit/themes/shared/in-content/info-pages.inc.css b/toolkit/themes/shared/in-content/info-pages.inc.css
index 6943a3340e35..5b3c911a5aab 100644
--- a/toolkit/themes/shared/in-content/info-pages.inc.css
+++ b/toolkit/themes/shared/in-content/info-pages.inc.css
@@ -41,10 +41,11 @@ body.wide-container {
background-image: url("chrome://global/skin/icons/info.svg");
background-position: left 0;
background-repeat: no-repeat;
- background-size: 1.6em;
- margin-inline-start: -2.3em;
- padding-inline-start: 2.3em;
- font-size: 2.2em;
+ background-size: 3.0em;
+ margin-inline-start: -4.5em;
+ padding-inline-start: 4.5em;
+ margin-bottom: -2.0em;
+ font-size: 1.5em;
-moz-context-properties: fill;
fill: currentColor;
}
@@ -56,7 +57,10 @@ body.wide-container {
.title-text {
font-size: inherit;
- padding-bottom: 0.4em;
+ padding-bottom: 2.0em !important;
+ line-height: 1.0em;
+ font-weight: bold;
+ vertical-align: top;
}
@media (max-width: 970px) {
@@ -68,6 +72,7 @@ body.wide-container {
.title-text {
padding-top: 0;
+ vertical-align: middle !important;
}
}
diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js
index 2ff107b553b2..f8fa83574df7 100644
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/browser-window.js
@@ -70,6 +70,10 @@ function getGlobalScriptIncludes(scriptPath) {
let match = line.match(globalScriptsRegExp);
if (match) {
let sourceFile = match[1]
+ .replace(
+ "chrome://browser/content/torconnect/",
+ "browser/components/torconnect/content/"
+ )
.replace(
"chrome://browser/content/search/",
"browser/components/search/content/"
1
0

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

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

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

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

[tor-browser/tor-browser-78.13.0esr-11.0-2] TB4: Tor Browser's Firefox preference overrides.
by boklm@torproject.org 10 Aug '21
by boklm@torproject.org 10 Aug '21
10 Aug '21
commit 7e0d9b147124647a405357bfd73652f855c024a5
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Tue Sep 10 18:20:43 2013 -0700
TB4: Tor Browser's Firefox preference overrides.
This hack directly includes our preference changes in omni.ja.
Bug 18292: Staged updates fail on Windows
Temporarily disable staged updates on Windows.
Bug 18297: Use separate Noto JP,KR,SC,TC fonts
Bug 23404: Add Noto Sans Buginese to the macOS whitelist
Bug 23745: Set dom.indexedDB.enabled = true
Bug 13575: Disable randomised Firefox HTTP cache decay user tests.
(Fernando Fernandez Mancera <ffmancera(a)riseup.net>)
Bug 17252: Enable session identifiers with FPI
Session tickets and session identifiers were isolated
by OriginAttributes, so we can re-enable them by
allowing the default value (true) of
"security.ssl.disable_session_identifiers".
The pref "security.enable_tls_session_tickets" is obsolete
(removed in https://bugzilla.mozilla.org/917049)
Bug 14952: Enable http/2 and AltSvc
In Firefox, SPDY/HTTP2 now uses Origin Attributes for
isolation of connections, push streams, origin frames, etc.
That means we get first-party isolation provided
"privacy.firstparty.isolate" is true. So in this patch, we
stop overriding "network.http.spdy.enabled" and
"network.http.spdy.enabled.http2".
Alternate Services also use Origin Attributes for isolation.
So we stop overriding
"network.http.altsvc.enabled" and "network.http.altsvc.oe"
as well.
(All 4 of the abovementioned "network.http.*" prefs adopt
Firefox 60ESR's default value of true.)
However, we want to disable HTTP/2 push for now, so we
set "network.http.spdy.allow-push" to false.
"network.http.spdy.enabled.http2draft" was removed in Bug 1132357.
"network.http.sped.enabled.v2" was removed in Bug 912550.
"network.http.sped.enabled.v3" was removed in Bug 1097944.
"network.http.sped.enabled.v3-1" was removed in Bug 1248197.
Bug 26114: addons.mozilla.org is not special
* Don't expose navigator.mozAddonManager on any site
* Don't block NoScript from modifying addons.mozilla.org or other sites
Enable ReaderView mode again (#27281).
Bug 29916: Make sure enterprise policies are disabled
Bug 2874: Block Components.interfaces from content
Bug 26146: Spoof HTTP User-Agent header for desktop platforms
In Tor Browser 8.0, the OS was revealed in both the HTTP User-Agent
header and to JavaScript code via navigator.userAgent. To avoid
leaking the OS inside each HTTP request (which many web servers
log), always use the Windows 7 OS value in the desktop User-Agent
header. We continue to allow access to the actual OS via JavaScript,
since doing so improves compatibility with web applications such
as GitHub and Google Docs.
Bug 12885: Windows Jump Lists fail for Tor Browser
Jumplist entries are stored in a binary file in:
%APPDATA%\\Microsoft\Windows\Recent\CustomDestinations\
and has a name in the form
[a-f0-9]+.customDestinations-ms
The hex at the front is unique per app, and is ultimately derived from
something called the 'App User Model ID' (AUMID) via some unknown
hashing method. The AUMID is provided as a key when programmatically
creating, updating, and deleting a jumplist. The default behaviour in
firefox is for the installer to define an AUMID for an app, and save it
in the registry so that the jumplist data can be removed by the
uninstaller.
However, the Tor Browser does not set this (or any other) regkey during
installation, so this codepath fails and the app's AUMID is left
undefined. As a result the app's AUMID ends up being defined by
windows, but unknowable by Tor Browser. This unknown AUMID is used to
create and modify the jumplist, but the delete API requires that we
provide the app's AUMID explicitly. Since we don't know what the AUMID
is (since the expected regkey where it is normally stored does not
exist) jumplist deletion will fail and we will leave behind a mostly
empty customDestinations-ms file. The name of the file is derived from
the binary path, so an enterprising person could reverse engineer how
that hex name is calculated, and generate the name for Tor Browser's
default Desktop installation path to determine whether a person had
used Tor Browser in the past.
The 'taskbar.grouping.useprofile' option that is enabled by this patch
works around this AUMID problem by having firefox.exe create it's own
AUMID based on the profile path (rather than looking for a regkey). This
way, if a user goes in and enables and disables jumplist entries, the
backing store is properly deleted.
Unfortunately, all windows users currently have this file lurking in
the above mentioned directory and this patch will not remove it since it
was created with an unknown AUMID. However, another patch could be
written which goes to that directory and deletes any item containing the
'Tor Browser' string. See bug 28996.
Bug 31396: Disable indexedDB WebExtension storage backend.
Bug 30845: Make sure default themes and other internal extensions are enabled
Bug 28896: Enable extensions in private browsing by default
Bug 31065: Explicitly allow proxying localhost
Bug 31598: Enable letterboxing
Disable Presentation API everywhere
Bug 21549 - Use Firefox's WASM default pref. It is disabled at safer
security levels.
Bug 32321: Disable Mozilla's MitM pings
Bug 19890: Disable installation of system addons
By setting the URL to "" we make sure that already installed system
addons get deleted as well.
Bug 22548: Firefox downgrades VP9 videos to VP8.
On systems where H.264 is not available or no HWA, VP9 is preferred. But in Tor
Browser 7.0 all youtube videos are degraded to VP8.
This behaviour can be turned off by setting media.benchmark.vp9.threshold to 0.
All clients will get better experience and lower traffic, beause TBB doesn't
use "Use hardware acceleration when available".
Bug 25741 - TBA: Add mobile-override of 000-tor-browser prefs
Bug 16441: Suppress "Reset Tor Browser" prompt.
Bug 29120: Use the in-memory media cache and increase its maximum size.
Bug 33697: use old search config based on list.json
Bug 33855: Ensure that site-specific browser mode is disabled.
Bug 30682: Disable Intermediate CA Preloading.
Bug 40061: Omit the Windows default browser agent from the build
Bug 40140: Videos stop working with Tor Browser 10.0 on Windows
Bug 40322: Consider disabling network.connectivity-service.enabled
Bug 40408: Disallow SVG Context Paint in all web content
---
.eslintignore | 3 +
browser/app/profile/000-tor-browser.js | 646 ++++++++++++++++++++++++++
browser/app/profile/firefox.js | 6 +-
browser/installer/package-manifest.in | 1 +
browser/moz.build | 1 +
mobile/android/app/000-tor-browser-android.js | 47 ++
mobile/android/app/geckoview-prefs.js | 2 +
mobile/android/app/mobile.js | 4 +
mobile/android/app/moz.build | 1 +
taskcluster/ci/source-test/mozlint.yml | 2 +
10 files changed, 710 insertions(+), 3 deletions(-)
diff --git a/.eslintignore b/.eslintignore
index e0be1073894c..031ff26f1808 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -143,6 +143,9 @@ js/src/jsapi-tests/binast/
js/src/tests/
js/src/Y.js
+# uses `#include`
+mobile/android/app/000-tor-browser-android.js
+
# Uses `#filter substitution`
mobile/android/app/mobile.js
mobile/android/app/geckoview-prefs.js
diff --git a/browser/app/profile/000-tor-browser.js b/browser/app/profile/000-tor-browser.js
new file mode 100644
index 000000000000..3b3bbfd1889b
--- /dev/null
+++ b/browser/app/profile/000-tor-browser.js
@@ -0,0 +1,646 @@
+# Default Preferences
+# Tor Browser Bundle
+# Do not edit this file.
+
+// Please maintain unit tests at ./tbb-tests/browser_tor_TB4.js
+
+// Disable initial homepage notifications
+pref("browser.search.update", false);
+pref("browser.rights.3.shown", true);
+pref("browser.startup.homepage_override.mstone", "ignore");
+pref("startup.homepage_welcome_url", "");
+pref("startup.homepage_welcome_url.additional", "");
+
+// Set a generic, default URL that will be opened in a tab after an update.
+// Typically, this will not be used; instead, the <update> element within
+// each update manifest should contain attributes similar to:
+// actions="showURL"
+// openURL="https://blog.torproject.org/tor-browser-55a2-released"
+pref("startup.homepage_override_url", "https://blog.torproject.org/category/tags/tor-browser");
+
+// Try to nag a bit more about updates: Pop up a restart dialog an hour after the initial dialog
+pref("app.update.promptWaitTime", 3600);
+
+#ifdef XP_WIN
+// For now, disable staged updates on Windows (see #18292).
+pref("app.update.staging.enabled", false);
+#endif
+
+// Disable "Slow startup" warnings and associated disk history
+// (bug #13346)
+pref("browser.slowStartup.notificationDisabled", true);
+pref("browser.slowStartup.maxSamples", 0);
+pref("browser.slowStartup.samples", 0);
+
+// Disable the "Refresh" prompt that is displayed for stale profiles.
+pref("browser.disableResetPrompt", true);
+
+// Disk activity: Disable Browsing History Storage
+pref("browser.privatebrowsing.autostart", true);
+pref("browser.cache.disk.enable", false);
+pref("browser.cache.offline.enable", false);
+pref("permissions.memory_only", true);
+pref("network.cookie.lifetimePolicy", 2);
+pref("security.nocertdb", true);
+
+// Disk activity: TBB Directory Isolation
+pref("browser.download.useDownloadDir", false);
+pref("browser.shell.checkDefaultBrowser", false);
+pref("browser.download.manager.addToRecentDocs", false);
+
+// Misc privacy: Disk
+pref("signon.rememberSignons", false);
+pref("browser.formfill.enable", false);
+pref("signon.autofillForms", false);
+pref("browser.sessionstore.privacy_level", 2);
+// Use the in-memory media cache and increase its maximum size (#29120)
+pref("browser.privatebrowsing.forceMediaMemoryCache", true);
+pref("media.memory_cache_max_size", 16384);
+// Disable site-specific browsing to avoid sharing site icons with the OS.
+pref("browser.ssb.enabled", false);
+
+// Misc privacy: Remote
+pref("browser.send_pings", false);
+pref("geo.enabled", false);
+pref("geo.provider.network.url", "");
+pref("browser.search.suggest.enabled", false);
+pref("browser.safebrowsing.malware.enabled", false);
+pref("browser.safebrowsing.phishing.enabled", false);
+pref("browser.safebrowsing.downloads.enabled", false);
+pref("browser.safebrowsing.downloads.remote.enabled", false);
+pref("browser.safebrowsing.blockedURIs.enabled", false);
+pref("browser.safebrowsing.downloads.remote.url", "");
+pref("browser.safebrowsing.provider.google.updateURL", "");
+pref("browser.safebrowsing.provider.google.gethashURL", "");
+pref("browser.safebrowsing.provider.google4.updateURL", "");
+pref("browser.safebrowsing.provider.google4.gethashURL", "");
+pref("browser.safebrowsing.provider.mozilla.updateURL", "");
+pref("browser.safebrowsing.provider.mozilla.gethashURL", "");
+pref("extensions.ui.lastCategory", "addons://list/extension");
+pref("datareporting.healthreport.uploadEnabled", false);
+pref("datareporting.policy.dataSubmissionEnabled", false);
+// Make sure Unified Telemetry is really disabled, see: #18738.
+pref("toolkit.telemetry.unified", false);
+pref("toolkit.telemetry.enabled", false);
+#ifdef XP_WIN
+// Defense-in-depth: ensure that the Windows default browser agent will
+// not ping Mozilla if it is somehow present (we omit it at build time).
+pref("default-browser-agent.enabled", false);
+#endif
+pref("identity.fxaccounts.enabled", false); // Disable sync by default
+pref("services.sync.engine.prefs", false); // Never sync prefs, addons, or tabs with other browsers
+pref("services.sync.engine.addons", false);
+pref("services.sync.engine.tabs", false);
+pref("extensions.getAddons.cache.enabled", false); // https://blog.mozilla.org/addons/how-to-opt-out-of-add-on-metadata-updates/
+pref("browser.newtabpage.enabled", false);
+pref("browser.search.region", "US"); // The next two prefs disable GeoIP search lookups (#16254)
+pref("browser.search.geoip.url", "");
+pref("browser.fixup.alternate.enabled", false); // Bug #16783: Prevent .onion fixups
+// Make sure there is no Tracking Protection active in Tor Browser, see: #17898.
+pref("privacy.trackingprotection.enabled", false);
+pref("privacy.trackingprotection.pbmode.enabled", false);
+pref("privacy.trackingprotection.annotate_channels", false);
+pref("privacy.trackingprotection.cryptomining.enabled", false);
+pref("privacy.trackingprotection.fingerprinting.enabled", false);
+pref("privacy.trackingprotection.socialtracking.enabled", false);
+pref("privacy.socialtracking.block_cookies.enabled", false);
+pref("privacy.annotate_channels.strict_list.enabled", false);
+
+// Disable the Pocket extension (Bug #18886 and #31602)
+pref("extensions.pocket.enabled", false);
+pref("network.http.referer.hideOnionSource", true);
+
+// Disable use of WiFi location information
+pref("browser.region.network.scan", false);
+pref("browser.region.network.url", "");
+
+// Don't load Mozilla domains in a separate tab process
+pref("browser.tabs.remote.separatedMozillaDomains", "");
+
+// Avoid DNS lookups on search terms
+pref("browser.urlbar.dnsResolveSingleWordsAfterSearch", 0);
+
+// Disable about:newtab and "first run" experiments
+pref("messaging-system.rsexperimentloader.enabled", false);
+pref("trailhead.firstrun.branches", "");
+
+// Clear the list of trusted recursive resolver services
+pref("network.trr.resolvers", "");
+
+// Disable crlite
+pref("security.pki.crlite_mode", 0);
+
+// Disable website password breach alerts
+pref("signon.management.page.breach-alerts.enabled", false);
+pref("extensions.fxmonitor.enabled", false);
+
+// Remove mobile app tracking URLs
+pref("signon.management.page.mobileAndroidURL", "");
+pref("signon.management.page.mobileAppleURL", "");
+
+// Disable ServiceWorkers and push notifications by default
+pref("dom.serviceWorkers.enabled", false);
+pref("dom.push.enabled", false);
+
+// Fingerprinting
+pref("webgl.disable-extensions", true);
+pref("webgl.disable-fail-if-major-performance-caveat", true);
+pref("webgl.enable-webgl2", false);
+pref("gfx.downloadable_fonts.fallback_delay", -1);
+pref("browser.startup.homepage_override.buildID", "20100101");
+pref("browser.link.open_newwindow.restriction", 0); // Bug 9881: Open popups in new tabs (to avoid fullscreen popups)
+// Set video VP9 to 0 for everyone (bug 22548)
+pref("media.benchmark.vp9.threshold", 0);
+pref("dom.enable_resource_timing", false); // Bug 13024: To hell with this API
+pref("privacy.resistFingerprinting", true);
+pref("privacy.resistFingerprinting.block_mozAddonManager", true); // Bug 26114
+pref("dom.webaudio.enabled", false); // Bug 13017: Disable Web Audio API
+pref("dom.w3c_touch_events.enabled", 0); // Bug 10286: Always disable Touch API
+pref("dom.w3c_pointer_events.enabled", false);
+pref("dom.vr.enabled", false); // Bug 21607: Disable WebVR for now
+// Disable randomised Firefox HTTP cache decay user test groups (Bug: 13575)
+pref("security.webauth.webauthn", false); // Bug 26614: Disable Web Authentication API for now
+// Disable intermediate preloading (Bug 30682)
+pref("security.remote_settings.intermediates.enabled", false);
+// Bug 2874: Block Components.interfaces from content
+pref("dom.use_components_shim", false);
+// Enable letterboxing
+pref("privacy.resistFingerprinting.letterboxing", true);
+// Disable network information API everywhere. It gets spoofed in bug 1372072
+// but, alas, the behavior is inconsistent across platforms, see:
+// https://trac.torproject.org/projects/tor/ticket/27268#comment:19. We should
+// not leak that difference if possible.
+pref("dom.netinfo.enabled", false);
+pref("network.http.referer.defaultPolicy", 2); // Bug 32948: Make referer behavior consistent regardless of private browing mode status
+pref("media.videocontrols.picture-in-picture.enabled", false); // Bug 40148: disable until audited in #40147
+
+// Third party stuff
+pref("privacy.firstparty.isolate", true); // Always enforce first party isolation
+pref("network.cookie.cookieBehavior", 1);
+pref("network.http.spdy.allow-push", false); // Disabled for now. See https://bugs.torproject.org/27127
+pref("network.predictor.enabled", false); // Temporarily disabled. See https://bugs.torproject.org/16633
+
+// Proxy and proxy security
+pref("network.proxy.socks", "127.0.0.1");
+pref("network.proxy.socks_port", 9150);
+pref("network.proxy.socks_remote_dns", true);
+pref("network.proxy.no_proxies_on", ""); // For fingerprinting and local service vulns (#10419)
+pref("network.proxy.allow_hijacking_localhost", true); // Allow proxies for localhost (#31065)
+pref("network.proxy.type", 1);
+pref("network.security.ports.banned", "9050,9051,9150,9151");
+pref("network.dns.disabled", true); // This should cover the #5741 patch for DNS leaks
+pref("network.dns.disablePrefetch", true);
+pref("network.protocol-handler.external-default", false);
+pref("network.protocol-handler.external.mailto", false);
+pref("network.protocol-handler.external.news", false);
+pref("network.protocol-handler.external.nntp", false);
+pref("network.protocol-handler.external.snews", false);
+pref("network.protocol-handler.warn-external.mailto", true);
+pref("network.protocol-handler.warn-external.news", true);
+pref("network.protocol-handler.warn-external.nntp", true);
+pref("network.protocol-handler.warn-external.snews", true);
+// Make sure we don't have any GIO supported protocols (defense in depth
+// measure)
+pref("network.gio.supported-protocols", "");
+pref("plugin.disable", true); // Disable to search plugins on first start
+pref("plugin.state.flash", 0); // Disable for defense-in-depth
+pref("media.peerconnection.enabled", false); // Disable WebRTC interfaces
+// Disables media devices but only if `media.peerconnection.enabled` is set to
+// `false` as well. (see bug 16328 for this defense-in-depth measure)
+pref("media.navigator.enabled", false);
+// GMPs: We make sure they don't show up on the Add-on panel and confuse users.
+// And the external update/donwload server must not get pinged. We apply a
+// clever solution for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=769716.
+pref("media.gmp-provider.enabled", false);
+pref("media.gmp-manager.url.override", "data:text/plain,");
+// Since ESR52 it is not enough anymore to block pinging the GMP update/download
+// server. There is a local fallback that must be blocked now as well. See:
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1267495.
+pref("media.gmp-manager.updateEnabled", false);
+// Mozilla is relying on preferences to make sure no DRM blob is downloaded and
+// run. Even though those prefs should be set correctly by specifying
+// --disable-eme (which we do), we disable all of them here as well for defense
+// in depth (see bug 16285 for more details).
+pref("browser.eme.ui.enabled", false);
+pref("media.gmp-widevinecdm.visible", false);
+pref("media.gmp-widevinecdm.enabled", false);
+pref("media.eme.enabled", false);
+pref("media.mediadrm-widevinecdm.visible", false);
+// WebIDE can bypass proxy settings for remote debugging. It also downloads
+// some additional addons that we have not reviewed. Turn all that off.
+pref("devtools.webide.autoinstallADBExtension", false);
+pref("devtools.webide.enabled", false);
+// The in-browser debugger for debugging chrome code is not coping with our
+// restrictive DNS look-up policy. We use "127.0.0.1" instead of "localhost" as
+// a workaround. See bug 16523 for more details.
+pref("devtools.debugger.chrome-debugging-host", "127.0.0.1");
+// Disable using UNC paths (bug 26424 and Mozilla's bug 1413868)
+pref("network.file.disable_unc_paths", true);
+// Enhance our treatment of file:// to avoid proxy bypasses (see Mozilla's bug
+// 1412081)
+pref("network.file.path_blacklist", "/net");
+// Make sure no enterprise policy can interfere with our proxy settings, see
+// #29916.
+pref("browser.policies.testing.disallowEnterprise", true);
+
+// Security slider
+pref("svg.in-content.enabled", true);
+pref("mathml.disabled", false);
+
+// Bug 40408
+pref("svg.context-properties.content.allowed-domains", "");
+
+// Network and performance
+pref("security.ssl.enable_false_start", true);
+pref("network.http.connection-retry-timeout", 0);
+pref("network.http.max-persistent-connections-per-proxy", 256);
+pref("network.manage-offline-status", false);
+// No need to leak things to Mozilla, see bug 21790 and tor-browser#40322
+pref("network.captive-portal-service.enabled", false);
+pref("network.connectivity-service.enabled", false);
+// As a "defense in depth" measure, configure an empty push server URL (the
+// DOM Push features are disabled by default via other prefs).
+pref("dom.push.serverURL", "");
+
+// Extension support
+pref("extensions.autoDisableScopes", 0);
+pref("extensions.bootstrappedAddons", "{}");
+pref("extensions.checkCompatibility.4.*", false);
+pref("extensions.databaseSchema", 3);
+pref("extensions.enabledAddons", "https-everywhere%40eff.org:3.1.4,%7B73a6fe31-595d-460b-a920-fcc0f8843232%7D:2.6.6.1,torbutton%40torproject.org:1.5.2,ubufox%40ubuntu.com:2.6,%7B972ce4c6-7e08-4474-a285-3208198ce6fd%7D:17.0.5");
+pref("extensions.enabledItems", "langpack-en-US@firefox.mozilla.org:,{73a6fe31-595d-460b-a920-fcc0f8843232}:1.9.9.57,{e0204bd5-9d31-402b-a99d-a6aa8ffebdca}:1.2.4,{972ce4c6-7e08-4474-a285-3208198ce6fd}:3.5.8");
+pref("extensions.enabledScopes", 5); // AddonManager.SCOPE_PROFILE=1 | AddonManager.SCOPE_APPLICATION=4
+pref("extensions.pendingOperations", false);
+pref("xpinstall.whitelist.add", "");
+pref("xpinstall.whitelist.add.36", "");
+// We don't know what extensions Mozilla is advertising to our users and we
+// don't want to have some random Google Analytics script running either on the
+// about:addons page, see bug 22073, 22900 and 31601.
+pref("extensions.getAddons.showPane", false);
+pref("extensions.htmlaboutaddons.recommendations.enabled", false);
+// Show our legacy extensions directly on about:addons and get rid of the
+// warning for the default theme.
+pref("extensions.legacy.exceptions", "{972ce4c6-7e08-4474-a285-3208198ce6fd},torbutton(a)torproject.org");
+// Bug 26114: Allow NoScript to access addons.mozilla.org etc.
+pref("extensions.webextensions.restrictedDomains", "");
+// Bug 28896: Make sure our bundled WebExtensions are running in Private Browsing Mode
+pref("extensions.allowPrivateBrowsingByDefault", true);
+
+// Toolbar layout
+pref("browser.uiCustomization.state", "{\"placements\":{\"widget-overflow-fixed-list\":[],\"PersonalToolbar\":[\"personal-bookmarks\"],\"nav-bar\":[\"back-button\",\"forward-button\",\"stop-reload-button\",\"urlbar-container\",\"torbutton-button\",\"security-level-button\",\"downloads-button\"],\"TabsToolbar\":[\"tabbrowser-tabs\",\"new-tab-button\",\"alltabs-button\"],\"toolbar-menubar\":[\"menubar-items\"],\"PanelUI-contents\":[\"home-button\",\"edit-controls\",\"zoom-controls\",\"new-window-button\",\"save-page-button\",\"print-button\",\"bookmarks-menu-button\",\"history-panelmenu\",\"find-button\",\"preferences-button\",\"add-ons-button\",\"developer-button\"],\"addon-bar\":[\"addonbar-closebutton\",\"status-bar\"]},\"seen\":[\"developer-button\",\"https-everywhere-eff_eff_org-browser-action\",\"_73a6fe31-595d-460b-a920-fcc0f8843232_-browser-action\"],\"dirtyAreaCache\":[\"PersonalToolbar\",\"nav-bar\",\"TabsToolbar\",\"toolbar-menubar\"],\"currentVersion\":14,\"newElementCount
\":1}");
+
+// Putting the search engine prefs into this file to fix #11236.
+// Default search engine
+pref("browser.search.defaultenginename", "Search");
+
+// Search engine order (order displayed in the search bar dropdown)
+// Somewhat surprisingly we get some random behavior if we specify more than
+// two search engines as below. See
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1126722 for details.
+pref("browser.search.order.extra.1", "Search");
+pref("browser.search.order.extra.2", "YouTube");
+
+// Enforce certificate pinning, see: https://bugs.torproject.org/16206
+pref("security.cert_pinning.enforcement_level", 2);
+
+// Don't allow MitM via Microsoft Family Safety, see bug 21686
+pref("security.family_safety.mode", 0);
+
+// Don't allow MitM via enterprise roots, see bug 30681
+pref("security.enterprise_roots.enabled", false);
+
+// Don't ping Mozilla for MitM detection, see bug 32321
+pref("security.certerrors.mitm.priming.enabled", false);
+
+// Disable the language pack signing check for now on macOS, see #31942
+#ifdef XP_MACOSX
+pref("extensions.langpacks.signatures.required", false);
+#endif
+
+// Avoid report TLS errors to Mozilla. We might want to repurpose this feature
+// one day to help detecting bad relays (which is bug 19119). For now we just
+// hide the checkbox, see bug 22072.
+pref("security.ssl.errorReporting.enabled", false);
+
+// Workaround for https://bugs.torproject.org/13579. Progress on
+// `about:downloads` is only shown if the following preference is set to `true`
+// in case the download panel got removed from the toolbar.
+pref("browser.download.panel.shown", true);
+
+// Treat .onions as secure
+pref("dom.securecontext.whitelist_onions", true);
+
+// Disable special URL bar behaviors
+pref("browser.urlbar.suggest.topsites", false);
+pref("browser.urlbar.update1.interventions", false);
+pref("browser.urlbar.update1.searchTips", false);
+
+// Skip checking omni.ja and other files for corruption since the result
+// is only reported via telemetry (which is disabled).
+pref("corroborator.enabled", false);
+
+// Having the RDD Opus option enabled on Windows breaks videos for us.
+// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1667360 and
+// tor-browser#40140.
+#ifdef XP_WIN
+pref("media.rdd-opus.enabled", false);
+#endif
+
+// prefs to disable jump-list entries in the taskbar on Windows (see bug #12885)
+#ifdef XP_WIN
+// this pref changes the app's set AUMID to be dependent on the profile path, rather than
+// attempting to read it from the registry; this is necessary so that the file generated
+// by the jumplist system can be properly deleted if it is disabled
+pref("taskbar.grouping.useprofile", true);
+pref("browser.taskbar.lists.enabled", false);
+pref("browser.taskbar.lists.frequent.enabled", false);
+pref("browser.taskbar.lists.tasks.enabled", false);
+pref("browser.taskbar.lists.recent.enabled", false);
+#endif
+
+// Disable Presentation API
+pref("dom.presentation.controller.enabled", false);
+pref("dom.presentation.enabled", false);
+pref("dom.presentation.discoverable", false);
+pref("dom.presentation.discoverable.encrypted", false);
+pref("dom.presentation.discovery.enabled", false);
+pref("dom.presentation.receiver.enabled", false);
+
+pref("dom.audiochannel.audioCompeting", false);
+pref("dom.audiochannel.mediaControl", false);
+
+#expand pref("torbrowser.version", __TOR_BROWSER_VERSION_QUOTED__);
+
+// Old torbutton prefs
+
+// debug prefs
+pref("extensions.torbutton.loglevel",4);
+pref("extensions.torbutton.logmethod",1); // 0=stdout, 1=errorconsole, 2=debuglog
+
+// Display prefs
+pref("extensions.torbutton.display_circuit", true);
+pref("extensions.torbutton(a)torproject.org.description", "chrome://torbutton/locale/torbutton.properties");
+pref("extensions.torbutton.updateNeeded", false);
+
+// Tor check and proxy prefs
+pref("extensions.torbutton.test_enabled",true);
+pref("extensions.torbutton.test_url","https://check.torproject.org/?TorButton=true");
+pref("extensions.torbutton.local_tor_check",true);
+pref("extensions.torbutton.versioncheck_url","https://www.torproject.org/projects/torbrowser/RecommendedTBBVersions");
+pref("extensions.torbutton.versioncheck_enabled",true);
+pref("extensions.torbutton.use_nontor_proxy",false);
+
+// State prefs:
+pref("extensions.torbutton.startup",false);
+pref("extensions.torbutton.inserted_button",false);
+pref("extensions.torbutton.inserted_security_level",false);
+
+// This is only used when letterboxing is disabled.
+// See #7255 for details. We display the warning three times to make sure the
+// user did not click on it by accident.
+pref("extensions.torbutton.maximize_warnings_remaining", 3);
+
+// Security prefs:
+pref("extensions.torbutton.clear_http_auth",true);
+pref("extensions.torbutton.close_newnym",true);
+pref("extensions.torbutton.resize_new_windows",false);
+pref("extensions.torbutton.startup_state", 2); // 0=non-tor, 1=tor, 2=last
+pref("extensions.torbutton.tor_memory_jar",false);
+pref("extensions.torbutton.nontor_memory_jar",false);
+pref("extensions.torbutton.launch_warning",true);
+
+// Opt out of Firefox addon pings:
+// https://developer.mozilla.org/en/Addons/Working_with_AMO
+pref("extensions.torbutton(a)torproject.org.getAddons.cache.enabled", false);
+
+// Security Slider
+pref("extensions.torbutton.security_slider", 4);
+pref("extensions.torbutton.security_custom", false);
+
+pref("extensions.torbutton.confirm_plugins", true);
+pref("extensions.torbutton.confirm_newnym", true);
+
+pref("extensions.torbutton.noscript_inited", false);
+pref("extensions.torbutton.noscript_persist", false);
+
+// Browser home page:
+pref("browser.startup.homepage", "about:tor");
+
+// This pref specifies an ad-hoc "version" for various pref update hacks we need to do
+pref("extensions.torbutton.pref_fixup_version", 0);
+
+// If we are bundling fonts, whitelist those bundled fonts, and restrict system fonts to a selection.
+
+#ifdef MOZ_BUNDLED_FONTS
+
+#ifdef XP_MACOSX
+pref("font.system.whitelist", "AppleGothic, Apple Color Emoji, Arial, Courier, Geneva, Georgia, Heiti TC, Helvetica, Helvetica Neue, .Helvetica Neue DeskInterface, Hiragino Kaku Gothic ProN, Lucida Grande, Monaco, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Tibetan, Noto Sans Yi, STHeiti, STIX Math, Tahoma, Thonburi, Times, Times New Roman, Verdana");
+pref("font.name-list.cursive.x-unicode", "Apple Chancery, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Tibetan, Noto Sans Yi");
+pref("font.name-list.fantasy.x-unicode", "Papyrus, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Tibetan, Noto Sans Yi");
+pref("font.name-list.monospace.x-unicode", "Courier, Arial, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Tibetan, Noto Sans Yi");
+pref("font.name-list.sans-serif.x-unicode", "Helvetica, Tahoma, Arial, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Tibetan, Noto Sans Yi");
+pref("font.name-list.serif.x-unicode", "Times, Arial, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Tibetan, Noto Sans Yi");
+pref("font.name.cursive.ar", "Arial");
+pref("font.name.fantasy.ar", "Arial");
+pref("font.name.monospace.ar", "Arial");
+pref("font.name.sans-serif.ar", "Arial");
+#endif
+
+#ifdef XP_WIN
+pref("font.system.whitelist", "Arial, Batang, 바탕, Cambria Math, Courier New, Euphemia, Gautami, Georgia, Gulim, 굴림, GulimChe, 굴림체, Iskoola Pota, Kalinga, Kartika, Latha, Lucida Console, MS Gothic, MS ゴシック, MS Mincho, MS 明朝, MS PGothic, MS Pゴシック, MS PMincho, MS P明朝, MV Boli, Malgun Gothic, Mangal, Meiryo, Meiryo UI, Microsoft Himalaya, Microsoft JhengHei, Microsoft JhengHei UI, Microsoft YaHei, 微软雅黑, Microsoft YaHei UI, MingLiU, 細明體, Noto Sans Buginese, Noto Sans Khmer, Noto Sans Lao, Noto Sans Myanmar, Noto Sans Yi, Nyala, PMingLiU, 新細明體, Plantagenet Cherokee, Raavi, Segoe UI, Shruti, SimSun, 宋体, Sylfaen, Tahoma, Times New Roman, Tunga, Verdana, Vrinda, Yu Gothic UI");
+#endif
+
+#ifdef XP_LINUX
+pref("font.default.lo", "Noto Sans Lao");
+pref("font.default.my", "Noto Sans Myanmar");
+pref("font.default.x-western", "sans-serif");
+pref("font.name-list.cursive.ar", "Noto Naskh Arabic, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.cursive.he", "Noto Sans Hebrew, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.cursive.x-cyrillic", "Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.cursive.x-unicode", "Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.cursive.x-western", "Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.fantasy.ar", "Noto Naskh Arabic, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.fantasy.el", "Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.fantasy.he", "Noto Sans Hebrew, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.fantasy.x-cyrillic", "Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.fantasy.x-unicode", "Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.fantasy.x-western", "Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.ar", "Noto Naskh Arabic, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.el", "Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.he", "Noto Sans Hebrew, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.ja", "Noto Sans JP Regular, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.ko", "Noto Sans KR Regular, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.th", "Noto Sans Thai, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-armn", "Noto Sans Armenian, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-beng", "Noto Sans Bengali, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-cyrillic", "Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-devanagari", "Noto Sans Devanagari, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-ethi", "Noto Sans Ethiopic, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-geor", "Noto Sans Georgian, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-gujr", "Noto Sans Gujarati, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-guru", "Noto Sans Gurmukhi, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-khmr", "Noto Sans Khmer, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-knda", "Noto Sans Kannada, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-mlym", "Noto Sans Malayalam, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-orya", "Noto Sans Oriya, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-sinh", "Noto Sans Sinhala, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-tamil", "Noto Sans Tamil, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-telu", "Noto Sans Telugu, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-tibt", "Noto Sans Tibetan, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-unicode", "Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.x-western", "Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.zh-CN", "Noto Sans SC Regular, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.zh-HK", "Noto Sans TC Regular, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.monospace.zh-TW", "Noto Sans TC Regular, Cousine, Courier, Courier New, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.ar", "Noto Naskh Arabic, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.el", "Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.he", "Noto Sans Hebrew, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.ja", "Noto Sans JP Regular, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.ko", "Noto Sans KR Regular, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.th", "Noto Sans Thai, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-armn", "Noto Sans Armenian, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-beng", "Noto Sans Bengali, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-cyrillic", "Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-devanagari", "Noto Sans Devanagari, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-ethi", "Noto Sans Ethiopic, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-geor", "Noto Sans Georgian, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-gujr", "Noto Sans Gujarati, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-guru", "Noto Sans Gurmukhi, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-khmr", "Noto Sans Khmer, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-knda", "Noto Sans Kannada, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-mlym", "Noto Sans Malayalam, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-orya", "Noto Sans Oriya, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-sinh", "Noto Sans Sinhala, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-tamil", "Noto Sans Tamil, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-telu", "Noto Sans Telugu, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-tibt", "Noto Sans Tibetan, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-unicode", "Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.x-western", "Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.zh-CN", "Noto Sans SC Regular, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.zh-HK", "Noto Sans TC Regular, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.sans-serif.zh-TW", "Noto Sans TC Regular, Arimo, Arial, Verdana, Noto Naskh Arabic, Noto Sans Armenian, Noto Sans Bengali, Noto Sans Buginese, Noto Sans JP Regular, Noto Sans KR Regular, Noto Sans SC Regular, Noto Sans TC Regular, Noto Sans Canadian Aboriginal, Noto Sans Cherokee, Noto Sans Devanagari, Noto Sans Ethiopic, Noto Sans Georgian, Noto Sans Gujarati, Noto Sans Gurmukhi, Noto Sans Hebrew, Noto Sans Kannada, Noto Sans Khmer, Noto Sans Lao, Noto Sans Malayalam, Noto Sans Mongolian, Noto Sans Myanmar, Noto Sans Oriya, Noto Sans Sinhala, Noto Sans Tamil, Noto Sans Telugu, Noto Sans Thaana, Noto Sans Thai, Noto Sans Tibetan, Noto Sans Yi, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.ar", "Noto Naskh Arabic, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.el", "Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.he", "Tinos, Georgia, Noto Sans Hebrew, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.ja", "Noto Sans JP Regular, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.ko", "Noto Sans KR Regular, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.th", "Noto Serif Thai, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-armn", "Noto Serif Armenian, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-beng", "Noto Sans Bengali, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-cyrillic", "Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-devanagari", "Noto Sans Devanagari, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-ethi", "Noto Sans Ethiopic, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-geor", "Noto Sans Georgian, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-gujr", "Noto Sans Gujarati, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-guru", "Noto Sans Gurmukhi, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-khmr", "Noto Serif Khmer, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-knda", "Noto Sans Kannada, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-mlym", "Noto Sans Malayalam, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-orya", "Noto Sans Oriya, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-sinh", "Noto Sans Sinhala, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-tamil", "Noto Sans Tamil, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-telu", "Noto Sans Telugu, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-tibt", "Noto Sans Tibetan, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-unicode", "Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.x-western", "Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.zh-CN", "Noto Sans SC Regular, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.zh-HK", "Noto Sans TC Regular, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name-list.serif.zh-TW", "Noto Sans TC Regular, Tinos, Georgia, Noto Serif Armenian, Noto Serif Khmer, Noto Serif Lao, Noto Serif Thai");
+pref("font.name.cursive.ar", "Noto Naskh Arabic");
+pref("font.name.cursive.el", "Tinos, Georgia");
+pref("font.name.cursive.he", "Noto Sans Hebrew");
+pref("font.name.cursive.x-cyrillic", "Tinos, Georgia");
+pref("font.name.cursive.x-unicode", "Tinos, Georgia");
+pref("font.name.cursive.x-western", "Tinos, Georgia");
+pref("font.name.fantasy.ar", "Noto Naskh Arabic");
+pref("font.name.fantasy.el", "Tinos, Georgia");
+pref("font.name.fantasy.he", "Noto Sans Hebrew");
+pref("font.name.fantasy.x-cyrillic", "Tinos, Georgia");
+pref("font.name.fantasy.x-unicode", "Tinos, Georgia");
+pref("font.name.fantasy.x-western", "Tinos, Georgia");
+pref("font.name.monospace.ar", "Noto Naskh Arabic");
+pref("font.name.monospace.el", "Tinos, Georgia");
+pref("font.name.monospace.he", "Noto Sans Hebrew");
+pref("font.name.monospace.ja", "Noto Sans JP Regular");
+pref("font.name.monospace.ko", "Noto Sans KR Regular");
+pref("font.name.monospace.my", "Noto Sans Myanmar");
+pref("font.name.monospace.th", "Noto Sans Thai");
+pref("font.name.monospace.x-armn", "Noto Sans Armenian");
+pref("font.name.monospace.x-beng", "Noto Sans Bengali");
+pref("font.name.monospace.x-cyrillic", "Cousine, Courier, Courier New");
+pref("font.name.monospace.x-devanagari", "Noto Sans Devanagari");
+pref("font.name.monospace.x-ethi", "Noto Sans Ethiopic");
+pref("font.name.monospace.x-geor", "Noto Sans Georgian");
+pref("font.name.monospace.x-gujr", "Noto Sans Gujarati");
+pref("font.name.monospace.x-guru", "Noto Sans Gurmukhi");
+pref("font.name.monospace.x-khmr", "Noto Sans Khmer");
+pref("font.name.monospace.x-knda", "Noto Sans Kannada");
+pref("font.name.monospace.x-mlym", "Noto Sans Malayalam");
+pref("font.name.monospace.x-orya", "Noto Sans Oriya");
+pref("font.name.monospace.x-sinh", "Noto Sans Sinhala");
+pref("font.name.monospace.x-tamil", "Noto Sans Tamil");
+pref("font.name.monospace.x-telu", "Noto Sans Telugu");
+pref("font.name.monospace.x-tibt", "Noto Sans Tibetan");
+pref("font.name.monospace.x-unicode", "Cousine, Courier, Courier New");
+pref("font.name.monospace.x-western", "Cousine, Courier, Courier New");
+pref("font.name.monospace.zh-CN", "Noto Sans SC Regular");
+pref("font.name.monospace.zh-HK", "Noto Sans TC Regular");
+pref("font.name.monospace.zh-TW", "Noto Sans TC Regular");
+pref("font.name.sans-serif.ar", "Noto Naskh Arabic");
+pref("font.name.sans-serif.el", "Arimo, Arial, Verdana");
+pref("font.name.sans-serif.he", "Noto Sans Hebrew");
+pref("font.name.sans-serif.ja", "Noto Sans JP Regular");
+pref("font.name.sans-serif.ko", "Noto Sans KR Regular");
+pref("font.name.sans-serif.th", "Noto Sans Thai");
+pref("font.name.sans-serif.x-armn", "Noto Sans Armenian");
+pref("font.name.sans-serif.x-beng", "Noto Sans Bengali");
+pref("font.name.sans-serif.x-cyrillic", "Arimo, Arial, Verdana");
+pref("font.name.sans-serif.x-devanagari", "Noto Sans Devanagari");
+pref("font.name.sans-serif.x-ethi", "Noto Sans Ethiopic");
+pref("font.name.sans-serif.x-geor", "Noto Sans Georgian");
+pref("font.name.sans-serif.x-gujr", "Noto Sans Gujarati");
+pref("font.name.sans-serif.x-guru", "Noto Sans Gurmukhi");
+pref("font.name.sans-serif.x-khmr", "Noto Sans Khmer");
+pref("font.name.sans-serif.x-knda", "Noto Sans Kannada");
+pref("font.name.sans-serif.x-mlym", "Noto Sans Malayalam");
+pref("font.name.sans-serif.x-orya", "Noto Sans Oriya");
+pref("font.name.sans-serif.x-sinh", "Noto Sans Sinhala");
+pref("font.name.sans-serif.x-tamil", "Noto Sans Tamil");
+pref("font.name.sans-serif.x-telu", "Noto Sans Telugu");
+pref("font.name.sans-serif.x-tibt", "Noto Sans Tibetan");
+pref("font.name.sans-serif.x-unicode", "Arimo, Arial, Verdana");
+pref("font.name.sans-serif.x-western", "Arimo, Arial, Verdana");
+pref("font.name.sans-serif.zh-CN", "Noto Sans SC Regular");
+pref("font.name.sans-serif.zh-HK", "Noto Sans TC Regular");
+pref("font.name.sans-serif.zh-TW", "Noto Sans TC Regular");
+pref("font.name.sans.my", "Noto Sans Myanmar");
+pref("font.name.serif.ar", "Noto Naskh Arabic");
+pref("font.name.serif.el", "Tinos, Georgia");
+pref("font.name.serif.he", "Noto Sans Hebrew");
+pref("font.name.serif.ja", "Noto Sans JP Regular");
+pref("font.name.serif.ko", "Noto Sans KR Regular");
+pref("font.name.serif.my", "Noto Sans Myanmar");
+pref("font.name.serif.th", "Noto Serif Thai");
+pref("font.name.serif.x-armn", "Noto Serif Armenian");
+pref("font.name.serif.x-beng", "Noto Sans Bengali");
+pref("font.name.serif.x-cyrillic", "Tinos, Georgia");
+pref("font.name.serif.x-devanagari", "Noto Sans Devanagari");
+pref("font.name.serif.x-ethi", "Noto Sans Ethiopic");
+pref("font.name.serif.x-geor", "Noto Sans Georgian");
+pref("font.name.serif.x-gujr", "Noto Sans Gujarati");
+pref("font.name.serif.x-guru", "Noto Sans Gurmukhi");
+pref("font.name.serif.x-khmr", "Noto Serif Khmer");
+pref("font.name.serif.x-knda", "Noto Sans Kannada");
+pref("font.name.serif.x-mlym", "Noto Sans Malayalam");
+pref("font.name.serif.x-orya", "Noto Sans Oriya");
+pref("font.name.serif.x-sinh", "Noto Sans Sinhala");
+pref("font.name.serif.x-tamil", "Noto Sans Tamil");
+pref("font.name.serif.x-telu", "Noto Sans Telugu");
+pref("font.name.serif.x-tibt", "Noto Sans Tibetan");
+pref("font.name.serif.x-unicode", "Tinos, Georgia");
+pref("font.name.serif.x-western", "Tinos, Georgia");
+pref("font.name.serif.zh-CN", "Noto Sans SC Regular");
+pref("font.name.serif.zh-HK", "Noto Sans TC Regular");
+pref("font.name.serif.zh-TW", "Noto Sans TC Regular");
+#endif
+#endif
diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
index 479c68efdd8c..b04fd2dd30f0 100644
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -53,9 +53,9 @@ pref("extensions.recommendations.themeRecommendationUrl", "https://color.firefox
pref("extensions.update.autoUpdateDefault", true);
-// Check AUS for system add-on updates.
-pref("extensions.systemAddon.update.url", "https://aus5.mozilla.org/update/3/SystemAddons/%VERSION%/%BUILD_ID%/%BUILD_…");
-pref("extensions.systemAddon.update.enabled", true);
+// No AUS check for system add-on updates for Tor Browser users.
+pref("extensions.systemAddon.update.url", "");
+pref("extensions.systemAddon.update.enabled", false);
// Disable add-ons that are not installed by the user in all scopes by default.
// See the SCOPE constants in AddonManager.jsm for values to use here.
diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in
index e011b74cc4b4..7deaf1b51f9a 100644
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -292,6 +292,7 @@
@RESPATH@/browser/defaults/settings/pinning
@RESPATH@/browser/defaults/settings/main
@RESPATH@/browser/defaults/settings/security-state
+@RESPATH@/browser/@PREF_DIR@/000-tor-browser.js
; Warning: changing the path to channel-prefs.js can cause bugs (Bug 756325)
; Technically this is an app pref file, but we are keeping it in the original
diff --git a/browser/moz.build b/browser/moz.build
index cfbfea4f31f2..19977e036fba 100644
--- a/browser/moz.build
+++ b/browser/moz.build
@@ -53,6 +53,7 @@ if CONFIG['MOZ_GPSD']:
# These files are specified in this moz.build to pick up DIST_SUBDIR as set in
# this directory, which is un-set in browser/app.
JS_PREFERENCE_PP_FILES += [
+ 'app/profile/000-tor-browser.js',
'app/profile/firefox.js',
]
FINAL_TARGET_FILES.defaults += ['app/permissions']
diff --git a/mobile/android/app/000-tor-browser-android.js b/mobile/android/app/000-tor-browser-android.js
new file mode 100644
index 000000000000..61c8a0cd7fa1
--- /dev/null
+++ b/mobile/android/app/000-tor-browser-android.js
@@ -0,0 +1,47 @@
+// Import all prefs from the canonical file
+// We override mobile-specific prefs below
+// Tor Browser for Android
+// Do not edit this file.
+
+#include ../../../browser/app/profile/000-tor-browser.js
+
+// Space separated list of URLs that are allowed to send objects (instead of
+// only strings) through webchannels. This list is duplicated in browser/app/profile/firefox.js
+pref("webchannel.allowObject.urlWhitelist", "");
+
+// Disable browser auto updaters
+pref("app.update.auto", false);
+pref("browser.startup.homepage_override.mstone", "ignore");
+
+// Clear data on quit
+pref("privacy.clearOnShutdown.cache", true);
+pref("privacy.clearOnShutdown.cookies",true);
+pref("privacy.clearOnShutdown.downloads",true);
+pref("privacy.clearOnShutdown.formdata",true);
+pref("privacy.clearOnShutdown.history",true);
+pref("privacy.clearOnShutdown.offlineApps",true);
+pref("privacy.clearOnShutdown.passwords",true);
+pref("privacy.clearOnShutdown.sessions",true);
+pref("privacy.clearOnShutdown.siteSettings",true);
+
+// controls if we want camera support
+pref("media.realtime_decoder.enabled", false);
+
+// Enable touch events on Android (highlighting text, etc)
+pref("dom.w3c_touch_events.enabled", 2);
+
+// Ensure that pointer events are disabled
+pref("dom.w3c_pointer_events.multiprocess.android.enabled", false);
+
+// No HLS support for now due to browser freezing, see: #29859.
+pref("media.hls.enabled", false);
+
+// Inherit locale from the OS, used for multi-locale builds
+pref("intl.locale.requested", "");
+
+// Disable WebAuthn. It requires Google Play Services, so it isn't
+// available, but avoid any potential problems.
+pref("security.webauth.webauthn_enable_android_fido2", false);
+
+// Disable the External App Blocker on Android
+pref("extensions.torbutton.launch_warning", false);
diff --git a/mobile/android/app/geckoview-prefs.js b/mobile/android/app/geckoview-prefs.js
index 3d3871975a28..826970425362 100644
--- a/mobile/android/app/geckoview-prefs.js
+++ b/mobile/android/app/geckoview-prefs.js
@@ -91,3 +91,5 @@ pref("toolkit.autocomplete.delegate", true);
// Android doesn't support the new sync storage yet, we will have our own in
// Bug 1625257.
pref("webextensions.storage.sync.kinto", true);
+
+#include 000-tor-browser-android.js
diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js
index c0f0a0a2dfd8..6c72bc2ed2d7 100644
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -399,7 +399,11 @@ pref("app.update.timerMinimumDelay", 30); // seconds
// used by update service to decide whether or not to
// automatically download an update
pref("app.update.autodownload", "wifi");
+#ifdef TOR_BROWSER_VERSION
+pref("app.update.url.android", "");
+#else
pref("app.update.url.android", "https://aus5.mozilla.org/update/4/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TAR…");
+#endif
#ifdef MOZ_UPDATER
/* prefs used specifically for updating the app */
diff --git a/mobile/android/app/moz.build b/mobile/android/app/moz.build
index 65963fe448eb..4075e8a9d2c4 100644
--- a/mobile/android/app/moz.build
+++ b/mobile/android/app/moz.build
@@ -17,6 +17,7 @@ if CONFIG['MOZ_PKG_SPECIAL']:
DEFINES['MOZ_PKG_SPECIAL'] = CONFIG['MOZ_PKG_SPECIAL']
JS_PREFERENCE_PP_FILES += [
+ '000-tor-browser-android.js',
'mobile.js',
]
diff --git a/taskcluster/ci/source-test/mozlint.yml b/taskcluster/ci/source-test/mozlint.yml
index 6e3373dee6ec..42067fcf14a0 100644
--- a/taskcluster/ci/source-test/mozlint.yml
+++ b/taskcluster/ci/source-test/mozlint.yml
@@ -135,7 +135,9 @@ lintpref:
files-changed:
- 'modules/libpref/init/all.js'
- 'modules/libpref/init/StaticPrefList.yaml'
+ - 'browser/app/profile/000-tor-browser.js'
- 'browser/app/profile/firefox.js'
+ - 'mobile/android/app/000-tor-browser-android.js'
- 'mobile/android/app/mobile.js'
- 'devtools/client/preferences/debugger.js'
- 'mobile/android/app/geckoview-prefs.js'
1
0