tor-commits
Threads by month
- ----- 2026 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 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
- 1 participants
- 216110 discussions
[tor-browser/tor-browser-91.6.0esr-11.0-1] Bug 40198: Expose privacy.spoof_english pref in GeckoView
by richard@torproject.org 02 Feb '22
by richard@torproject.org 02 Feb '22
02 Feb '22
commit 7fc447990e8ce785ae7db128e169eedc6ac98f5b
Author: Alex Catarineu <acat(a)torproject.org>
Date: Sun Oct 18 17:06:04 2020 +0200
Bug 40198: Expose privacy.spoof_english pref in GeckoView
---
mobile/android/geckoview/api.txt | 3 ++
.../mozilla/geckoview/GeckoRuntimeSettings.java | 33 ++++++++++++++++++++++
2 files changed, 36 insertions(+)
diff --git a/mobile/android/geckoview/api.txt b/mobile/android/geckoview/api.txt
index f9f0c9d14a8a..3335aaffb1fb 100644
--- a/mobile/android/geckoview/api.txt
+++ b/mobile/android/geckoview/api.txt
@@ -737,6 +737,7 @@ package org.mozilla.geckoview {
method public boolean getRemoteDebuggingEnabled();
method @Nullable public GeckoRuntime getRuntime();
method @Nullable public Rect getScreenSizeOverride();
+ method public boolean getSpoofEnglish();
method @Nullable public RuntimeTelemetry.Delegate getTelemetryDelegate();
method public int getTorSecurityLevel();
method public boolean getUseMaxScreenDepth();
@@ -759,6 +760,7 @@ package org.mozilla.geckoview {
method @NonNull public GeckoRuntimeSettings setLoginAutofillEnabled(boolean);
method @NonNull public GeckoRuntimeSettings setPreferredColorScheme(int);
method @NonNull public GeckoRuntimeSettings setRemoteDebuggingEnabled(boolean);
+ method @NonNull public GeckoRuntimeSettings setSpoofEnglish(boolean);
method @NonNull public GeckoRuntimeSettings setTorSecurityLevel(int);
method @NonNull public GeckoRuntimeSettings setWebFontsEnabled(boolean);
method @NonNull public GeckoRuntimeSettings setWebManifestEnabled(boolean);
@@ -799,6 +801,7 @@ package org.mozilla.geckoview {
method @NonNull public GeckoRuntimeSettings.Builder preferredColorScheme(int);
method @NonNull public GeckoRuntimeSettings.Builder remoteDebuggingEnabled(boolean);
method @NonNull public GeckoRuntimeSettings.Builder screenSizeOverride(int, int);
+ method @NonNull public GeckoRuntimeSettings.Builder spoofEnglish(boolean);
method @NonNull public GeckoRuntimeSettings.Builder telemetryDelegate(@NonNull RuntimeTelemetry.Delegate);
method @NonNull public GeckoRuntimeSettings.Builder torSecurityLevel(int);
method @NonNull public GeckoRuntimeSettings.Builder useMaxScreenDepth(boolean);
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java
index d88e296d554a..5b54447cb6e6 100644
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java
@@ -483,6 +483,17 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
getSettings().mTorSecurityLevel.set(level);
return this;
}
+
+ /**
+ * Sets whether we should spoof locale to English for webpages.
+ *
+ * @param flag True if we should spoof locale to English for webpages, false otherwise.
+ * @return This Builder instance.
+ */
+ public @NonNull Builder spoofEnglish(final boolean flag) {
+ getSettings().mSpoofEnglish.set(flag ? 2 : 1);
+ return this;
+ }
}
private GeckoRuntime mRuntime;
@@ -541,6 +552,8 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
"dom.ipc.processCount", 2);
/* package */ final Pref<Integer> mTorSecurityLevel = new Pref<>(
"extensions.torbutton.security_slider", 4);
+ /* package */ final Pref<Integer> mSpoofEnglish = new Pref<>(
+ "privacy.spoof_english", 0);
/* package */ int mPreferredColorScheme = COLOR_SCHEME_SYSTEM;
@@ -1319,6 +1332,26 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
return this;
}
+ /**
+ * Get whether we should spoof locale to English for webpages.
+ *
+ * @return Whether we should spoof locale to English for webpages.
+ */
+ public boolean getSpoofEnglish() {
+ return mSpoofEnglish.get() == 2;
+ }
+
+ /**
+ * Set whether we should spoof locale to English for webpages.
+ *
+ * @param flag A flag determining whether we should locale to English for webpages.
+ * @return This GeckoRuntimeSettings instance.
+ */
+ public @NonNull GeckoRuntimeSettings setSpoofEnglish(final boolean flag) {
+ mSpoofEnglish.commit(flag ? 2 : 1);
+ return this;
+ }
+
@Override // Parcelable
public void writeToParcel(final Parcel out, final int flags) {
super.writeToParcel(out, flags);
1
0
[tor-browser/tor-browser-91.6.0esr-11.0-1] Bug 40432: Prevent probing installed applications
by richard@torproject.org 02 Feb '22
by richard@torproject.org 02 Feb '22
02 Feb '22
commit d16c97420ac93a920c2c5cea0a0a24f3950e45ea
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Mon May 17 18:09:09 2021 +0000
Bug 40432: Prevent probing installed applications
---
.../exthandler/nsExternalHelperAppService.cpp | 30 ++++++++++++++++++----
1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp
index 8404a538d9a0..a34e7d983cf0 100644
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -1068,8 +1068,33 @@ nsresult nsExternalHelperAppService::GetFileTokenForPath(
//////////////////////////////////////////////////////////////////////////////////////////////////////
// begin external protocol service default implementation...
//////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static const char kExternalProtocolPrefPrefix[] =
+ "network.protocol-handler.external.";
+static const char kExternalProtocolDefaultPref[] =
+ "network.protocol-handler.external-default";
+
NS_IMETHODIMP nsExternalHelperAppService::ExternalProtocolHandlerExists(
const char* aProtocolScheme, bool* aHandlerExists) {
+
+ // Replicate the same check performed in LoadURI.
+ // Deny load if the prefs say to do so
+ nsAutoCString externalPref(kExternalProtocolPrefPrefix);
+ externalPref += aProtocolScheme;
+ bool allowLoad = false;
+ *aHandlerExists = false;
+ if (NS_FAILED(Preferences::GetBool(externalPref.get(), &allowLoad))) {
+ // no scheme-specific value, check the default
+ if (NS_FAILED(
+ Preferences::GetBool(kExternalProtocolDefaultPref, &allowLoad))) {
+ return NS_OK; // missing default pref
+ }
+ }
+
+ if (!allowLoad) {
+ return NS_OK; // explicitly denied
+ }
+
nsCOMPtr<nsIHandlerInfo> handlerInfo;
nsresult rv = GetProtocolHandlerInfo(nsDependentCString(aProtocolScheme),
getter_AddRefs(handlerInfo));
@@ -1112,11 +1137,6 @@ NS_IMETHODIMP nsExternalHelperAppService::IsExposedProtocol(
return NS_OK;
}
-static const char kExternalProtocolPrefPrefix[] =
- "network.protocol-handler.external.";
-static const char kExternalProtocolDefaultPref[] =
- "network.protocol-handler.external-default";
-
// static
nsresult nsExternalHelperAppService::EscapeURI(nsIURI* aURI, nsIURI** aResult) {
MOZ_ASSERT(aURI);
1
0
[tor-browser/tor-browser-91.6.0esr-11.0-1] Bug 30605: Honor privacy.spoof_english in Android
by richard@torproject.org 02 Feb '22
by richard@torproject.org 02 Feb '22
02 Feb '22
commit 9058236919ea519f9642e3de5a9726430366e1b7
Author: Alex Catarineu <acat(a)torproject.org>
Date: Fri Oct 16 10:45:17 2020 +0200
Bug 30605: Honor privacy.spoof_english in Android
This checks `privacy.spoof_english` whenever `setLocales` is
called from Fenix side and sets `intl.accept_languages`
accordingly.
---
mobile/android/components/geckoview/GeckoViewStartup.jsm | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/mobile/android/components/geckoview/GeckoViewStartup.jsm b/mobile/android/components/geckoview/GeckoViewStartup.jsm
index 055c3da638e1..2bf394f2cb3b 100644
--- a/mobile/android/components/geckoview/GeckoViewStartup.jsm
+++ b/mobile/android/components/geckoview/GeckoViewStartup.jsm
@@ -17,6 +17,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
EventDispatcher: "resource://gre/modules/Messaging.jsm",
Preferences: "resource://gre/modules/Preferences.jsm",
Services: "resource://gre/modules/Services.jsm",
+ RFPHelper: "resource://gre/modules/RFPHelper.jsm",
});
const { debug, warn } = GeckoViewUtils.initLogging("Startup");
@@ -255,6 +256,10 @@ class GeckoViewStartup {
if (aData.requestedLocales) {
Services.locale.requestedLocales = aData.requestedLocales;
}
+ RFPHelper._handleSpoofEnglishChanged();
+ if (Services.prefs.getIntPref("privacy.spoof_english", 0) === 2) {
+ break;
+ }
const pls = Cc["@mozilla.org/pref-localizedstring;1"].createInstance(
Ci.nsIPrefLocalizedString
);
1
0
[tor-browser/tor-browser-91.6.0esr-11.0-1] Adding issue template for bugs.
by richard@torproject.org 02 Feb '22
by richard@torproject.org 02 Feb '22
02 Feb '22
commit 5d7d72c3ae2b1bab145c7877d0707bc298b166ed
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-91.6.0esr-11.0-1] Bug 40309: Avoid using regional OS locales
by richard@torproject.org 02 Feb '22
by richard@torproject.org 02 Feb '22
02 Feb '22
commit b1bbb8a3e75edb470d926c5d4e3a0e2090a5035b
Author: Alex Catarineu <acat(a)torproject.org>
Date: Wed Jan 27 11:28:05 2021 +0100
Bug 40309: Avoid using regional OS locales
Only use regional OS locales if the pref
`intl.regional_prefs.use_os_locales` is set to true.
---
intl/locale/LocaleService.cpp | 25 -------------------------
1 file changed, 25 deletions(-)
diff --git a/intl/locale/LocaleService.cpp b/intl/locale/LocaleService.cpp
index 022d41cab2e2..ac001ee98991 100644
--- a/intl/locale/LocaleService.cpp
+++ b/intl/locale/LocaleService.cpp
@@ -452,31 +452,6 @@ LocaleService::GetRegionalPrefsLocales(nsTArray<nsCString>& aRetVal) {
OSPreferences::GetInstance()->GetRegionalPrefsLocales(aRetVal))) {
return NS_OK;
}
-
- // If we fail to retrieve them, return the app locales.
- GetAppLocalesAsBCP47(aRetVal);
- return NS_OK;
- }
-
- // Otherwise, fetch OS Regional Preferences locales and compare the first one
- // to the app locale. If the language subtag matches, we can safely use
- // the OS Regional Preferences locale.
- //
- // This facilitates scenarios such as Firefox in "en-US" and User sets
- // regional prefs to "en-GB".
- nsAutoCString appLocale;
- AutoTArray<nsCString, 10> regionalPrefsLocales;
- LocaleService::GetInstance()->GetAppLocaleAsBCP47(appLocale);
-
- if (NS_FAILED(OSPreferences::GetInstance()->GetRegionalPrefsLocales(
- regionalPrefsLocales))) {
- GetAppLocalesAsBCP47(aRetVal);
- return NS_OK;
- }
-
- if (LocaleService::LanguagesMatch(appLocale, regionalPrefsLocales[0])) {
- aRetVal = regionalPrefsLocales.Clone();
- return NS_OK;
}
// Otherwise use the app locales.
1
0
[tor-browser/tor-browser-91.6.0esr-11.0-1] Bug 40597: Implement TorSettings module
by richard@torproject.org 02 Feb '22
by richard@torproject.org 02 Feb '22
02 Feb '22
commit f80be97bd47a68a5f7440b18cb0c30e35eade29a
Author: Richard Pospesel <richard(a)torproject.org>
Date: Fri Aug 6 16:39:03 2021 +0200
Bug 40597: Implement TorSettings module
- migrated in-page settings read/write implementation from about:preferences#tor
to the TorSettings module
- TorSettings initially loads settings from the tor daemon, and saves them to
firefox prefs
- TorSettings notifies observers when a setting has changed; currently only
QuickStart notification is implemented for parity with previous preference
notify logic in about:torconnect and about:preferences#tor
- about:preferences#tor, and about:torconnect now read and write settings
thorugh the TorSettings module
- all tor settings live in the torbrowser.settings.* preference branch
- removed unused pref modify permission for about:torconnect content page from
AsyncPrefs.jsm
---
browser/components/torconnect/TorConnectParent.jsm | 25 +-
.../torpreferences/content/parseFunctions.jsm | 89 ---
.../torpreferences/content/torBridgeSettings.jsm | 325 --------
.../torpreferences/content/torFirewallSettings.jsm | 72 --
.../components/torpreferences/content/torPane.js | 301 ++++----
.../torpreferences/content/torProxySettings.jsm | 245 -------
browser/components/torpreferences/jar.mn | 12 +-
browser/modules/TorConnect.jsm | 47 +-
browser/modules/TorSettings.jsm | 814 +++++++++++++++++++++
browser/modules/moz.build | 1 +
.../processsingleton/MainProcessSingleton.jsm | 5 +
toolkit/modules/AsyncPrefs.jsm | 1 -
12 files changed, 989 insertions(+), 948 deletions(-)
diff --git a/browser/components/torconnect/TorConnectParent.jsm b/browser/components/torconnect/TorConnectParent.jsm
index 526c588a423e..2fbc2a5c7c7c 100644
--- a/browser/components/torconnect/TorConnectParent.jsm
+++ b/browser/components/torconnect/TorConnectParent.jsm
@@ -7,10 +7,9 @@ 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",
-});
+const { TorSettings, TorSettingsTopics, TorSettingsData } = ChromeUtils.import(
+ "resource:///modules/TorSettings.jsm"
+);
/*
This object is basically a marshalling interface between the TorConnect module
@@ -31,7 +30,7 @@ class TorConnectParent extends JSWindowActorParent {
BootstrapProgress: TorConnect.bootstrapProgress,
BootstrapStatus: TorConnect.bootstrapStatus,
ShowCopyLog: TorConnect.logHasWarningOrError,
- QuickStartEnabled: Services.prefs.getBoolPref(TorLauncherPrefs.quickstart, false),
+ QuickStartEnabled: TorSettings.quickstart.enabled,
};
// JSWindowActiveParent derived objects cannot observe directly, so create a member
@@ -78,9 +77,12 @@ class TorConnectParent extends JSWindowActorParent {
// TODO: handle
break;
}
- case "nsPref:changed": {
- if (aData === TorLauncherPrefs.quickstart) {
- self.state.QuickStartEnabled = Services.prefs.getBoolPref(TorLauncherPrefs.quickstart);
+ case TorSettingsTopics.SettingChanged:{
+ if (aData === TorSettingsData.QuickStartEnabled) {
+ self.state.QuickStartEnabled = obj.value;
+ } else {
+ // this isn't a setting torconnect cares about
+ return;
}
break;
}
@@ -98,7 +100,7 @@ class TorConnectParent extends JSWindowActorParent {
const topic = TorConnectTopics[key];
Services.obs.addObserver(this.torConnectObserver, topic);
}
- Services.prefs.addObserver(TorLauncherPrefs.quickstart, this.torConnectObserver);
+ Services.obs.addObserver(this.torConnectObserver, TorSettingsTopics.SettingChanged);
}
willDestroy() {
@@ -107,13 +109,14 @@ class TorConnectParent extends JSWindowActorParent {
const topic = TorConnectTopics[key];
Services.obs.removeObserver(this.torConnectObserver, topic);
}
- Services.prefs.removeObserver(TorLauncherPrefs.quickstart, this.torConnectObserver);
+ Services.obs.removeObserver(this.torConnectObserver, TorSettingsTopics.SettingChanged);
}
receiveMessage(message) {
switch (message.name) {
case "torconnect:set-quickstart":
- Services.prefs.setBoolPref(TorLauncherPrefs.quickstart, message.data);
+ TorSettings.quickstart.enabled = message.data;
+ TorSettings.saveToPrefs().applySettings();
break;
case "torconnect:open-tor-preferences":
TorConnect.openTorPreferences();
diff --git a/browser/components/torpreferences/content/parseFunctions.jsm b/browser/components/torpreferences/content/parseFunctions.jsm
deleted file mode 100644
index 954759de63a5..000000000000
--- a/browser/components/torpreferences/content/parseFunctions.jsm
+++ /dev/null
@@ -1,89 +0,0 @@
-"use strict";
-
-var EXPORTED_SYMBOLS = [
- "parsePort",
- "parseAddrPort",
- "parseUsernamePassword",
- "parseAddrPortList",
- "parseBridgeStrings",
- "parsePortList",
-];
-
-// expects a string representation of an integer from 1 to 65535
-let parsePort = function(aPort) {
- // ensure port string is a valid positive integer
- const validIntRegex = /^[0-9]+$/;
- if (!validIntRegex.test(aPort)) {
- throw new Error(`Invalid PORT string : '${aPort}'`);
- }
-
- // ensure port value is on valid range
- let port = Number.parseInt(aPort);
- if (port < 1 || port > 65535) {
- throw new Error(
- `Invalid PORT value, needs to be on range [1,65535] : '${port}'`
- );
- }
-
- return port;
-};
-// expects a string in the format: "ADDRESS:PORT"
-let parseAddrPort = function(aAddrColonPort) {
- let tokens = aAddrColonPort.split(":");
- if (tokens.length != 2) {
- throw new Error(`Invalid ADDRESS:PORT string : '${aAddrColonPort}'`);
- }
- let address = tokens[0];
- let port = parsePort(tokens[1]);
- return [address, port];
-};
-
-// expects a string in the format: "USERNAME:PASSWORD"
-// split on the first colon and any subsequent go into password
-let parseUsernamePassword = function(aUsernameColonPassword) {
- let colonIndex = aUsernameColonPassword.indexOf(":");
- if (colonIndex < 0) {
- // we don't log the contents of the potentially password containing string
- throw new Error("Invalid USERNAME:PASSWORD string");
- }
-
- let username = aUsernameColonPassword.substring(0, colonIndex);
- let password = aUsernameColonPassword.substring(colonIndex + 1);
-
- return [username, password];
-};
-
-// expects a string in the format: ADDRESS:PORT,ADDRESS:PORT,...
-// returns array of ports (as ints)
-let parseAddrPortList = function(aAddrPortList) {
- let addrPorts = aAddrPortList.split(",");
- // parse ADDRESS:PORT string and only keep the port (second element in returned array)
- let retval = addrPorts.map(addrPort => parseAddrPort(addrPort)[1]);
- return retval;
-};
-
-// expects a '/n' or '/r/n' delimited bridge string, which we split and trim
-// each bridge string can also optionally have 'bridge' at the beginning ie:
-// bridge $(type) $(address):$(port) $(certificate)
-// we strip out the 'bridge' prefix here
-let parseBridgeStrings = function(aBridgeStrings) {
-
- // replace carriage returns ('\r') with new lines ('\n')
- aBridgeStrings = aBridgeStrings.replace(/\r/g, "\n");
- // then replace contiguous new lines ('\n') with a single one
- aBridgeStrings = aBridgeStrings.replace(/[\n]+/g, "\n");
-
- // split on the newline and for each bridge string: trim, remove starting 'bridge' string
- // finally discard entries that are empty strings; empty strings could occur if we receive
- // a new line containing only whitespace
- let splitStrings = aBridgeStrings.split("\n");
- return splitStrings.map(val => val.trim().replace(/^bridge\s+/i, ""))
- .filter(bridgeString => bridgeString != "");
-};
-
-// expecting a ',' delimited list of ints with possible white space between
-// returns an array of ints
-let parsePortList = function(aPortListString) {
- let splitStrings = aPortListString.split(",");
- return splitStrings.map(val => parsePort(val.trim()));
-};
diff --git a/browser/components/torpreferences/content/torBridgeSettings.jsm b/browser/components/torpreferences/content/torBridgeSettings.jsm
deleted file mode 100644
index ceb61d3ec972..000000000000
--- a/browser/components/torpreferences/content/torBridgeSettings.jsm
+++ /dev/null
@@ -1,325 +0,0 @@
-"use strict";
-
-var EXPORTED_SYMBOLS = [
- "TorBridgeSource",
- "TorBridgeSettings",
- "makeTorBridgeSettingsNone",
- "makeTorBridgeSettingsBuiltin",
- "makeTorBridgeSettingsBridgeDB",
- "makeTorBridgeSettingsUserProvided",
-];
-
-const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-const { TorProtocolService } = ChromeUtils.import(
- "resource:///modules/TorProtocolService.jsm"
-);
-const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm");
-
-const TorBridgeSource = {
- NONE: "NONE",
- BUILTIN: "BUILTIN",
- BRIDGEDB: "BRIDGEDB",
- USERPROVIDED: "USERPROVIDED",
-};
-
-class TorBridgeSettings {
- constructor() {
- this._bridgeSource = TorBridgeSource.NONE;
- this._selectedDefaultBridgeType = null;
- this._bridgeStrings = [];
- }
-
- get selectedDefaultBridgeType() {
- if (this._bridgeSource == TorBridgeSource.BUILTIN) {
- return this._selectedDefaultBridgeType;
- }
- return undefined;
- }
-
- get bridgeSource() {
- return this._bridgeSource;
- }
-
- // for display
- get bridgeStrings() {
- return this._bridgeStrings.join("\n");
- }
-
- // raw
- get bridgeStringsArray() {
- return this._bridgeStrings;
- }
-
- static get defaultBridgeTypes() {
- if (TorBridgeSettings._defaultBridgeTypes) {
- return TorBridgeSettings._defaultBridgeTypes;
- }
-
- let bridgeListBranch = Services.prefs.getBranch(
- TorStrings.preferenceBranches.defaultBridge
- );
- let bridgePrefs = bridgeListBranch.getChildList("", {});
-
- // an unordered set for shoving bridge types into
- let bridgeTypes = new Set();
- // look for keys ending in ".N" and treat string before that as the bridge type
- const pattern = /\.[0-9]+$/;
- for (const key of bridgePrefs) {
- const offset = key.search(pattern);
- if (offset != -1) {
- const bt = key.substring(0, offset);
- bridgeTypes.add(bt);
- }
- }
-
- // recommended bridge type goes first in the list
- let recommendedBridgeType = Services.prefs.getCharPref(
- TorStrings.preferenceKeys.recommendedBridgeType,
- null
- );
-
- let retval = [];
- if (recommendedBridgeType && bridgeTypes.has(recommendedBridgeType)) {
- retval.push(recommendedBridgeType);
- }
-
- for (const bridgeType of bridgeTypes.values()) {
- if (bridgeType != recommendedBridgeType) {
- retval.push(bridgeType);
- }
- }
-
- // cache off
- TorBridgeSettings._defaultBridgeTypes = retval;
- return retval;
- }
-
- _readDefaultBridges(aBridgeType) {
- let bridgeBranch = Services.prefs.getBranch(
- TorStrings.preferenceBranches.defaultBridge
- );
- let bridgeBranchPrefs = bridgeBranch.getChildList("", {});
-
- let retval = [];
-
- // regex matches against strings ending in ".N" where N is a positive integer
- let pattern = /\.[0-9]+$/;
- for (const key of bridgeBranchPrefs) {
- // verify the location of the match is the correct offset required for aBridgeType
- // to fit, and that the string begins with aBridgeType
- if (
- key.search(pattern) == aBridgeType.length &&
- key.startsWith(aBridgeType)
- ) {
- let bridgeStr = bridgeBranch.getCharPref(key);
- retval.push(bridgeStr);
- }
- }
-
- // fisher-yates shuffle
- // shuffle so that Tor Browser users don't all try the built-in bridges in the same order
- for (let i = retval.length - 1; i > 0; --i) {
- // number n such that 0.0 <= n < 1.0
- const n = Math.random();
- // integer j such that 0 <= j <= i
- const j = Math.floor(n * (i + 1));
-
- // swap values at indices i and j
- const tmp = retval[i];
- retval[i] = retval[j];
- retval[j] = tmp;
- }
-
- return retval;
- }
-
- _readBridgeDBBridges() {
- let bridgeBranch = Services.prefs.getBranch(
- `${TorStrings.preferenceBranches.bridgeDBBridges}`
- );
- let bridgeBranchPrefs = bridgeBranch.getChildList("", {});
- // the child prefs do not come in any particular order so sort the keys
- // so the values can be compared to what we get out off torrc
- bridgeBranchPrefs.sort();
-
- // just assume all of the prefs under the parent point to valid bridge string
- let retval = bridgeBranchPrefs.map(key =>
- bridgeBranch.getCharPref(key).trim()
- );
-
- return retval;
- }
-
- _readTorrcBridges() {
- let bridgeList = TorProtocolService.readStringArraySetting(
- TorStrings.configKeys.bridgeList
- );
-
- let retval = [];
- for (const line of bridgeList) {
- let trimmedLine = line.trim();
- if (trimmedLine) {
- retval.push(trimmedLine);
- }
- }
-
- return retval;
- }
-
- // analagous to initBridgeSettings()
- readSettings() {
- // restore to defaults
- this._bridgeSource = TorBridgeSource.NONE;
- this._selectedDefaultBridgeType = null;
- this._bridgeStrings = [];
-
- // So the way tor-launcher determines the origin of the configured bridges is a bit
- // weird and depends on inferring our scenario based on some firefox prefs and the
- // relationship between the saved list of bridges in about:config vs the list saved in torrc
-
- // first off, if "extensions.torlauncher.default_bridge_type" is set to one of our
- // builtin default types (obfs4, meek-azure, snowflake, etc) then we provide the
- // bridges in "extensions.torlauncher.default_bridge.*" (filtered by our default_bridge_type)
-
- // next, we compare the list of bridges saved in torrc to the bridges stored in the
- // "extensions.torlauncher.bridgedb_bridge."" branch. If they match *exactly* then we assume
- // the bridges were retrieved from BridgeDB and use those. If the torrc list is empty then we know
- // we have no bridge settings
-
- // finally, if none of the previous conditions are not met, it is assumed the bridges stored in
- // torrc are user-provided
-
- // what we should(?) do once we excise tor-launcher entirely is explicitly store an int/enum in
- // about:config that tells us which scenario we are in so we don't have to guess
-
- let defaultBridgeType = Services.prefs.getCharPref(
- TorStrings.preferenceKeys.defaultBridgeType,
- null
- );
-
- // check if source is BUILTIN
- if (defaultBridgeType) {
- this._bridgeStrings = this._readDefaultBridges(defaultBridgeType);
- this._bridgeSource = TorBridgeSource.BUILTIN;
- this._selectedDefaultBridgeType = defaultBridgeType;
- return;
- }
-
- let torrcBridges = this._readTorrcBridges();
-
- // no stored bridges means no bridge is in use
- if (torrcBridges.length == 0) {
- this._bridgeStrings = [];
- this._bridgeSource = TorBridgeSource.NONE;
- return;
- }
-
- let bridgedbBridges = this._readBridgeDBBridges();
-
- // if these two lists are equal then we got our bridges from bridgedb
- // ie: same element in identical order
- let arraysEqual = (left, right) => {
- if (left.length != right.length) {
- return false;
- }
- const length = left.length;
- for (let i = 0; i < length; ++i) {
- if (left[i] != right[i]) {
- return false;
- }
- }
- return true;
- };
-
- // agreement between prefs and torrc means bridgedb bridges
- if (arraysEqual(torrcBridges, bridgedbBridges)) {
- this._bridgeStrings = torrcBridges;
- this._bridgeSource = TorBridgeSource.BRIDGEDB;
- return;
- }
-
- // otherwise they must be user provided
- this._bridgeStrings = torrcBridges;
- this._bridgeSource = TorBridgeSource.USERPROVIDED;
- }
-
- writeSettings() {
- let settingsObject = new Map();
-
- // init tor bridge settings to null
- settingsObject.set(TorStrings.configKeys.useBridges, null);
- settingsObject.set(TorStrings.configKeys.bridgeList, null);
-
- // clear bridge related firefox prefs
- Services.prefs.setCharPref(TorStrings.preferenceKeys.defaultBridgeType, "");
- let bridgeBranch = Services.prefs.getBranch(
- `${TorStrings.preferenceBranches.bridgeDBBridges}`
- );
- let bridgeBranchPrefs = bridgeBranch.getChildList("", {});
- for (const pref of bridgeBranchPrefs) {
- Services.prefs.clearUserPref(
- `${TorStrings.preferenceBranches.bridgeDBBridges}${pref}`
- );
- }
-
- switch (this._bridgeSource) {
- case TorBridgeSource.BUILTIN:
- // set builtin bridge type to use in prefs
- Services.prefs.setCharPref(
- TorStrings.preferenceKeys.defaultBridgeType,
- this._selectedDefaultBridgeType
- );
- break;
- case TorBridgeSource.BRIDGEDB:
- // save bridges off to prefs
- for (let i = 0; i < this.bridgeStringsArray.length; ++i) {
- Services.prefs.setCharPref(
- `${TorStrings.preferenceBranches.bridgeDBBridges}${i}`,
- this.bridgeStringsArray[i]
- );
- }
- break;
- }
-
- // write over our bridge list if bridges are enabled
- if (this._bridgeSource != TorBridgeSource.NONE) {
- settingsObject.set(TorStrings.configKeys.useBridges, true);
- settingsObject.set(
- TorStrings.configKeys.bridgeList,
- this.bridgeStringsArray
- );
- }
- TorProtocolService.writeSettings(settingsObject);
- }
-}
-
-function makeTorBridgeSettingsNone() {
- return new TorBridgeSettings();
-}
-
-function makeTorBridgeSettingsBuiltin(aBridgeType) {
- let retval = new TorBridgeSettings();
- retval._bridgeSource = TorBridgeSource.BUILTIN;
- retval._selectedDefaultBridgeType = aBridgeType;
- retval._bridgeStrings = retval._readDefaultBridges(aBridgeType);
-
- return retval;
-}
-
-function makeTorBridgeSettingsBridgeDB(aBridges) {
- let retval = new TorBridgeSettings();
- retval._bridgeSource = TorBridgeSource.BRIDGEDB;
- retval._selectedDefaultBridgeType = null;
- retval._bridgeStrings = aBridges;
-
- return retval;
-}
-
-function makeTorBridgeSettingsUserProvided(aBridges) {
- let retval = new TorBridgeSettings();
- retval._bridgeSource = TorBridgeSource.USERPROVIDED;
- retval._selectedDefaultBridgeType = null;
- retval._bridgeStrings = aBridges;
-
- return retval;
-}
diff --git a/browser/components/torpreferences/content/torFirewallSettings.jsm b/browser/components/torpreferences/content/torFirewallSettings.jsm
deleted file mode 100644
index e77f18ef2fae..000000000000
--- a/browser/components/torpreferences/content/torFirewallSettings.jsm
+++ /dev/null
@@ -1,72 +0,0 @@
-"use strict";
-
-var EXPORTED_SYMBOLS = [
- "TorFirewallSettings",
- "makeTorFirewallSettingsNone",
- "makeTorFirewallSettingsCustom",
-];
-
-const { TorProtocolService } = ChromeUtils.import(
- "resource:///modules/TorProtocolService.jsm"
-);
-const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm");
-const { parseAddrPortList } = ChromeUtils.import(
- "chrome://browser/content/torpreferences/parseFunctions.jsm"
-);
-
-class TorFirewallSettings {
- constructor() {
- this._allowedPorts = [];
- }
-
- get portsConfigurationString() {
- let portStrings = this._allowedPorts.map(port => `*:${port}`);
- return portStrings.join(",");
- }
-
- get commaSeparatedListString() {
- return this._allowedPorts.join(",");
- }
-
- get hasPorts() {
- return this._allowedPorts.length > 0;
- }
-
- readSettings() {
- let addressPortList = TorProtocolService.readStringSetting(
- TorStrings.configKeys.reachableAddresses
- );
-
- let allowedPorts = [];
- if (addressPortList) {
- allowedPorts = parseAddrPortList(addressPortList);
- }
- this._allowedPorts = allowedPorts;
- }
-
- writeSettings() {
- let settingsObject = new Map();
-
- // init to null so Tor daemon resets if no ports
- settingsObject.set(TorStrings.configKeys.reachableAddresses, null);
-
- if (this._allowedPorts.length > 0) {
- settingsObject.set(
- TorStrings.configKeys.reachableAddresses,
- this.portsConfigurationString
- );
- }
-
- TorProtocolService.writeSettings(settingsObject);
- }
-}
-
-function makeTorFirewallSettingsNone() {
- return new TorFirewallSettings();
-}
-
-function makeTorFirewallSettingsCustom(aPortsList) {
- let retval = new TorFirewallSettings();
- retval._allowedPorts = aPortsList;
- return retval;
-}
diff --git a/browser/components/torpreferences/content/torPane.js b/browser/components/torpreferences/content/torPane.js
index b81a238efc6f..2df71db9327e 100644
--- a/browser/components/torpreferences/content/torPane.js
+++ b/browser/components/torpreferences/content/torPane.js
@@ -2,6 +2,10 @@
/* global Services */
+const { TorSettings, TorSettingsTopics, TorSettingsData, TorBridgeSource, TorBuiltinBridgeTypes, TorProxyType } = ChromeUtils.import(
+ "resource:///modules/TorSettings.jsm"
+);
+
const { TorProtocolService } = ChromeUtils.import(
"resource:///modules/TorProtocolService.jsm"
);
@@ -10,35 +14,6 @@ const { TorConnect, TorConnectTopics, TorConnectState } = ChromeUtils.import(
"resource:///modules/TorConnect.jsm"
);
-const {
- TorBridgeSource,
- TorBridgeSettings,
- makeTorBridgeSettingsNone,
- makeTorBridgeSettingsBuiltin,
- makeTorBridgeSettingsBridgeDB,
- makeTorBridgeSettingsUserProvided,
-} = ChromeUtils.import(
- "chrome://browser/content/torpreferences/torBridgeSettings.jsm"
-);
-
-const {
- TorProxyType,
- TorProxySettings,
- makeTorProxySettingsNone,
- makeTorProxySettingsSocks4,
- makeTorProxySettingsSocks5,
- makeTorProxySettingsHTTPS,
-} = ChromeUtils.import(
- "chrome://browser/content/torpreferences/torProxySettings.jsm"
-);
-const {
- TorFirewallSettings,
- makeTorFirewallSettingsNone,
- makeTorFirewallSettingsCustom,
-} = ChromeUtils.import(
- "chrome://browser/content/torpreferences/torFirewallSettings.jsm"
-);
-
const { TorLogDialog } = ChromeUtils.import(
"chrome://browser/content/torpreferences/torLogDialog.jsm"
);
@@ -53,14 +28,6 @@ ChromeUtils.defineModuleGetter(
"resource:///modules/TorStrings.jsm"
);
-const { parsePort, parseBridgeStrings, parsePortList } = ChromeUtils.import(
- "chrome://browser/content/torpreferences/parseFunctions.jsm"
-);
-
-const TorLauncherPrefs = {
- quickstart: "extensions.torlauncher.quickstart",
-}
-
/*
Tor Pane
@@ -261,10 +228,11 @@ const gTorPane = (function() {
);
this._enableQuickstartCheckbox.addEventListener("command", e => {
const checked = this._enableQuickstartCheckbox.checked;
- Services.prefs.setBoolPref(TorLauncherPrefs.quickstart, checked);
+ TorSettings.quickstart.enabled = checked;
+ TorSettings.saveToPrefs().applySettings();
});
- this._enableQuickstartCheckbox.checked = Services.prefs.getBoolPref(TorLauncherPrefs.quickstart);
- Services.prefs.addObserver(TorLauncherPrefs.quickstart, this);
+ this._enableQuickstartCheckbox.checked = TorSettings.quickstart.enabled;
+ Services.obs.addObserver(this, TorSettingsTopics.SettingChanged);
// Bridge setup
prefpane.querySelector(selectors.bridges.header).innerText =
@@ -291,7 +259,7 @@ const gTorPane = (function() {
this._bridgeSelectionRadiogroup = prefpane.querySelector(
selectors.bridges.bridgeSelectionRadiogroup
);
- this._bridgeSelectionRadiogroup.value = TorBridgeSource.BUILTIN;
+ this._bridgeSelectionRadiogroup.value = TorBridgeSource.BuiltIn;
this._bridgeSelectionRadiogroup.addEventListener("command", e => {
const value = this._bridgeSelectionRadiogroup.value;
gTorPane.onSelectBridgeOption(value).onUpdateBridgeSettings();
@@ -305,7 +273,7 @@ const gTorPane = (function() {
"label",
TorStrings.settings.selectBridge
);
- this._builtinBridgeOption.setAttribute("value", TorBridgeSource.BUILTIN);
+ this._builtinBridgeOption.setAttribute("value", TorBridgeSource.BuiltIn);
this._builtinBridgeMenulist = prefpane.querySelector(
selectors.bridges.builtinBridgeList
);
@@ -321,7 +289,7 @@ const gTorPane = (function() {
"label",
TorStrings.settings.requestBridgeFromTorProject
);
- this._requestBridgeOption.setAttribute("value", TorBridgeSource.BRIDGEDB);
+ this._requestBridgeOption.setAttribute("value", TorBridgeSource.BridgeDB);
this._requestBridgeButton = prefpane.querySelector(
selectors.bridges.requestBridgeButton
);
@@ -346,7 +314,7 @@ const gTorPane = (function() {
);
this._provideBridgeOption.setAttribute(
"value",
- TorBridgeSource.USERPROVIDED
+ TorBridgeSource.UserProvided
);
prefpane.querySelector(
selectors.bridges.provideBridgeDescription
@@ -395,11 +363,11 @@ const gTorPane = (function() {
let mockProxies = [
{
- value: TorProxyType.SOCKS4,
+ value: TorProxyType.Socks4,
label: TorStrings.settings.proxyTypeSOCKS4,
},
{
- value: TorProxyType.SOCKS5,
+ value: TorProxyType.Socks5,
label: TorStrings.settings.proxyTypeSOCKS5,
},
{ value: TorProxyType.HTTPS, label: TorStrings.settings.proxyTypeHTTP },
@@ -550,12 +518,8 @@ const gTorPane = (function() {
true
);
- // load bridge settings
- let torBridgeSettings = new TorBridgeSettings();
- torBridgeSettings.readSettings();
-
- // populate the bridge list
- for (let currentBridge of TorBridgeSettings.defaultBridgeTypes) {
+ // init bridge UI
+ for (let currentBridge of TorBuiltinBridgeTypes) {
let menuEntry = document.createXULElement("menuitem");
menuEntry.setAttribute("value", currentBridge);
menuEntry.setAttribute("label", currentBridge);
@@ -564,53 +528,41 @@ const gTorPane = (function() {
.appendChild(menuEntry);
}
- this.onSelectBridgeOption(torBridgeSettings.bridgeSource);
- this.onToggleBridge(
- torBridgeSettings.bridgeSource != TorBridgeSource.NONE
- );
- switch (torBridgeSettings.bridgeSource) {
- case TorBridgeSource.NONE:
- break;
- case TorBridgeSource.BUILTIN:
- this._builtinBridgeMenulist.value =
- torBridgeSettings.selectedDefaultBridgeType;
- break;
- case TorBridgeSource.BRIDGEDB:
- this._requestBridgeTextarea.value = torBridgeSettings.bridgeStrings;
- break;
- case TorBridgeSource.USERPROVIDED:
- this._provideBridgeTextarea.value = torBridgeSettings.bridgeStrings;
- break;
+ if (TorSettings.bridges.enabled) {
+ this.onSelectBridgeOption(TorSettings.bridges.source);
+ this.onToggleBridge(
+ TorSettings.bridges.source != TorBridgeSource.Invalid
+ );
+ switch (TorSettings.bridges.source) {
+ case TorBridgeSource.Invalid:
+ break;
+ case TorBridgeSource.BuiltIn:
+ this._builtinBridgeMenulist.value = TorSettings.bridges.builtin_type;
+ break;
+ case TorBridgeSource.BridgeDB:
+ this._requestBridgeTextarea.value = TorSettings.bridges.bridge_strings.join("\n");
+ break;
+ case TorBridgeSource.UserProvided:
+ this._provideBridgeTextarea.value = TorSettings.bridges.bridge_strings.join("\n");
+ break;
+ }
}
- this._bridgeSettings = torBridgeSettings;
-
- // load proxy settings
- let torProxySettings = new TorProxySettings();
- torProxySettings.readSettings();
-
- if (torProxySettings.type != TorProxyType.NONE) {
+ // init proxy UI
+ if (TorSettings.proxy.enabled) {
this.onToggleProxy(true);
- this.onSelectProxyType(torProxySettings.type);
- this._proxyAddressTextbox.value = torProxySettings.address;
- this._proxyPortTextbox.value = torProxySettings.port;
- this._proxyUsernameTextbox.value = torProxySettings.username;
- this._proxyPasswordTextbox.value = torProxySettings.password;
+ this.onSelectProxyType(TorSettings.proxy.type);
+ this._proxyAddressTextbox.value = TorSettings.proxy.address;
+ this._proxyPortTextbox.value = TorSettings.proxy.port;
+ this._proxyUsernameTextbox.value = TorSettings.proxy.username;
+ this._proxyPasswordTextbox.value = TorSettings.proxy.password;
}
- this._proxySettings = torProxySettings;
-
- // load firewall settings
- let torFirewallSettings = new TorFirewallSettings();
- torFirewallSettings.readSettings();
-
- if (torFirewallSettings.hasPorts) {
+ // init firewall
+ if (TorSettings.firewall.enabled) {
this.onToggleFirewall(true);
- this._allowedPortsTextbox.value =
- torFirewallSettings.commaSeparatedListString;
+ this._allowedPortsTextbox.value = TorSettings.firewall.allowed_ports.join(", ");
}
-
- this._firewallSettings = torFirewallSettings;
},
init() {
@@ -683,13 +635,17 @@ const gTorPane = (function() {
if (enabled) {
this.onSelectBridgeOption(this._bridgeSelectionRadiogroup.value);
} else {
- this.onSelectBridgeOption(TorBridgeSource.NONE);
+ this.onSelectBridgeOption(TorBridgeSource.Invalid);
}
return this;
},
// callback when a bridge option is selected
onSelectBridgeOption(source) {
+ if (typeof source === "string") {
+ source = parseInt(source);
+ }
+
// disable all of the bridge elements under radio buttons
this._setElementsDisabled(
[
@@ -701,23 +657,23 @@ const gTorPane = (function() {
true
);
- if (source != TorBridgeSource.NONE) {
+ if (source != TorBridgeSource.Invalid) {
this._bridgeSelectionRadiogroup.value = source;
}
switch (source) {
- case TorBridgeSource.BUILTIN: {
+ case TorBridgeSource.BuiltIn: {
this._setElementsDisabled([this._builtinBridgeMenulist], false);
break;
}
- case TorBridgeSource.BRIDGEDB: {
+ case TorBridgeSource.BridgeDB: {
this._setElementsDisabled(
[this._requestBridgeButton, this._requestBridgeTextarea],
false
);
break;
}
- case TorBridgeSource.USERPROVIDED: {
+ case TorBridgeSource.UserProvided: {
this._setElementsDisabled([this._provideBridgeTextarea], false);
break;
}
@@ -730,14 +686,17 @@ const gTorPane = (function() {
let requestBridgeDialog = new RequestBridgeDialog();
requestBridgeDialog.openDialog(
gSubDialog,
- this._proxySettings.proxyURI,
+ TorSettings.proxy.uri,
aBridges => {
if (aBridges.length > 0) {
- let bridgeSettings = makeTorBridgeSettingsBridgeDB(aBridges);
- bridgeSettings.writeSettings();
- this._bridgeSettings = bridgeSettings;
-
- this._requestBridgeTextarea.value = bridgeSettings.bridgeStrings;
+ let bridgeStrings = aBridges.join("\n");
+ TorSettings.bridges.enabled = true;
+ TorSettings.bridges.source = TorBridgeSource.BridgeDB;
+ TorSettings.bridges.bridge_strings = bridgeStrings;
+ TorSettings.saveToPrefs();
+ TorSettings.applySettings().then((result) => {
+ this._requestBridgeTextarea.value = bridgeStrings;
+ });
}
}
);
@@ -746,53 +705,56 @@ const gTorPane = (function() {
// pushes bridge settings from UI to tor
onUpdateBridgeSettings() {
- let bridgeSettings = null;
-
let source = this._useBridgeCheckbox.checked
- ? this._bridgeSelectionRadiogroup.value
- : TorBridgeSource.NONE;
+ ? parseInt(this._bridgeSelectionRadiogroup.value)
+ : TorBridgeSource.Invalid;
+
switch (source) {
- case TorBridgeSource.NONE: {
- bridgeSettings = makeTorBridgeSettingsNone();
- break;
+ case TorBridgeSource.Invalid: {
+ TorSettings.bridges.enabled = false;
}
- case TorBridgeSource.BUILTIN: {
+ break;
+ case TorBridgeSource.BuiltIn: {
// if there is a built-in bridge already selected, use that
let bridgeType = this._builtinBridgeMenulist.value;
+ console.log(`bridge type: ${bridgeType}`);
if (bridgeType) {
- bridgeSettings = makeTorBridgeSettingsBuiltin(bridgeType);
+ TorSettings.bridges.enabled = true;
+ TorSettings.bridges.source = TorBridgeSource.BuiltIn;
+ TorSettings.bridges.builtin_type = bridgeType;
} else {
- bridgeSettings = makeTorBridgeSettingsNone();
+ TorSettings.bridges.enabled = false;
}
break;
}
- case TorBridgeSource.BRIDGEDB: {
+ case TorBridgeSource.BridgeDB: {
// if there are bridgedb bridges saved in the text area, use them
let bridgeStrings = this._requestBridgeTextarea.value;
if (bridgeStrings) {
- let bridgeStringList = parseBridgeStrings(bridgeStrings);
- bridgeSettings = makeTorBridgeSettingsBridgeDB(bridgeStringList);
+ TorSettings.bridges.enabled = true;
+ TorSettings.bridges.source = TorBridgeSource.BridgeDB;
+ TorSettings.bridges.bridge_strings = bridgeStrings;
} else {
- bridgeSettings = makeTorBridgeSettingsNone();
+ TorSettings.bridges.enabled = false;
}
break;
}
- case TorBridgeSource.USERPROVIDED: {
+ case TorBridgeSource.UserProvided: {
// if bridges already exist in the text area, use them
let bridgeStrings = this._provideBridgeTextarea.value;
if (bridgeStrings) {
- let bridgeStringList = parseBridgeStrings(bridgeStrings);
- bridgeSettings = makeTorBridgeSettingsUserProvided(
- bridgeStringList
- );
+ TorSettings.bridges.enabled = true;
+ TorSettings.bridges.source = TorBridgeSource.UserProvided;
+ TorSettings.bridges.bridge_strings = bridgeStrings;
} else {
- bridgeSettings = makeTorBridgeSettingsNone();
+ TorSettings.bridges.enabled = false;
}
break;
}
}
- bridgeSettings.writeSettings();
- this._bridgeSettings = bridgeSettings;
+ TorSettings.saveToPrefs();
+ TorSettings.applySettings();
+
return this;
},
@@ -822,12 +784,13 @@ const gTorPane = (function() {
// callback when proxy type is changed
onSelectProxyType(value) {
- if (value == "") {
- value = TorProxyType.NONE;
+ if (typeof value === "string") {
+ value = parseInt(value);
}
+
this._proxyTypeMenulist.value = value;
switch (value) {
- case TorProxyType.NONE: {
+ case TorProxyType.Invalid: {
this._setElementsDisabled(
[
this._proxyAddressLabel,
@@ -848,7 +811,7 @@ const gTorPane = (function() {
this._proxyPasswordTextbox.value = "";
break;
}
- case TorProxyType.SOCKS4: {
+ case TorProxyType.Socks4: {
this._setElementsDisabled(
[
this._proxyAddressLabel,
@@ -872,7 +835,7 @@ const gTorPane = (function() {
this._proxyPasswordTextbox.value = "";
break;
}
- case TorProxyType.SOCKS5:
+ case TorProxyType.Socks5:
case TorProxyType.HTTPS: {
this._setElementsDisabled(
[
@@ -895,46 +858,45 @@ const gTorPane = (function() {
// pushes proxy settings from UI to tor
onUpdateProxySettings() {
- const proxyType = this._useProxyCheckbox.checked
- ? this._proxyTypeMenulist.value
- : TorProxyType.NONE;
- const addressString = this._proxyAddressTextbox.value;
- const portString = this._proxyPortTextbox.value;
- const usernameString = this._proxyUsernameTextbox.value;
- const passwordString = this._proxyPasswordTextbox.value;
-
- let proxySettings = null;
-
- switch (proxyType) {
- case TorProxyType.NONE:
- proxySettings = makeTorProxySettingsNone();
+ const type = this._useProxyCheckbox.checked
+ ? parseInt(this._proxyTypeMenulist.value)
+ : TorProxyType.Invalid;
+ const address = this._proxyAddressTextbox.value;
+ const port = this._proxyPortTextbox.value;
+ const username = this._proxyUsernameTextbox.value;
+ const password = this._proxyPasswordTextbox.value;
+
+ switch (type) {
+ case TorProxyType.Invalid:
+ TorSettings.proxy.enabled = false;
break;
- case TorProxyType.SOCKS4:
- proxySettings = makeTorProxySettingsSocks4(
- addressString,
- parsePort(portString)
- );
+ case TorProxyType.Socks4:
+ TorSettings.proxy.enabled = true;
+ TorSettings.proxy.type = type;
+ TorSettings.proxy.address = address;
+ TorSettings.proxy.port = port;
+
break;
- case TorProxyType.SOCKS5:
- proxySettings = makeTorProxySettingsSocks5(
- addressString,
- parsePort(portString),
- usernameString,
- passwordString
- );
+ case TorProxyType.Socks5:
+ TorSettings.proxy.enabled = true;
+ TorSettings.proxy.type = type;
+ TorSettings.proxy.address = address;
+ TorSettings.proxy.port = port;
+ TorSettings.proxy.username = username;
+ TorSettings.proxy.password = password;
break;
case TorProxyType.HTTPS:
- proxySettings = makeTorProxySettingsHTTPS(
- addressString,
- parsePort(portString),
- usernameString,
- passwordString
- );
+ TorSettings.proxy.enabled = true;
+ TorSettings.proxy.type = type;
+ TorSettings.proxy.address = address;
+ TorSettings.proxy.port = port;
+ TorSettings.proxy.username = username;
+ TorSettings.proxy.password = password;
break;
}
+ TorSettings.saveToPrefs();
+ TorSettings.applySettings();
- proxySettings.writeSettings();
- this._proxySettings = proxySettings;
return this;
},
@@ -953,21 +915,20 @@ const gTorPane = (function() {
// pushes firewall settings from UI to tor
onUpdateFirewallSettings() {
+
let portListString = this._useFirewallCheckbox.checked
? this._allowedPortsTextbox.value
: "";
- let firewallSettings = null;
if (portListString) {
- firewallSettings = makeTorFirewallSettingsCustom(
- parsePortList(portListString)
- );
+ TorSettings.firewall.enabled = true;
+ TorSettings.firewall.allowed_ports = portListString;
} else {
- firewallSettings = makeTorFirewallSettingsNone();
+ TorSettings.firewall.enabled = false;
}
+ TorSettings.saveToPrefs();
+ TorSettings.applySettings();
- firewallSettings.writeSettings();
- this._firewallSettings = firewallSettings;
return this;
},
diff --git a/browser/components/torpreferences/content/torProxySettings.jsm b/browser/components/torpreferences/content/torProxySettings.jsm
deleted file mode 100644
index 98bb5e8d5cbf..000000000000
--- a/browser/components/torpreferences/content/torProxySettings.jsm
+++ /dev/null
@@ -1,245 +0,0 @@
-"use strict";
-
-var EXPORTED_SYMBOLS = [
- "TorProxyType",
- "TorProxySettings",
- "makeTorProxySettingsNone",
- "makeTorProxySettingsSocks4",
- "makeTorProxySettingsSocks5",
- "makeTorProxySettingsHTTPS",
-];
-
-const { TorProtocolService } = ChromeUtils.import(
- "resource:///modules/TorProtocolService.jsm"
-);
-const { TorStrings } = ChromeUtils.import("resource:///modules/TorStrings.jsm");
-const { parseAddrPort, parseUsernamePassword } = ChromeUtils.import(
- "chrome://browser/content/torpreferences/parseFunctions.jsm"
-);
-
-const TorProxyType = {
- NONE: "NONE",
- SOCKS4: "SOCKS4",
- SOCKS5: "SOCKS5",
- HTTPS: "HTTPS",
-};
-
-class TorProxySettings {
- constructor() {
- this._proxyType = TorProxyType.NONE;
- this._proxyAddress = undefined;
- this._proxyPort = undefined;
- this._proxyUsername = undefined;
- this._proxyPassword = undefined;
- }
-
- get type() {
- return this._proxyType;
- }
- get address() {
- return this._proxyAddress;
- }
- get port() {
- return this._proxyPort;
- }
- get username() {
- return this._proxyUsername;
- }
- get password() {
- return this._proxyPassword;
- }
- get proxyURI() {
- switch (this._proxyType) {
- case TorProxyType.SOCKS4:
- return `socks4a://${this._proxyAddress}:${this._proxyPort}`;
- case TorProxyType.SOCKS5:
- if (this._proxyUsername) {
- return `socks5://${this._proxyUsername}:${this._proxyPassword}@${
- this._proxyAddress
- }:${this._proxyPort}`;
- }
- return `socks5://${this._proxyAddress}:${this._proxyPort}`;
- case TorProxyType.HTTPS:
- if (this._proxyUsername) {
- return `http://${this._proxyUsername}:${this._proxyPassword}@${
- this._proxyAddress
- }:${this._proxyPort}`;
- }
- return `http://${this._proxyAddress}:${this._proxyPort}`;
- }
- return undefined;
- }
-
- // attempts to read proxy settings from Tor daemon
- readSettings() {
- // SOCKS4
- {
- let addressPort = TorProtocolService.readStringSetting(
- TorStrings.configKeys.socks4Proxy
- );
- if (addressPort) {
- // address+port
- let [proxyAddress, proxyPort] = parseAddrPort(addressPort);
-
- this._proxyType = TorProxyType.SOCKS4;
- this._proxyAddress = proxyAddress;
- this._proxyPort = proxyPort;
- this._proxyUsername = "";
- this._proxyPassword = "";
-
- return;
- }
- }
-
- // SOCKS5
- {
- let addressPort = TorProtocolService.readStringSetting(
- TorStrings.configKeys.socks5Proxy
- );
-
- if (addressPort) {
- // address+port
- let [proxyAddress, proxyPort] = parseAddrPort(addressPort);
- // username
- let proxyUsername = TorProtocolService.readStringSetting(
- TorStrings.configKeys.socks5ProxyUsername
- );
- // password
- let proxyPassword = TorProtocolService.readStringSetting(
- TorStrings.configKeys.socks5ProxyPassword
- );
-
- this._proxyType = TorProxyType.SOCKS5;
- this._proxyAddress = proxyAddress;
- this._proxyPort = proxyPort;
- this._proxyUsername = proxyUsername;
- this._proxyPassword = proxyPassword;
-
- return;
- }
- }
-
- // HTTP
- {
- let addressPort = TorProtocolService.readStringSetting(
- TorStrings.configKeys.httpsProxy
- );
-
- if (addressPort) {
- // address+port
- let [proxyAddress, proxyPort] = parseAddrPort(addressPort);
-
- // username:password
- let proxyAuthenticator = TorProtocolService.readStringSetting(
- TorStrings.configKeys.httpsProxyAuthenticator
- );
-
- let [proxyUsername, proxyPassword] = ["", ""];
- if (proxyAuthenticator) {
- [proxyUsername, proxyPassword] = parseUsernamePassword(
- proxyAuthenticator
- );
- }
-
- this._proxyType = TorProxyType.HTTPS;
- this._proxyAddress = proxyAddress;
- this._proxyPort = proxyPort;
- this._proxyUsername = proxyUsername;
- this._proxyPassword = proxyPassword;
- }
- }
- // no proxy settings
- } /* TorProxySettings::ReadFromTor() */
-
- // attempts to write proxy settings to Tor daemon
- // throws on error
- writeSettings() {
- let settingsObject = new Map();
-
- // init proxy related settings to null so Tor daemon resets them
- settingsObject.set(TorStrings.configKeys.socks4Proxy, null);
- settingsObject.set(TorStrings.configKeys.socks5Proxy, null);
- settingsObject.set(TorStrings.configKeys.socks5ProxyUsername, null);
- settingsObject.set(TorStrings.configKeys.socks5ProxyPassword, null);
- settingsObject.set(TorStrings.configKeys.httpsProxy, null);
- settingsObject.set(TorStrings.configKeys.httpsProxyAuthenticator, null);
-
- switch (this._proxyType) {
- case TorProxyType.SOCKS4:
- settingsObject.set(
- TorStrings.configKeys.socks4Proxy,
- `${this._proxyAddress}:${this._proxyPort}`
- );
- break;
- case TorProxyType.SOCKS5:
- settingsObject.set(
- TorStrings.configKeys.socks5Proxy,
- `${this._proxyAddress}:${this._proxyPort}`
- );
- settingsObject.set(
- TorStrings.configKeys.socks5ProxyUsername,
- this._proxyUsername
- );
- settingsObject.set(
- TorStrings.configKeys.socks5ProxyPassword,
- this._proxyPassword
- );
- break;
- case TorProxyType.HTTPS:
- settingsObject.set(
- TorStrings.configKeys.httpsProxy,
- `${this._proxyAddress}:${this._proxyPort}`
- );
- settingsObject.set(
- TorStrings.configKeys.httpsProxyAuthenticator,
- `${this._proxyUsername}:${this._proxyPassword}`
- );
- break;
- }
-
- TorProtocolService.writeSettings(settingsObject);
- } /* TorProxySettings::WriteToTor() */
-}
-
-// factory methods for our various supported proxies
-function makeTorProxySettingsNone() {
- return new TorProxySettings();
-}
-
-function makeTorProxySettingsSocks4(aProxyAddress, aProxyPort) {
- let retval = new TorProxySettings();
- retval._proxyType = TorProxyType.SOCKS4;
- retval._proxyAddress = aProxyAddress;
- retval._proxyPort = aProxyPort;
- return retval;
-}
-
-function makeTorProxySettingsSocks5(
- aProxyAddress,
- aProxyPort,
- aProxyUsername,
- aProxyPassword
-) {
- let retval = new TorProxySettings();
- retval._proxyType = TorProxyType.SOCKS5;
- retval._proxyAddress = aProxyAddress;
- retval._proxyPort = aProxyPort;
- retval._proxyUsername = aProxyUsername;
- retval._proxyPassword = aProxyPassword;
- return retval;
-}
-
-function makeTorProxySettingsHTTPS(
- aProxyAddress,
- aProxyPort,
- aProxyUsername,
- aProxyPassword
-) {
- let retval = new TorProxySettings();
- retval._proxyType = TorProxyType.HTTPS;
- retval._proxyAddress = aProxyAddress;
- retval._proxyPort = aProxyPort;
- retval._proxyUsername = aProxyUsername;
- retval._proxyPassword = aProxyPassword;
- return retval;
-}
diff --git a/browser/components/torpreferences/jar.mn b/browser/components/torpreferences/jar.mn
index 857bc9ee3eac..552c92b2feff 100644
--- a/browser/components/torpreferences/jar.mn
+++ b/browser/components/torpreferences/jar.mn
@@ -1,14 +1,10 @@
browser.jar:
- content/browser/torpreferences/parseFunctions.jsm (content/parseFunctions.jsm)
- content/browser/torpreferences/requestBridgeDialog.xhtml (content/requestBridgeDialog.xhtml)
+ content/browser/torpreferences/requestBridgeDialog.xhtml (content/requestBridgeDialog.xhtml)
content/browser/torpreferences/requestBridgeDialog.jsm (content/requestBridgeDialog.jsm)
- content/browser/torpreferences/torBridgeSettings.jsm (content/torBridgeSettings.jsm)
- content/browser/torpreferences/torCategory.inc.xhtml (content/torCategory.inc.xhtml)
- content/browser/torpreferences/torFirewallSettings.jsm (content/torFirewallSettings.jsm)
+ content/browser/torpreferences/torCategory.inc.xhtml (content/torCategory.inc.xhtml)
content/browser/torpreferences/torLogDialog.jsm (content/torLogDialog.jsm)
- content/browser/torpreferences/torLogDialog.xhtml (content/torLogDialog.xhtml)
+ content/browser/torpreferences/torLogDialog.xhtml (content/torLogDialog.xhtml)
content/browser/torpreferences/torPane.js (content/torPane.js)
- content/browser/torpreferences/torPane.xhtml (content/torPane.xhtml)
+ content/browser/torpreferences/torPane.xhtml (content/torPane.xhtml)
content/browser/torpreferences/torPreferences.css (content/torPreferences.css)
content/browser/torpreferences/torPreferencesIcon.svg (content/torPreferencesIcon.svg)
- content/browser/torpreferences/torProxySettings.jsm (content/torProxySettings.jsm)
diff --git a/browser/modules/TorConnect.jsm b/browser/modules/TorConnect.jsm
index 4be220108d73..ddc14148eb88 100644
--- a/browser/modules/TorConnect.jsm
+++ b/browser/modules/TorConnect.jsm
@@ -18,6 +18,10 @@ const { TorLauncherUtil } = ChromeUtils.import(
"resource://torlauncher/modules/tl-util.jsm"
);
+const { TorSettings, TorSettingsTopics } = ChromeUtils.import(
+ "resource:///modules/TorSettings.jsm"
+);
+
/* Browser observer topis */
const BrowserTopics = Object.freeze({
ProfileAfterChange: "profile-after-change",
@@ -25,7 +29,6 @@ const BrowserTopics = Object.freeze({
/* tor-launcher observer topics */
const TorTopics = Object.freeze({
- ProcessIsReady: "TorProcessIsReady",
BootstrapStatus: "TorBootstrapStatus",
BootstrapError: "TorBootstrapError",
ProcessExited: "TorProcessExited",
@@ -34,7 +37,6 @@ const TorTopics = Object.freeze({
/* Relevant prefs used by tor-launcher */
const TorLauncherPrefs = Object.freeze({
- quickstart: "extensions.torlauncher.quickstart",
prompt_at_startup: "extensions.torlauncher.prompt_at_startup",
});
@@ -250,38 +252,29 @@ const TorConnect = (() => {
// Disabled
this.legacyOrSystemTor();
} else {
- // register the Tor topics we always care about
- for (const topicKey in TorTopics) {
- const topic = TorTopics[topicKey];
+ let observeTopic = (topic) => {
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();
- }
+ // register the Tor topics we always care about
+ for (const topicKey in TorTopics) {
+ const topic = TorTopics[topicKey];
+ observeTopic(topic);
}
+ observeTopic(TorSettingsTopics.Ready);
}
-
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();
- }
+ /* We need to wait until TorSettings have been loaded and applied before we can Quickstart */
+ case TorSettingsTopics.Ready: {
+ if (this.shouldQuickStart) {
+ // Quickstart
+ this.beginBootstrap();
+ } else {
+ // Configuring
+ this.beginConfigure();
}
break;
}
@@ -342,7 +335,7 @@ const TorConnect = (() => {
get shouldQuickStart() {
// quickstart must be enabled
- return Services.prefs.getBoolPref(TorLauncherPrefs.quickstart, false) &&
+ return TorSettings.quickstart.enabled &&
// and the previous bootstrap attempt must have succeeded
!Services.prefs.getBoolPref(TorLauncherPrefs.prompt_at_startup, true);
},
diff --git a/browser/modules/TorSettings.jsm b/browser/modules/TorSettings.jsm
new file mode 100644
index 000000000000..6d2a6c4a07cf
--- /dev/null
+++ b/browser/modules/TorSettings.jsm
@@ -0,0 +1,814 @@
+"use strict";
+
+var EXPORTED_SYMBOLS = ["TorSettings", "TorSettingsTopics", "TorSettingsData", "TorBridgeSource", "TorBuiltinBridgeTypes", "TorProxyType"];
+
+const { Services } = ChromeUtils.import(
+ "resource://gre/modules/Services.jsm"
+);
+
+const { TorProtocolService, TorProcessStatus } = ChromeUtils.import(
+ "resource:///modules/TorProtocolService.jsm"
+);
+
+/* Browser observer topics */
+const BrowserTopics = Object.freeze({
+ ProfileAfterChange: "profile-after-change",
+});
+
+/* tor-launcher observer topics */
+const TorTopics = Object.freeze({
+ ProcessIsReady: "TorProcessIsReady",
+});
+
+/* TorSettings observer topics */
+const TorSettingsTopics = Object.freeze({
+ Ready: "torsettings:ready",
+ SettingChanged: "torsettings:setting-changed",
+});
+
+/* TorSettings observer data (for SettingChanged topic) */
+const TorSettingsData = Object.freeze({
+ QuickStartEnabled : "torsettings:quickstart_enabled",
+});
+
+/* Prefs used to store settings in TorBrowser prefs */
+const TorSettingsPrefs = Object.freeze({
+ /* bool: are we pulling tor settings from the preferences */
+ enabled: 'torbrowser.settings.enabled',
+ quickstart : {
+ /* bool: does tor connect automatically on launch */
+ enabled: 'torbrowser.settings.quickstart.enabled',
+ },
+ bridges : {
+ /* bool: does tor use bridges */
+ enabled : 'torbrowser.settings.bridges.enabled',
+ /* int: -1=invalid|0=builtin|1=bridge_db|2=user_provided */
+ source : 'torbrowser.settings.bridges.source',
+ /* string: obfs4|meek_azure|snowflake|etc */
+ builtin_type : 'torbrowser.settings.bridges.builtin_type',
+ /* preference branch: each child branch should be a bridge string */
+ bridge_strings : 'torbrowser.settings.bridges.bridge_strings',
+ },
+ proxy : {
+ /* bool: does tor use a proxy */
+ enabled : 'torbrowser.settings.proxy.enabled',
+ /* -1=invalid|0=socks4,1=socks5,2=https */
+ type: 'torbrowser.settings.proxy.type',
+ /* string: proxy server address */
+ address: 'torbrowser.settings.proxy.address',
+ /* int: [1,65535], proxy port */
+ port: 'torbrowser.settings.proxy.port',
+ /* string: username */
+ username: 'torbrowser.settings.proxy.username',
+ /* string: password */
+ password: 'torbrowser.settings.proxy.password',
+ },
+ firewall : {
+ /* bool: does tor have a port allow list */
+ enabled: 'torbrowser.settings.firewall.enabled',
+ /* string: comma-delimitted list of port numbers */
+ allowed_ports: 'torbrowser.settings.firewall.allowed_ports',
+ },
+});
+
+/* Legacy tor-launcher prefs and pref branches*/
+const TorLauncherPrefs = Object.freeze({
+ quickstart: "extensions.torlauncher.quickstart",
+ default_bridge_type: "extensions.torlauncher.default_bridge_type",
+ default_bridge: "extensions.torlauncher.default_bridge.",
+ default_bridge_recommended_type: "extensions.torlauncher.default_bridge_recommended_type",
+ bridgedb_bridge: "extensions.torlauncher.bridgedb_bridge.",
+});
+
+/* Config Keys used to configure tor daemon */
+const TorConfigKeys = Object.freeze({
+ useBridges: "UseBridges",
+ bridgeList: "Bridge",
+ socks4Proxy: "Socks4Proxy",
+ socks5Proxy: "Socks5Proxy",
+ socks5ProxyUsername: "Socks5ProxyUsername",
+ socks5ProxyPassword: "Socks5ProxyPassword",
+ httpsProxy: "HTTPSProxy",
+ httpsProxyAuthenticator: "HTTPSProxyAuthenticator",
+ reachableAddresses: "ReachableAddresses",
+ clientTransportPlugin: "ClientTransportPlugin",
+});
+
+const TorBridgeSource = Object.freeze({
+ Invalid: -1,
+ BuiltIn: 0,
+ BridgeDB: 1,
+ UserProvided: 2,
+});
+
+const TorProxyType = Object.freeze({
+ Invalid: -1,
+ Socks4: 0,
+ Socks5: 1,
+ HTTPS: 2,
+});
+
+
+const TorBuiltinBridgeTypes = Object.freeze(
+ (() => {
+ let bridgeListBranch = Services.prefs.getBranch(TorLauncherPrefs.default_bridge);
+ let bridgePrefs = bridgeListBranch.getChildList("");
+
+ // an unordered set for shoving bridge types into
+ let bridgeTypes = new Set();
+ // look for keys ending in ".N" and treat string before that as the bridge type
+ const pattern = /\.[0-9]+$/;
+ for (const key of bridgePrefs) {
+ const offset = key.search(pattern);
+ if (offset != -1) {
+ const bt = key.substring(0, offset);
+ bridgeTypes.add(bt);
+ }
+ }
+
+ // recommended bridge type goes first in the list
+ let recommendedBridgeType = Services.prefs.getCharPref(TorLauncherPrefs.default_bridge_recommended_type, null);
+
+ let retval = [];
+ if (recommendedBridgeType && bridgeTypes.has(recommendedBridgeType)) {
+ retval.push(recommendedBridgeType);
+ }
+
+ for (const bridgeType of bridgeTypes.values()) {
+ if (bridgeType != recommendedBridgeType) {
+ retval.push(bridgeType);
+ }
+ }
+ return retval;
+ })()
+);
+
+/* Parsing Methods */
+
+// expects a string representation of an integer from 1 to 65535
+let parsePort = function(aPort) {
+ // ensure port string is a valid positive integer
+ const validIntRegex = /^[0-9]+$/;
+ if (!validIntRegex.test(aPort)) {
+ return 0;
+ }
+
+ // ensure port value is on valid range
+ let port = Number.parseInt(aPort);
+ if (port < 1 || port > 65535) {
+ return 0;
+ }
+
+ return port;
+};
+// expects a string in the format: "ADDRESS:PORT"
+let parseAddrPort = function(aAddrColonPort) {
+ let tokens = aAddrColonPort.split(":");
+ if (tokens.length != 2) {
+ return ["", 0];
+ }
+ let address = tokens[0];
+ let port = parsePort(tokens[1]);
+ return [address, port];
+};
+
+// expects a string in the format: "USERNAME:PASSWORD"
+// split on the first colon and any subsequent go into password
+let parseUsernamePassword = function(aUsernameColonPassword) {
+ let colonIndex = aUsernameColonPassword.indexOf(":");
+ if (colonIndex < 0) {
+ return ["", ""];
+ }
+
+ let username = aUsernameColonPassword.substring(0, colonIndex);
+ let password = aUsernameColonPassword.substring(colonIndex + 1);
+
+ return [username, password];
+};
+
+// expects a string in the format: ADDRESS:PORT,ADDRESS:PORT,...
+// returns array of ports (as ints)
+let parseAddrPortList = function(aAddrPortList) {
+ let addrPorts = aAddrPortList.split(",");
+ // parse ADDRESS:PORT string and only keep the port (second element in returned array)
+ let retval = addrPorts.map(addrPort => parseAddrPort(addrPort)[1]);
+ return retval;
+};
+
+// expects a '/n' or '/r/n' delimited bridge string, which we split and trim
+// each bridge string can also optionally have 'bridge' at the beginning ie:
+// bridge $(type) $(address):$(port) $(certificate)
+// we strip out the 'bridge' prefix here
+let parseBridgeStrings = function(aBridgeStrings) {
+
+ // replace carriage returns ('\r') with new lines ('\n')
+ aBridgeStrings = aBridgeStrings.replace(/\r/g, "\n");
+ // then replace contiguous new lines ('\n') with a single one
+ aBridgeStrings = aBridgeStrings.replace(/[\n]+/g, "\n");
+
+ // split on the newline and for each bridge string: trim, remove starting 'bridge' string
+ // finally discard entries that are empty strings; empty strings could occur if we receive
+ // a new line containing only whitespace
+ let splitStrings = aBridgeStrings.split("\n");
+ return splitStrings.map(val => val.trim().replace(/^bridge\s+/i, ""))
+ .filter(bridgeString => bridgeString != "");
+};
+
+// expecting a ',' delimited list of ints with possible white space between
+// returns an array of ints
+let parsePortList = function(aPortListString) {
+ let splitStrings = aPortListString.split(",");
+ // parse and remove duplicates
+ let portSet = new Set(splitStrings.map(val => parsePort(val.trim())));
+ // parsePort returns 0 for failed parses, so remove 0 from list
+ portSet.delete(0);
+ return Array.from(portSet);
+};
+
+let getBuiltinBridgeStrings = function(builtinType) {
+ let bridgeBranch = Services.prefs.getBranch(TorLauncherPrefs.default_bridge);
+ let bridgeBranchPrefs = bridgeBranch.getChildList("");
+ let retval = [];
+
+ // regex matches against strings ending in ".N" where N is a positive integer
+ let pattern = /\.[0-9]+$/;
+ for (const key of bridgeBranchPrefs) {
+ // verify the location of the match is the correct offset required for aBridgeType
+ // to fit, and that the string begins with aBridgeType
+ if (key.search(pattern) == builtinType.length &&
+ key.startsWith(builtinType)) {
+ let bridgeStr = bridgeBranch.getCharPref(key);
+ retval.push(bridgeStr);
+ }
+ }
+
+ // shuffle so that Tor Browser users don't all try the built-in bridges in the same order
+ arrayShuffle(retval);
+
+ return retval;
+};
+
+/* Array methods */
+
+let arrayShuffle = function(array) {
+ // fisher-yates shuffle
+ for (let i = array.length - 1; i > 0; --i) {
+ // number n such that 0.0 <= n < 1.0
+ const n = Math.random();
+ // integer j such that 0 <= j <= i
+ const j = Math.floor(n * (i + 1));
+
+ // swap values at indices i and j
+ const tmp = array[i];
+ array[i] = array[j];
+ array[j] = tmp;
+ }
+}
+
+let arrayCopy = function(array) {
+ return [].concat(array);
+}
+
+/* TorSettings module */
+
+const TorSettings = (() => {
+ let self = {
+ _settings: null,
+
+ // tor daemon related settings
+ defaultSettings: function() {
+ let settings = {
+ quickstart: {
+ enabled: false
+ },
+ bridges : {
+ enabled: false,
+ source: TorBridgeSource.Invalid,
+ builtin_type: null,
+ bridge_strings: [],
+ },
+ proxy: {
+ enabled: false,
+ type: TorProxyType.Invalid,
+ address: null,
+ port: 0,
+ username: null,
+ password: null,
+ },
+ firewall: {
+ enabled: false,
+ allowed_ports: [],
+ },
+ };
+ return settings;
+ },
+
+ /* try and load our settings, and register observers */
+ init: function() {
+ if (TorProtocolService.ownsTorDaemon) {
+ // if the settings branch exists, load settings from prefs
+ if (Services.prefs.getBoolPref(TorSettingsPrefs.enabled, false)) {
+ this.loadFromPrefs();
+ Services.obs.notifyObservers(null, TorSettingsTopics.Ready);
+ }
+ Services.obs.addObserver(this, BrowserTopics.ProfileAfterChange);
+ Services.obs.addObserver(this, TorTopics.ProcessIsReady);
+ }
+ },
+
+ /* wait for relevant life-cycle events to load and/or apply saved settings */
+ observe: async function(subject, topic, data) {
+ console.log(`TorSettings: observed ${topic}`);
+
+ // once the process is ready, we need to apply our settings
+ let handleProcessReady = async () => {
+ Services.obs.removeObserver(this, TorTopics.ProcessIsReady);
+ if (this._settings == null) {
+ // load settings from tor if our load in init() failed and save them to prefs
+ await this.loadLegacy();
+ this.saveToPrefs();
+ } else {
+ // push down settings to tor
+ await this.applySettings();
+ }
+ Services.obs.notifyObservers(null, TorSettingsTopics.Ready);
+ };
+
+ switch (topic) {
+ case BrowserTopics.ProfileAfterChange: {
+ if (TorProtocolService.torProcessStatus == TorProcessStatus.Running) {
+ await handleProcessReady();
+ }
+ }
+ break;
+ case TorTopics.ProcessIsReady: {
+ await handleProcessReady();
+ }
+ break;
+ }
+ },
+
+ // load our settings from old locations (misc prefs and from tor daemon)
+ // TODO: remove this after some time has elapsed to ensure users have migrated to pref settings
+ loadLegacy: async function() {
+ console.log("TorSettings: loadLegacy()");
+
+ let settings = this.defaultSettings();
+
+ /* Quickstart */
+ settings.quickstart.enabled = Services.prefs.getBoolPref(TorLauncherPrefs.quickstart, false);
+
+ /* Bridges
+
+ So the way tor-launcher determines the origin of the configured bridges is a bit
+ weird and depends on inferring our scenario based on some firefox prefs and the
+ relationship between the saved list of bridges in about:config vs the list saved in torrc
+
+ first off, if "extensions.torlauncher.default_bridge_type" is set to one of our
+ builtin default types (obfs4, meek-azure, snowflake, etc) then we provide the
+ bridges in "extensions.torlauncher.default_bridge.*" (filtered by our default_bridge_type)
+
+ next, we compare the list of bridges saved in torrc to the bridges stored in the
+ "extensions.torlauncher.bridgedb_bridge."" branch. If they match *exactly* then we assume
+ the bridges were retrieved from BridgeDB and use those. If the torrc list is empty then we know
+ we have no bridge settings
+
+ finally, if none of the previous conditions are not met, it is assumed the bridges stored in
+ torrc are user-provided
+ */
+
+ let builtinType = Services.prefs.getCharPref(TorLauncherPrefs.default_bridge_type, null);
+
+ // check if source is built-in
+ if (builtinType) {
+ let builtinBridgeStrings = getBuiltinBridgeStrings(builtinType);
+ if (builtinBridgeStrings.length > 0) {
+ settings.bridges.enabled = true;
+ settings.bridges.source = TorBridgeSource.BuiltIn;
+ settings.bridges.builtin_type = builtinType;
+ settings.bridges.bridge_strings = builtinBridgeStrings;
+ }
+ } else {
+ // get our currently configured bridges from tor
+ let torrcBridgeStrings = await (async () => {
+ let bridgeList = await TorProtocolService.readStringArraySetting(TorConfigKeys.bridgeList);
+ let retval = [];
+ for (const line of bridgeList) {
+ let trimmedLine = line.trim();
+ if (trimmedLine) {
+ retval.push(trimmedLine);
+ }
+ }
+ return retval;
+ })();
+
+ // torrc has bridges configured
+ if (torrcBridgeStrings.length > 0) {
+ // compare tor's bridges to our saved bridgedb bridges
+ let bridgedbBBridgeStrings = (() => {
+ let bridgeBranch = Services.prefs.getBranch(TorLauncherPrefs.bridgedb_bridge);
+ let bridgeBranchPrefs = bridgeBranch.getChildList("");
+ // the child prefs do not come in any particular order so sort the keys
+ // so the values can be compared to what we get out off torrc
+ bridgeBranchPrefs.sort();
+
+ // just assume all of the prefs under the parent point to valid bridge string
+ let retval = bridgeBranchPrefs.map(key =>
+ bridgeBranch.getCharPref(key).trim()
+ );
+ return retval;
+ })();
+
+ let arraysEqual = (left, right) => {
+ if (left.length != right.length) {
+ return false;
+ }
+ const length = left.length;
+ for (let i = 0; i < length; ++i) {
+ if (left[i] != right[i]) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ if (arraysEqual(torrcBridgeStrings, bridgedbBBridgeStrings)) {
+ settings.bridges.enabled = true;
+ settings.bridges.source = TorBridgeSource.BridgeDB;
+ settings.bridges.builtin_type = null;
+ settings.bridges.bridge_strings = torrcBridgeStrings;
+ } else {
+ settings.bridges.enabled = true;
+ settings.bridges.source = TorBridgeSource.UserProvided;
+ settings.bridges.builtin_type = null;
+ settings.bridges.bridge_strings = torrcBridgeStrings;
+ }
+ } else {
+ // tor has no bridge strings saved, so bridges not in use
+ settings.bridges.enabled = false;
+ settings.bridges.source = TorBridgeSource.Invalid;
+ settings.bridges.builtin_type = null;
+ settings.bridges.bridge_strings = [];
+ }
+ }
+
+ /* Proxy */
+
+ let proxyString = null;
+ if (proxyString = await TorProtocolService.readStringSetting(TorConfigKeys.socks4Proxy)) {
+ let [address, port] = parseAddrPort(proxyString);
+
+ settings.proxy.enabled = true;
+ settings.proxy.type = TorProxyType.Socks4;
+ settings.proxy.address = address;
+ settings.proxy.port = port;
+ settings.proxy.username = null;
+ settings.proxy.password = null;
+ } else if (proxyString = await TorProtocolService.readStringSetting(TorConfigKeys.socks5Proxy)) {
+ let [address, port] = parseAddrPort(proxyString);
+ let username = await TorProtocolService.readStringSetting(TorConfigKeys.socks5ProxyUsername);
+ let password = await TorProtocolService.readStringSetting(TorConfigKeys.socks5ProxyPassword);
+
+ settings.proxy.enabled = true;
+ settings.proxy.type = TorProxyType.Socks5;
+ settings.proxy.address = address;
+ settings.proxy.port = port;
+ settings.proxy.username = username;
+ settings.proxy.password = password;
+ } else if (proxyString = await TorProtocolService.readStringSetting(TorConfigKeys.httpsProxy)) {
+ let [address, port] = parseAddrPort(proxyString);
+ let authenticator = await TorProtocolService.readStringSetting(TorConfigKeys.httpsProxyAuthenticator);
+ let [username, password] = parseUsernamePassword(authenticator);
+
+ settings.proxy.enabled = true;
+ settings.proxy.type = TorProxyType.HTTPS;
+ settings.proxy.address = address;
+ settings.proxy.port = port;
+ settings.proxy.username = username;
+ settings.proxy.password = password;
+ } else {
+ settings.proxy.enabled = false;
+ settings.proxy.type = TorProxyType.Invalid;
+ settings.proxy.address = null;
+ settings.proxy.port = 0;
+ settings.proxy.username = null;
+ settings.proxy.password = null;
+ }
+
+ /* Firewall */
+ let firewallString = await TorProtocolService.readStringSetting(TorConfigKeys.reachableAddresses);
+ if (firewallString) {
+ let allowedPorts = parseAddrPortList(firewallString);
+ settings.firewall.enabled = allowedPorts.length > 0;
+ settings.firewall.allowed_ports = allowedPorts;
+ } else {
+ settings.firewall.enabled = false;
+ settings.firewall.allowed_ports = [];
+ }
+
+ this._settings = settings;
+
+ return this;
+ },
+
+ // load our settings from prefs
+ loadFromPrefs: function() {
+ console.log("TorSettings: loadFromPrefs()");
+
+ let settings = this.defaultSettings();
+
+ /* Quickstart */
+ settings.quickstart.enabled = Services.prefs.getBoolPref(TorSettingsPrefs.quickstart.enabled);
+ /* Bridges */
+ settings.bridges.enabled = Services.prefs.getBoolPref(TorSettingsPrefs.bridges.enabled);
+ if (settings.bridges.enabled) {
+ settings.bridges.source = Services.prefs.getIntPref(TorSettingsPrefs.bridges.source);
+ // builtin bridge (obfs4, meek, snowlfake, etc)
+ if (settings.bridges.source == TorBridgeSource.BuiltIn) {
+ let builtinType = Services.prefs.getStringPref(TorSettingsPrefs.bridges.builtin_type);
+ settings.bridges.builtin_type = builtinType;
+ // always dynamically load builtin bridges rather than loading the cached versions
+ // if the user upgrades and the builtin bridges have changed, we want to ensure the user
+ // can still bootstrap using the provided bridges
+ let bridgeStrings = getBuiltinBridgeStrings(builtinType);
+ if (bridgeStrings.length > 0) {
+ settings.bridges.bridge_strings = bridgeStrings;
+ } else {
+ // in this case the user is using a builtin bridge that is no longer supported,
+ // reset to settings to default values
+ settings.bridges.enabled = false;
+ settings.bridges.source = TorBridgeSource.Invalid;
+ settings.bridges.builtin_type = null;
+ }
+ } else {
+ settings.bridges.bridge_strings = [];
+ let bridgeBranchPrefs = Services.prefs.getBranch(TorSettingsPrefs.bridges.bridge_strings).getChildList("");
+ bridgeBranchPrefs.forEach(pref => {
+ let bridgeString = Services.prefs.getStringPref(`${TorSettingsPrefs.bridges.bridge_strings}${pref}`);
+ settings.bridges.bridge_strings.push(bridgeString);
+ });
+ }
+ } else {
+ settings.bridges.source = TorBridgeSource.Invalid;
+ settings.bridges.builtin_type = null;
+ settings.bridges.bridge_strings = [];
+ }
+ /* Proxy */
+ settings.proxy.enabled = Services.prefs.getBoolPref(TorSettingsPrefs.proxy.enabled);
+ if (settings.proxy.enabled) {
+ settings.proxy.type = Services.prefs.getIntPref(TorSettingsPrefs.proxy.type);
+ settings.proxy.address = Services.prefs.getStringPref(TorSettingsPrefs.proxy.address);
+ settings.proxy.port = Services.prefs.getIntPref(TorSettingsPrefs.proxy.port);
+ settings.proxy.username = Services.prefs.getStringPref(TorSettingsPrefs.proxy.username);
+ settings.proxy.password = Services.prefs.getStringPref(TorSettingsPrefs.proxy.password);
+ } else {
+ settings.proxy.type = TorProxyType.Invalid;
+ settings.proxy.address = null;
+ settings.proxy.port = 0;
+ settings.proxy.username = null;
+ settings.proxy.password = null;
+ }
+
+ /* Firewall */
+ settings.firewall.enabled = Services.prefs.getBoolPref(TorSettingsPrefs.firewall.enabled);
+ if(settings.firewall.enabled) {
+ let portList = Services.prefs.getStringPref(TorSettingsPrefs.firewall.allowed_ports);
+ settings.firewall.allowed_ports = parsePortList(portList);
+ } else {
+ settings.firewall.allowed_ports = 0;
+ }
+
+ this._settings = settings;
+
+ return this;
+ },
+
+ // save our settings to prefs
+ saveToPrefs: function() {
+ console.log("TorSettings: saveToPrefs()");
+
+ let settings = this._settings;
+
+ /* Quickstart */
+ Services.prefs.setBoolPref(TorSettingsPrefs.quickstart.enabled, settings.quickstart.enabled);
+ /* Bridges */
+ Services.prefs.setBoolPref(TorSettingsPrefs.bridges.enabled, settings.bridges.enabled);
+ if (settings.bridges.enabled) {
+ Services.prefs.setIntPref(TorSettingsPrefs.bridges.source, settings.bridges.source);
+ if (settings.bridges.source === TorBridgeSource.BuiltIn) {
+ Services.prefs.setStringPref(TorSettingsPrefs.bridges.builtin_type, settings.bridges.builtin_type);
+ } else {
+ Services.prefs.clearUserPref(TorSettingsPrefs.bridges.builtin_type);
+ }
+ // erase existing bridge strings
+ let bridgeBranchPrefs = Services.prefs.getBranch(TorSettingsPrefs.bridges.bridge_strings).getChildList("");
+ bridgeBranchPrefs.forEach(pref => {
+ Services.prefs.clearUserPref(`${TorSettingsPrefs.bridges.bridge_strings}${pref}`);
+ });
+ // write new ones
+ settings.bridges.bridge_strings.forEach((string, index) => {
+ Services.prefs.setStringPref(`${TorSettingsPrefs.bridges.bridge_strings}.${index}`, string);
+ });
+ } else {
+ Services.prefs.clearUserPref(TorSettingsPrefs.bridges.source);
+ Services.prefs.clearUserPref(TorSettingsPrefs.bridges.builtin_type);
+ let bridgeBranchPrefs = Services.prefs.getBranch(TorSettingsPrefs.bridges.bridge_strings).getChildList("");
+ bridgeBranchPrefs.forEach(pref => {
+ Services.prefs.clearUserPref(`${TorSettingsPrefs.bridges.bridge_strings}${pref}`);
+ });
+ }
+ /* Proxy */
+ Services.prefs.setBoolPref(TorSettingsPrefs.proxy.enabled, settings.proxy.enabled);
+ if (settings.proxy.enabled) {
+ Services.prefs.setIntPref(TorSettingsPrefs.proxy.type, settings.proxy.type);
+ Services.prefs.setStringPref(TorSettingsPrefs.proxy.address, settings.proxy.address);
+ Services.prefs.setIntPref(TorSettingsPrefs.proxy.port, settings.proxy.port);
+ Services.prefs.setStringPref(TorSettingsPrefs.proxy.username, settings.proxy.username);
+ Services.prefs.setStringPref(TorSettingsPrefs.proxy.password, settings.proxy.password);
+ } else {
+ Services.prefs.clearUserPref(TorSettingsPrefs.proxy.type);
+ Services.prefs.clearUserPref(TorSettingsPrefs.proxy.address);
+ Services.prefs.clearUserPref(TorSettingsPrefs.proxy.port);
+ Services.prefs.clearUserPref(TorSettingsPrefs.proxy.username);
+ Services.prefs.clearUserPref(TorSettingsPrefs.proxy.password);
+ }
+ /* Firewall */
+ Services.prefs.setBoolPref(TorSettingsPrefs.firewall.enabled, settings.firewall.enabled);
+ if (settings.firewall.enabled) {
+ Services.prefs.setStringPref(TorSettingsPrefs.firewall.allowed_ports, settings.firewall.allowed_ports.join(","));
+ } else {
+ Services.prefs.clearUserPref(TorSettingsPrefs.firewall.allowed_ports);
+ }
+
+ // all tor settings now stored in prefs :)
+ Services.prefs.setBoolPref(TorSettingsPrefs.enabled, true);
+
+ return this;
+ },
+
+ // push our settings down to the tor daemon
+ applySettings: async function() {
+ console.log("TorSettings: applySettings()");
+ let settings = this._settings;
+ let settingsMap = new Map();
+
+ /* Bridges */
+ settingsMap.set(TorConfigKeys.useBridges, settings.bridges.enabled);
+ if (settings.bridges.enabled) {
+ settingsMap.set(TorConfigKeys.bridgeList, settings.bridges.bridge_strings);
+ } else {
+ // shuffle bridge list
+ settingsMap.set(TorConfigKeys.bridgeList, null);
+ }
+
+ /* Proxy */
+ settingsMap.set(TorConfigKeys.socks4Proxy, null);
+ settingsMap.set(TorConfigKeys.socks5Proxy, null);
+ settingsMap.set(TorConfigKeys.socks5ProxyUsername, null);
+ settingsMap.set(TorConfigKeys.socks5ProxyPassword, null);
+ settingsMap.set(TorConfigKeys.httpsProxy, null);
+ settingsMap.set(TorConfigKeys.httpsProxyAuthenticator, null);
+ if (settings.proxy.enabled) {
+ let address = settings.proxy.address;
+ let port = settings.proxy.port;
+ let username = settings.proxy.username;
+ let password = settings.proxy.password;
+
+ switch (settings.proxy.type) {
+ case TorProxyType.Socks4:
+ settingsMap.set(TorConfigKeys.socks4Proxy, `${address}:${port}`);
+ break;
+ case TorProxyType.Socks5:
+ settingsMap.set(TorConfigKeys.socks5Proxy, `${address}:${port}`);
+ settingsMap.set(TorConfigKeys.socks5ProxyUsername, username);
+ settingsMap.set(TorConfigKeys.socks5ProxyPassword, password);
+ break;
+ case TorProxyType.HTTPS:
+ settingsMap.set(TorConfigKeys.httpsProxy, `${address}:${port}`);
+ settingsMap.set(TorConfigKeys.httpsProxyAuthenticator, `${username}:${password}`);
+ break;
+ }
+ }
+
+ /* Firewall */
+ if (settings.firewall.enabled) {
+ let reachableAddresses = settings.firewall.allowed_ports.map(port => `*:${port}`).join(",");
+ settingsMap.set(TorConfigKeys.reachableAddresses, reachableAddresses);
+ } else {
+ settingsMap.set(TorConfigKeys.reachableAddresses, null);
+ }
+
+ /* Push to Tor */
+ await TorProtocolService.writeSettings(settingsMap);
+
+ return this;
+ },
+
+ /* Getters and Setters */
+
+
+ // Quickstart
+ get quickstart() {
+ return {
+ // Avoid a race-condition on first-start where this property
+ // may be accessed before `self._settings` is initialized.
+ // This work-around can be removed when #40598 is resolved.
+ get enabled() { return (self._settings ? self._settings.quickstart.enabled : false); },
+ set enabled(val) {
+ if (val != self._settings.quickstart.enabled)
+ {
+ self._settings.quickstart.enabled = val;
+ Services.obs.notifyObservers({value: val}, TorSettingsTopics.SettingChanged, TorSettingsData.QuickStartEnabled);
+ }
+ },
+ };
+ },
+
+ // Bridges
+ get bridges() {
+ return {
+ get enabled() { return self._settings.bridges.enabled; },
+ set enabled(val) {
+ self._settings.bridges.enabled = val;
+ // reset bridge settings
+ self._settings.bridges.source = TorBridgeSource.Invalid;
+ self._settings.bridges.builtin_type = null;
+ self._settings.bridges.bridge_strings = [];
+ },
+ get source() { return self._settings.bridges.source; },
+ set source(val) { self._settings.bridges.source = val; },
+ get builtin_type() { return self._settings.bridges.builtin_type; },
+ set builtin_type(val) {
+ let bridgeStrings = getBuiltinBridgeStrings(val);
+ if (bridgeStrings.length > 0) {
+ self._settings.bridges.builtin_type = val;
+ self._settings.bridges.bridge_strings = bridgeStrings;
+ }
+ },
+ get bridge_strings() { return arrayCopy(self._settings.bridges.bridge_strings); },
+ set bridge_strings(val) {
+ self._settings.bridges.bridge_strings = parseBridgeStrings(val);
+ },
+ };
+ },
+
+ // Proxy
+ get proxy() {
+ return {
+ get enabled() { return self._settings.proxy.enabled; },
+ set enabled(val) {
+ self._settings.proxy.enabled = val;
+ // reset proxy settings
+ self._settings.proxy.type = TorProxyType.Invalid;
+ self._settings.proxy.address = null;
+ self._settings.proxy.port = 0;
+ self._settings.proxy.username = null;
+ self._settings.proxy.password = null;
+ },
+ get type() { return self._settings.proxy.type; },
+ set type(val) { self._settings.proxy.type = val; },
+ get address() { return self._settings.proxy.address; },
+ set address(val) { self._settings.proxy.address = val; },
+ get port() { return arrayCopy(self._settings.proxy.port); },
+ set port(val) { self._settings.proxy.port = parsePort(val); },
+ get username() { return self._settings.proxy.username; },
+ set username(val) { self._settings.proxy.username = val; },
+ get password() { return self._settings.proxy.password; },
+ set password(val) { self._settings.proxy.password = val; },
+ get uri() {
+ switch (this.type) {
+ case TorProxyType.Socks4:
+ return `socks4a://${this.address}:${this.port}`;
+ case TorProxyType.Socks5:
+ if (this.username) {
+ return `socks5://${this.username}:${this.password}@${this.address}:${this.port}`;
+ }
+ return `socks5://${this.address}:${this.port}`;
+ case TorProxyType.HTTPS:
+ if (this._proxyUsername) {
+ return `http://${this.username}:${this.password}@${this.address}:${this.port}`;
+ }
+ return `http://${this.address}:${this.port}`;
+ }
+ return null;
+ },
+ };
+ },
+
+ // Firewall
+ get firewall() {
+ return {
+ get enabled() { return self._settings.firewall.enabled; },
+ set enabled(val) {
+ self._settings.firewall.enabled = val;
+ // reset firewall settings
+ self._settings.firewall.allowed_ports = [];
+ },
+ get allowed_ports() { return self._settings.firewall.allowed_ports; },
+ set allowed_ports(val) { self._settings.firewall.allowed_ports = parsePortList(val); },
+ };
+ },
+ };
+ self.init();
+ return self;
+})();
diff --git a/browser/modules/moz.build b/browser/modules/moz.build
index 1ea57aba1a93..8c001d4ac6ed 100644
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -156,6 +156,7 @@ EXTRA_JS_MODULES += [
'TorConnect.jsm',
'TorProcessService.jsm',
"TorProtocolService.jsm",
+ "TorSettings.jsm",
"TorStrings.jsm",
"TransientPrefs.jsm",
"webrtcUI.jsm",
diff --git a/toolkit/components/processsingleton/MainProcessSingleton.jsm b/toolkit/components/processsingleton/MainProcessSingleton.jsm
index 62afa98e1ffc..ba8cd0f3f97d 100644
--- a/toolkit/components/processsingleton/MainProcessSingleton.jsm
+++ b/toolkit/components/processsingleton/MainProcessSingleton.jsm
@@ -24,6 +24,11 @@ MainProcessSingleton.prototype = {
null
);
+ ChromeUtils.import(
+ "resource:///modules/TorSettings.jsm",
+ null
+ );
+
ChromeUtils.import(
"resource:///modules/TorConnect.jsm",
null
diff --git a/toolkit/modules/AsyncPrefs.jsm b/toolkit/modules/AsyncPrefs.jsm
index f7d867e47dc0..2834c484c919 100644
--- a/toolkit/modules/AsyncPrefs.jsm
+++ b/toolkit/modules/AsyncPrefs.jsm
@@ -20,7 +20,6 @@ const kAllowedPrefs = new Set([
"browser.contentblocking.report.hide_vpn_banner",
"browser.contentblocking.report.show_mobile_app",
- "extensions.torlauncher.quickstart",
"narrate.rate",
"narrate.voice",
1
0
[tor-browser/tor-browser-91.6.0esr-11.0-1] Bug 40253: Explicitly allow NoScript in Private Browsing mode.
by richard@torproject.org 02 Feb '22
by richard@torproject.org 02 Feb '22
02 Feb '22
commit 21b1b5c81f0d19da823033d43943ae4cb11c04b5
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Fri Sep 3 14:58:28 2021 +0000
Bug 40253: Explicitly allow NoScript in Private Browsing mode.
---
toolkit/components/extensions/Extension.jsm | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/toolkit/components/extensions/Extension.jsm b/toolkit/components/extensions/Extension.jsm
index 783ec7c3391d..1d72f88b276d 100644
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -2644,6 +2644,15 @@ class Extension extends ExtensionData {
this.permissions.add(PRIVATE_ALLOWED_PERMISSION);
}
+ // Bug 40253: Explicitly allow NoScript in Private Browsing mode.
+ if (this.id === "{73a6fe31-595d-460b-a920-fcc0f8843232}") {
+ ExtensionPermissions.add(this.id, {
+ permissions: [PRIVATE_ALLOWED_PERMISSION],
+ origins: [],
+ });
+ this.permissions.add(PRIVATE_ALLOWED_PERMISSION);
+ }
+
// We only want to update the SVG_CONTEXT_PROPERTIES_PERMISSION during install and
// upgrade/downgrade startups.
if (INSTALL_AND_UPDATE_STARTUP_REASONS.has(this.startupReason)) {
1
0
[tor-browser/tor-browser-91.6.0esr-11.0-1] Revert "Bug 1724777, optimize suppressed MicroTask handling, r=mccr8 a=RyanVM"
by richard@torproject.org 02 Feb '22
by richard@torproject.org 02 Feb '22
02 Feb '22
commit a604c41a854aa1495600a78b32d0d6020b5051ad
Author: Georg Koppen <gk(a)torproject.org>
Date: Tue Dec 7 16:19:15 2021 +0000
Revert "Bug 1724777, optimize suppressed MicroTask handling, r=mccr8 a=RyanVM"
This reverts commit 1eb1364357ac5bc2a4531337fb5416af39c3793f.
This fixes tor-browser#40721, tor-browser#40698, and tor-browser#40706.
---
dom/base/Document.cpp | 12 ------
dom/base/Document.h | 8 +++-
dom/base/test/mochitest.ini | 2 -
dom/base/test/test_suppressed_microtasks.html | 62 ---------------------------
dom/workers/RuntimeService.cpp | 4 +-
dom/workers/WorkerPrivate.cpp | 2 +-
dom/worklet/WorkletThread.cpp | 2 +-
xpcom/base/CycleCollectedJSContext.cpp | 51 ++++++----------------
xpcom/base/CycleCollectedJSContext.h | 29 +++----------
9 files changed, 28 insertions(+), 144 deletions(-)
diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp
index 7e103e2705d1..2973457ec3de 100644
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -15665,18 +15665,6 @@ nsAutoSyncOperation::~nsAutoSyncOperation() {
}
}
-void Document::SetIsInSyncOperation(bool aSync) {
- if (CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get()) {
- ccjs->UpdateMicroTaskSuppressionGeneration();
- }
-
- if (aSync) {
- ++mInSyncOperationCount;
- } else {
- --mInSyncOperationCount;
- }
-}
-
gfxUserFontSet* Document::GetUserFontSet() {
if (!mFontFaceSet) {
return nullptr;
diff --git a/dom/base/Document.h b/dom/base/Document.h
index c8de049526ea..7ef73651d47f 100644
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -3214,7 +3214,13 @@ class Document : public nsINode,
bool IsInSyncOperation() { return mInSyncOperationCount != 0; }
- void SetIsInSyncOperation(bool aSync);
+ void SetIsInSyncOperation(bool aSync) {
+ if (aSync) {
+ ++mInSyncOperationCount;
+ } else {
+ --mInSyncOperationCount;
+ }
+ }
bool CreatingStaticClone() const { return mCreatingStaticClone; }
diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini
index 06b5691422c5..e287a0d10ae8 100644
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -769,8 +769,6 @@ skip-if = debug == false
[test_shared_compartment2.html]
[test_structuredclone_backref.html]
[test_style_cssText.html]
-[test_suppressed_microtasks.html]
-skip-if = debug || asan || verify || toolkit == 'android' # The test needs to run reasonably fast.
[test_text_wholeText.html]
[test_textnode_normalize_in_selection.html]
[test_textnode_split_in_selection.html]
diff --git a/dom/base/test/test_suppressed_microtasks.html b/dom/base/test/test_suppressed_microtasks.html
deleted file mode 100644
index f5d333638698..000000000000
--- a/dom/base/test/test_suppressed_microtasks.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <meta charset="utf-8">
- <title>Test microtask suppression</title>
- <script src="/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
- <script>
- SimpleTest.waitForExplicitFinish();
-
- var previousTask = -1;
- function test() {
- let win = window.open("about:blank");
- win.onload = function() {
- win.onmessage = function() {
- win.start = win.performance.now();
- win.didRunMicrotask = false;
- win.onmessage = function() {
- ok(win.didRunMicrotask, "Should have run a microtask.");
- let period = win.performance.now() - win.start;
- win.opener.ok(
- period < 200,
- "Running a task should be fast. Took " + period + "ms.");
- win.onmessage = null;
- }
- win.queueMicrotask(function() { win.didRunMicrotask = true; });
- win.postMessage("measurementMessage", "*");
- }
- win.postMessage("initialMessage", "*");
-
- const last = 500000;
- for (let i = 0; i < last + 1; ++i) {
- window.queueMicrotask(function() {
- // Check that once microtasks are unsuppressed, they are handled in
- // the correct order.
- if (previousTask != i - 1) {
- // Explicitly optimize out cases which pass.
- ok(false, "Microtasks should be handled in order.");
- }
- previousTask = i;
- if (i == last) {
- win.close();
- SimpleTest.finish();
- }
- });
- }
-
- // Synchronous XMLHttpRequest suppresses microtasks.
- var xhr = new XMLHttpRequest();
- xhr.open("GET", "slow.sjs", false);
- xhr.send();
- is(previousTask, -1, "Shouldn't have run microtasks during a sync XHR.");
- }
- }
- </script>
-</head>
-<body onload="test()">
-<p id="display"></p>
-<div id="content" style="display: none"></div>
-<pre id="test"></pre>
-</body>
-</html>
diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp
index c3e3f56834d7..3fda0a78fd23 100644
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -931,7 +931,7 @@ class WorkerJSContext final : public mozilla::CycleCollectedJSContext {
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(runnable);
- std::deque<RefPtr<MicroTaskRunnable>>* microTaskQueue = nullptr;
+ std::queue<RefPtr<MicroTaskRunnable>>* microTaskQueue = nullptr;
JSContext* cx = Context();
NS_ASSERTION(cx, "This should never be null!");
@@ -953,7 +953,7 @@ class WorkerJSContext final : public mozilla::CycleCollectedJSContext {
}
JS::JobQueueMayNotBeEmpty(cx);
- microTaskQueue->push_back(std::move(runnable));
+ microTaskQueue->push(std::move(runnable));
}
bool IsSystemCaller() const override {
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
index 506ef24185c4..6907a3ae816c 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -4313,7 +4313,7 @@ void WorkerPrivate::EnterDebuggerEventLoop() {
{
MutexAutoLock lock(mMutex);
- std::deque<RefPtr<MicroTaskRunnable>>& debuggerMtQueue =
+ std::queue<RefPtr<MicroTaskRunnable>>& debuggerMtQueue =
ccjscx->GetDebuggerMicroTaskQueue();
while (mControlQueue.IsEmpty() &&
!(debuggerRunnablesPending = !mDebuggerQueue.IsEmpty()) &&
diff --git a/dom/worklet/WorkletThread.cpp b/dom/worklet/WorkletThread.cpp
index fae1a1c550d1..c672dfb21b8b 100644
--- a/dom/worklet/WorkletThread.cpp
+++ b/dom/worklet/WorkletThread.cpp
@@ -159,7 +159,7 @@ class WorkletJSContext final : public CycleCollectedJSContext {
#endif
JS::JobQueueMayNotBeEmpty(cx);
- GetMicroTaskQueue().push_back(std::move(runnable));
+ GetMicroTaskQueue().push(std::move(runnable));
}
bool IsSystemCaller() const override {
diff --git a/xpcom/base/CycleCollectedJSContext.cpp b/xpcom/base/CycleCollectedJSContext.cpp
index 0a35a5cf5524..347f15c82322 100644
--- a/xpcom/base/CycleCollectedJSContext.cpp
+++ b/xpcom/base/CycleCollectedJSContext.cpp
@@ -61,7 +61,6 @@ CycleCollectedJSContext::CycleCollectedJSContext()
mDoingStableStates(false),
mTargetedMicroTaskRecursionDepth(0),
mMicroTaskLevel(0),
- mSuppressionGeneration(0),
mDebuggerRecursionDepth(0),
mMicroTaskRecursionDepth(0),
mFinalizationRegistryCleanup(this) {
@@ -292,7 +291,7 @@ class CycleCollectedJSContext::SavedMicroTaskQueue
private:
CycleCollectedJSContext* ccjs;
- std::deque<RefPtr<MicroTaskRunnable>> mQueue;
+ std::queue<RefPtr<MicroTaskRunnable>> mQueue;
};
js::UniquePtr<JS::JobQueue::SavedJobQueue>
@@ -380,13 +379,13 @@ void CycleCollectedJSContext::SetPendingException(Exception* aException) {
mPendingException = aException;
}
-std::deque<RefPtr<MicroTaskRunnable>>&
+std::queue<RefPtr<MicroTaskRunnable>>&
CycleCollectedJSContext::GetMicroTaskQueue() {
MOZ_ASSERT(mJSContext);
return mPendingMicroTaskRunnables;
}
-std::deque<RefPtr<MicroTaskRunnable>>&
+std::queue<RefPtr<MicroTaskRunnable>>&
CycleCollectedJSContext::GetDebuggerMicroTaskQueue() {
MOZ_ASSERT(mJSContext);
return mDebuggerMicroTaskQueue;
@@ -563,7 +562,7 @@ void CycleCollectedJSContext::DispatchToMicroTask(
JS::JobQueueMayNotBeEmpty(Context());
LogMicroTaskRunnable::LogDispatch(runnable.get());
- mPendingMicroTaskRunnables.push_back(std::move(runnable));
+ mPendingMicroTaskRunnables.push(std::move(runnable));
}
class AsyncMutationHandler final : public mozilla::Runnable {
@@ -582,25 +581,6 @@ class AsyncMutationHandler final : public mozilla::Runnable {
}
};
-SuppressedMicroTasks::SuppressedMicroTasks(CycleCollectedJSContext* aContext)
- : mContext(aContext),
- mSuppressionGeneration(aContext->mSuppressionGeneration) {}
-
-bool SuppressedMicroTasks::Suppressed() {
- if (mSuppressionGeneration == mContext->mSuppressionGeneration) {
- return true;
- }
-
- for (std::deque<RefPtr<MicroTaskRunnable>>::reverse_iterator it =
- mSuppressedMicroTaskRunnables.rbegin();
- it != mSuppressedMicroTaskRunnables.rend(); ++it) {
- mContext->GetMicroTaskQueue().push_front(*it);
- }
- mContext->mSuppressedMicroTasks = nullptr;
-
- return false;
-}
-
bool CycleCollectedJSContext::PerformMicroTaskCheckPoint(bool aForce) {
if (mPendingMicroTaskRunnables.empty() && mDebuggerMicroTaskQueue.empty()) {
AfterProcessMicrotasks();
@@ -636,14 +616,15 @@ bool CycleCollectedJSContext::PerformMicroTaskCheckPoint(bool aForce) {
bool didProcess = false;
AutoSlowOperation aso;
+ std::queue<RefPtr<MicroTaskRunnable>> suppressed;
for (;;) {
RefPtr<MicroTaskRunnable> runnable;
if (!mDebuggerMicroTaskQueue.empty()) {
runnable = std::move(mDebuggerMicroTaskQueue.front());
- mDebuggerMicroTaskQueue.pop_front();
+ mDebuggerMicroTaskQueue.pop();
} else if (!mPendingMicroTaskRunnables.empty()) {
runnable = std::move(mPendingMicroTaskRunnables.front());
- mPendingMicroTaskRunnables.pop_front();
+ mPendingMicroTaskRunnables.pop();
} else {
break;
}
@@ -654,16 +635,10 @@ bool CycleCollectedJSContext::PerformMicroTaskCheckPoint(bool aForce) {
// all suppressed tasks in mDebuggerMicroTaskQueue unexpectedly.
MOZ_ASSERT(NS_IsMainThread());
JS::JobQueueMayNotBeEmpty(Context());
- if (runnable != mSuppressedMicroTasks) {
- if (!mSuppressedMicroTasks) {
- mSuppressedMicroTasks = new SuppressedMicroTasks(this);
- }
- mSuppressedMicroTasks->mSuppressedMicroTaskRunnables.push_back(
- runnable);
- }
+ suppressed.push(runnable);
} else {
if (mPendingMicroTaskRunnables.empty() &&
- mDebuggerMicroTaskQueue.empty() && !mSuppressedMicroTasks) {
+ mDebuggerMicroTaskQueue.empty() && suppressed.empty()) {
JS::JobQueueIsEmpty(Context());
}
didProcess = true;
@@ -678,9 +653,7 @@ bool CycleCollectedJSContext::PerformMicroTaskCheckPoint(bool aForce) {
// Note, it is possible that we end up keeping these suppressed tasks around
// for some time, but no longer than spinning the event loop nestedly
// (sync XHR, alert, etc.)
- if (mSuppressedMicroTasks) {
- mPendingMicroTaskRunnables.push_back(mSuppressedMicroTasks);
- }
+ mPendingMicroTaskRunnables.swap(suppressed);
AfterProcessMicrotasks();
@@ -695,7 +668,7 @@ void CycleCollectedJSContext::PerformDebuggerMicroTaskCheckpoint() {
for (;;) {
// For a debugger microtask checkpoint, we always use the debugger microtask
// queue.
- std::deque<RefPtr<MicroTaskRunnable>>* microtaskQueue =
+ std::queue<RefPtr<MicroTaskRunnable>>* microtaskQueue =
&GetDebuggerMicroTaskQueue();
if (microtaskQueue->empty()) {
@@ -708,7 +681,7 @@ void CycleCollectedJSContext::PerformDebuggerMicroTaskCheckpoint() {
LogMicroTaskRunnable::Run log(runnable.get());
// This function can re-enter, so we remove the element before calling.
- microtaskQueue->pop_front();
+ microtaskQueue->pop();
if (mPendingMicroTaskRunnables.empty() && mDebuggerMicroTaskQueue.empty()) {
JS::JobQueueIsEmpty(Context());
diff --git a/xpcom/base/CycleCollectedJSContext.h b/xpcom/base/CycleCollectedJSContext.h
index 116bff1c90c8..769b000418ab 100644
--- a/xpcom/base/CycleCollectedJSContext.h
+++ b/xpcom/base/CycleCollectedJSContext.h
@@ -7,7 +7,7 @@
#ifndef mozilla_CycleCollectedJSContext_h
#define mozilla_CycleCollectedJSContext_h
-#include <deque>
+#include <queue>
#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
@@ -81,20 +81,6 @@ class MicroTaskRunnable {
virtual ~MicroTaskRunnable() = default;
};
-// Store the suppressed mictotasks in another microtask so that operations
-// for the microtask queue as a whole keep working.
-class SuppressedMicroTasks : public MicroTaskRunnable {
- public:
- explicit SuppressedMicroTasks(CycleCollectedJSContext* aContext);
-
- MOZ_CAN_RUN_SCRIPT_BOUNDARY void Run(AutoSlowOperation& aAso) final {}
- virtual bool Suppressed();
-
- CycleCollectedJSContext* mContext;
- uint64_t mSuppressionGeneration;
- std::deque<RefPtr<MicroTaskRunnable>> mSuppressedMicroTaskRunnables;
-};
-
// Support for JS FinalizationRegistry objects, which allow a JS callback to be
// registered that is called when objects die.
//
@@ -131,7 +117,6 @@ class FinalizationRegistryCleanup {
class CycleCollectedJSContext : dom::PerThreadAtomCache, private JS::JobQueue {
friend class CycleCollectedJSRuntime;
- friend class SuppressedMicroTasks;
protected:
CycleCollectedJSContext();
@@ -181,8 +166,8 @@ class CycleCollectedJSContext : dom::PerThreadAtomCache, private JS::JobQueue {
already_AddRefed<dom::Exception> GetPendingException() const;
void SetPendingException(dom::Exception* aException);
- std::deque<RefPtr<MicroTaskRunnable>>& GetMicroTaskQueue();
- std::deque<RefPtr<MicroTaskRunnable>>& GetDebuggerMicroTaskQueue();
+ std::queue<RefPtr<MicroTaskRunnable>>& GetMicroTaskQueue();
+ std::queue<RefPtr<MicroTaskRunnable>>& GetDebuggerMicroTaskQueue();
JSContext* Context() const {
MOZ_ASSERT(mJSContext);
@@ -198,8 +183,6 @@ class CycleCollectedJSContext : dom::PerThreadAtomCache, private JS::JobQueue {
mTargetedMicroTaskRecursionDepth = aDepth;
}
- void UpdateMicroTaskSuppressionGeneration() { ++mSuppressionGeneration; }
-
protected:
JSContext* MaybeContext() const { return mJSContext; }
@@ -333,10 +316,8 @@ class CycleCollectedJSContext : dom::PerThreadAtomCache, private JS::JobQueue {
uint32_t mMicroTaskLevel;
- std::deque<RefPtr<MicroTaskRunnable>> mPendingMicroTaskRunnables;
- std::deque<RefPtr<MicroTaskRunnable>> mDebuggerMicroTaskQueue;
- RefPtr<SuppressedMicroTasks> mSuppressedMicroTasks;
- uint64_t mSuppressionGeneration;
+ std::queue<RefPtr<MicroTaskRunnable>> mPendingMicroTaskRunnables;
+ std::queue<RefPtr<MicroTaskRunnable>> mDebuggerMicroTaskQueue;
// How many times the debugger has interrupted execution, possibly creating
// microtask checkpoints in places that they would not normally occur.
1
0
[tor-browser/tor-browser-91.6.0esr-11.0-1] Bug 40171: Make WebRequest and GeckoWebExecutor First-Party aware
by richard@torproject.org 02 Feb '22
by richard@torproject.org 02 Feb '22
02 Feb '22
commit 794e490ffeaf3e9b395bcdca4418d19ecfaabeb4
Author: Alex Catarineu <acat(a)torproject.org>
Date: Wed Nov 4 15:58:22 2020 +0100
Bug 40171: Make WebRequest and GeckoWebExecutor First-Party aware
---
.../main/java/org/mozilla/geckoview/WebRequest.java | 18 ++++++++++++++++++
widget/android/WebExecutorSupport.cpp | 10 ++++++++++
2 files changed, 28 insertions(+)
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebRequest.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebRequest.java
index d1d6e06b7396..4e17bc034edb 100644
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebRequest.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebRequest.java
@@ -51,6 +51,11 @@ public class WebRequest extends WebMessage {
*/
public final @Nullable String referrer;
+ /**
+ * The value of the origin of this request.
+ */
+ public final @Nullable String origin;
+
@Retention(RetentionPolicy.SOURCE)
@IntDef({CACHE_MODE_DEFAULT, CACHE_MODE_NO_STORE,
CACHE_MODE_RELOAD, CACHE_MODE_NO_CACHE,
@@ -112,6 +117,7 @@ public class WebRequest extends WebMessage {
method = builder.mMethod;
cacheMode = builder.mCacheMode;
referrer = builder.mReferrer;
+ origin = builder.mOrigin;
if (builder.mBody != null) {
body = builder.mBody.asReadOnlyBuffer();
@@ -128,6 +134,7 @@ public class WebRequest extends WebMessage {
/* package */ String mMethod = "GET";
/* package */ int mCacheMode = CACHE_MODE_DEFAULT;
/* package */ String mReferrer;
+ /* package */ String mOrigin;
/**
* Construct a Builder instance with the specified URI.
@@ -226,6 +233,17 @@ public class WebRequest extends WebMessage {
return this;
}
+ /**
+ * Set the origin URI.
+ *
+ * @param origin A URI String
+ * @return This Builder instance.
+ */
+ public @NonNull Builder origin(final @Nullable String origin) {
+ mOrigin = origin;
+ return this;
+ }
+
/**
* @return A {@link WebRequest} constructed with the values from this Builder instance.
*/
diff --git a/widget/android/WebExecutorSupport.cpp b/widget/android/WebExecutorSupport.cpp
index 99e7de95a0fb..bbdcc8f36bd6 100644
--- a/widget/android/WebExecutorSupport.cpp
+++ b/widget/android/WebExecutorSupport.cpp
@@ -393,6 +393,16 @@ nsresult WebExecutorSupport::CreateStreamLoader(
MOZ_ASSERT(cookieJarSettings);
nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
+
+ RefPtr<nsIURI> originUri;
+ const auto origin = req->Origin();
+ if (origin) {
+ rv = NS_NewURI(getter_AddRefs(originUri), origin->ToString());
+ NS_ENSURE_SUCCESS(rv, NS_ERROR_MALFORMED_URI);
+ OriginAttributes attrs = loadInfo->GetOriginAttributes();
+ attrs.SetFirstPartyDomain(true, originUri);
+ loadInfo->SetOriginAttributes(attrs);
+ }
loadInfo->SetCookieJarSettings(cookieJarSettings);
// setup http/https specific things
1
0
[tor-browser/tor-browser-91.6.0esr-11.0-1] Bug 40199: Avoid using system locale for intl.accept_languages in GeckoView
by richard@torproject.org 02 Feb '22
by richard@torproject.org 02 Feb '22
02 Feb '22
commit 7b16ecd606362077c1cca07d8a132e39e7c5434d
Author: Alex Catarineu <acat(a)torproject.org>
Date: Tue Oct 20 17:44:36 2020 +0200
Bug 40199: Avoid using system locale for intl.accept_languages in GeckoView
---
.../mozilla/geckoview/GeckoRuntimeSettings.java | 28 +++++++++++++---------
1 file changed, 17 insertions(+), 11 deletions(-)
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java
index c573ee7688f3..d88e296d554a 100644
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java
@@ -821,19 +821,25 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
private String computeAcceptLanguages() {
final ArrayList<String> locales = new ArrayList<String>();
- // Explicitly-set app prefs come first:
- if (mRequestedLocales != null) {
- for (final String locale : mRequestedLocales) {
- locales.add(locale.toLowerCase(Locale.ROOT));
- }
- }
- // OS prefs come second:
- for (final String locale : getDefaultLocales()) {
- final String localeLowerCase = locale.toLowerCase(Locale.ROOT);
- if (!locales.contains(localeLowerCase)) {
- locales.add(localeLowerCase);
+ // In Desktop, these are defined in the `intl.accept_languages` localized property.
+ // At some point we should probably use the same values here, but for now we use a simple
+ // strategy which will hopefully result in reasonable acceptLanguage values.
+ if (mRequestedLocales != null && mRequestedLocales.length > 0) {
+ String locale = mRequestedLocales[0].toLowerCase(Locale.ROOT);
+ // No need to include `en-us` twice.
+ if (!locale.equals("en-us")) {
+ locales.add(locale);
+ if (locale.contains("-")) {
+ String lang = locale.split("-")[0];
+ // No need to include `en` twice.
+ if (!lang.equals("en")) {
+ locales.add(lang);
+ }
+ }
}
}
+ locales.add("en-us");
+ locales.add("en");
return TextUtils.join(",", locales);
}
1
0