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

[tor-browser/tor-browser-78.13.0esr-11.0-2] Merge remote-tracking branch 'richardgl/40597' into tor-browser-78.13.0esr-11.0-2
by sysrqb@torproject.org 27 Aug '21
by sysrqb@torproject.org 27 Aug '21
27 Aug '21
commit 4973e06ef1d4e179f233f51bafe13b7ca8508b36
Merge: 85c5352a179d 441ff44f35a7
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Fri Aug 27 21:34:23 2021 +0000
Merge remote-tracking branch 'richardgl/40597' into tor-browser-78.13.0esr-11.0-2
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 | 324 ++++----
.../torpreferences/content/torProxySettings.jsm | 245 -------
browser/components/torpreferences/jar.mn | 12 +-
browser/modules/TorConnect.jsm | 47 +-
browser/modules/TorSettings.jsm | 811 +++++++++++++++++++++
browser/modules/moz.build | 1 +
.../processsingleton/MainProcessSingleton.jsm | 5 +
toolkit/modules/AsyncPrefs.jsm | 2 -
12 files changed, 1005 insertions(+), 953 deletions(-)
1
0

[tor-browser/tor-browser-78.13.0esr-11.0-2] Bug 40597: Implement TorSettings module
by sysrqb@torproject.org 27 Aug '21
by sysrqb@torproject.org 27 Aug '21
27 Aug '21
commit 441ff44f35a777bcc5aa8cc67270b9cdbe8c02e4
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 | 324 ++++----
.../torpreferences/content/torProxySettings.jsm | 245 -------
browser/components/torpreferences/jar.mn | 12 +-
browser/modules/TorConnect.jsm | 47 +-
browser/modules/TorSettings.jsm | 811 +++++++++++++++++++++
browser/modules/moz.build | 1 +
.../processsingleton/MainProcessSingleton.jsm | 5 +
toolkit/modules/AsyncPrefs.jsm | 2 -
12 files changed, 1005 insertions(+), 953 deletions(-)
diff --git a/browser/components/torconnect/TorConnectParent.jsm b/browser/components/torconnect/TorConnectParent.jsm
index 792f2af10ea6..b735d75c1a72 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
@@ -32,7 +31,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
@@ -84,9 +83,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;
}
@@ -104,7 +106,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() {
@@ -113,13 +115,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 59ecdec6d1d9..6dbc6b3c0e91 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 } = 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
@@ -253,10 +220,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 =
@@ -283,7 +251,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();
@@ -297,7 +265,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
);
@@ -313,7 +281,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
);
@@ -338,7 +306,7 @@ const gTorPane = (function() {
);
this._provideBridgeOption.setAttribute(
"value",
- TorBridgeSource.USERPROVIDED
+ TorBridgeSource.UserProvided
);
prefpane.querySelector(
selectors.bridges.provideBridgeDescription
@@ -387,11 +355,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 },
@@ -542,12 +510,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);
@@ -556,57 +520,56 @@ 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() {
this._populateXUL();
+
+ let onUnload = () => {
+ window.removeEventListener("unload", onUnload);
+ gTorPane.uninit();
+ };
+ window.addEventListener("unload", onUnload);
+ },
+
+ uninit() {
+ // unregister our observer topics
+ Services.obs.removeObserver(TorSettingsTopics.SettingChanged, this);
},
// whether the page should be present in about:preferences
@@ -620,10 +583,14 @@ const gTorPane = (function() {
// callback for when the quickstart pref changes
observe(subject, topic, data) {
- if (topic != "nsPref:changed") return;
- if (data === TorLauncherPrefs.quickstart) {
- this._enableQuickstartCheckbox.checked =
- Services.prefs.getBoolPref(TorLauncherPrefs.quickstart);
+ if (topic === TorSettingsTopics.SettingChanged) {
+ let obj = subject?.wrappedJSObject;
+ switch(data) {
+ case TorSettingsData.QuickStartEnabled: {
+ this._enableQuickstartCheckbox.checked = obj.value;
+ break;
+ }
+ }
}
},
@@ -650,13 +617,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(
[
@@ -668,23 +639,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;
}
@@ -697,14 +668,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();
+
+ this._requestBridgeTextarea.value = bridgeStrings;
}
}
);
@@ -713,53 +687,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;
},
@@ -789,12 +766,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,
@@ -815,7 +793,7 @@ const gTorPane = (function() {
this._proxyPasswordTextbox.value = "";
break;
}
- case TorProxyType.SOCKS4: {
+ case TorProxyType.Socks4: {
this._setElementsDisabled(
[
this._proxyAddressLabel,
@@ -839,7 +817,7 @@ const gTorPane = (function() {
this._proxyPasswordTextbox.value = "";
break;
}
- case TorProxyType.SOCKS5:
+ case TorProxyType.Socks5:
case TorProxyType.HTTPS: {
this._setElementsDisabled(
[
@@ -862,46 +840,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;
},
@@ -920,21 +897,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 bd5c998a6063..2f947374797a 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..d55a5fb5759c
--- /dev/null
+++ b/browser/modules/TorSettings.jsm
@@ -0,0 +1,811 @@
+"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: function(subject, topic, data) {
+ console.log(`TorSettings: observed ${topic}`);
+
+ // once the process is ready, we need to apply our settings
+ let handleProcessReady = () => {
+ 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
+ this.loadLegacy();
+ this.saveToPrefs();
+ } else {
+ // push down settings to tor
+ this.applySettings();
+ }
+ Services.obs.notifyObservers(null, TorSettingsTopics.Ready);
+ };
+
+ switch (topic) {
+ case BrowserTopics.ProfileAfterChange: {
+ if (TorProtocolService.torProcessStatus == TorProcessStatus.Running) {
+ handleProcessReady();
+ }
+ }
+ break;
+ case TorTopics.ProcessIsReady: {
+ 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: 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 = (() => {
+ let bridgeList = 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 = 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 = TorProtocolService.readStringSetting(TorConfigKeys.socks5Proxy)) {
+ let [address, port] = parseAddrPort(proxyString);
+ let username = TorProtocolService.readStringSetting(TorConfigKeys.socks5ProxyUsername);
+ let password = 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 = TorProtocolService.readStringSetting(TorConfigKeys.httpsProxy)) {
+ let [address, port] = parseAddrPort(proxyString);
+ let authenticator = 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 = 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: 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 */
+ TorProtocolService.writeSettings(settingsMap);
+
+ return this;
+ },
+
+ /* Getters and Setters */
+
+
+ // Quickstart
+ get quickstart() {
+ return {
+ get enabled() { return self._settings.quickstart.enabled; },
+ 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 7f091e0e7711..3b74753c7614 100644
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -158,6 +158,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 ea9288dccbb3..702ba3fbec98 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 b81ff5e22b9b..aca86556cd5e 100644
--- a/toolkit/modules/AsyncPrefs.jsm
+++ b/toolkit/modules/AsyncPrefs.jsm
@@ -18,8 +18,6 @@ const kAllowedPrefs = new Set([
"testing.allowed-prefs.some-char-pref",
"testing.allowed-prefs.some-int-pref",
- "extensions.torlauncher.quickstart",
-
"narrate.rate",
"narrate.voice",
1
0

[torbutton/master] Bug 40027: Make torbutton_send_ctrl_cmd async
by sysrqb@torproject.org 27 Aug '21
by sysrqb@torproject.org 27 Aug '21
27 Aug '21
commit ba03ae5f2ec1ce5c9fd46e4063b477fc8626f2d1
Author: Alex Catarineu <acat(a)torproject.org>
Date: Tue Jan 26 10:39:41 2021 +0100
Bug 40027: Make torbutton_send_ctrl_cmd async
- makes torbutton_send_ctrl_cmd async; now implemented using
torController.sendCommand rather than handling all of the io,
concurrency, and syncrhonization
- insert asyncs/awaits/catch to the relevant places where
torbutton_send_ctrl_cmd are called
- removed call to torbutton_do_tor_check() from
torbutton_new_window()
- NS_BASE_STREAM_CLOSED returned from read no longer triggers error
callback inside io.pumpInputStream
- tor.controllerCache is now expicitly a JavaScript map object
- controller() function now has option to always get a new
tor.controller, instead of a cached one
- refactored controller() function to use explicit map() functions
---
chrome/content/torbutton.js | 105 +++++++++++++-------------------------------
modules/tor-control-port.js | 52 +++++++++++++++-------
2 files changed, 66 insertions(+), 91 deletions(-)
diff --git a/chrome/content/torbutton.js b/chrome/content/torbutton.js
index 48539a96..8c016b39 100644
--- a/chrome/content/torbutton.js
+++ b/chrome/content/torbutton.js
@@ -28,7 +28,7 @@ let {
torbutton_log,
torbutton_get_property_string,
} = ChromeUtils.import("resource://torbutton/modules/utils.js", {});
-let { configureControlPortModule } = Cu.import("resource://torbutton/modules/tor-control-port.js", {});
+let { configureControlPortModule, controller } = Cu.import("resource://torbutton/modules/tor-control-port.js", {});
const k_tb_tor_check_failed_topic = "Torbutton:TorCheckFailed";
@@ -299,19 +299,19 @@ torbutton_init = function() {
var torbutton_abouttor_message_handler = {
// Receive IPC messages from the about:tor content script.
- receiveMessage: function(aMessage) {
+ receiveMessage: async function(aMessage) {
switch(aMessage.name) {
case "AboutTor:Loaded":
aMessage.target.messageManager.sendAsyncMessage("AboutTor:ChromeData",
- this.getChromeData(true));
+ await this.getChromeData(true));
break;
}
},
// Send privileged data to all of the about:tor content scripts.
- updateAllOpenPages: function() {
+ updateAllOpenPages: async function() {
window.messageManager.broadcastAsyncMessage("AboutTor:ChromeData",
- this.getChromeData(false));
+ await this.getChromeData(false));
},
// The chrome data contains all of the data needed by the about:tor
@@ -319,11 +319,11 @@ var torbutton_abouttor_message_handler = {
// It is sent to the content process when an about:tor window is opened
// and in response to events such as the browser noticing that Tor is
// not working.
- getChromeData: function(aIsRespondingToPageLoad) {
+ getChromeData: async function(aIsRespondingToPageLoad) {
let dataObj = {
mobile: torbutton_is_mobile(),
updateChannel: AppConstants.MOZ_UPDATE_CHANNEL,
- torOn: torbutton_tor_check_ok()
+ torOn: await torbutton_tor_check_ok()
};
if (aIsRespondingToPageLoad) {
@@ -446,70 +446,27 @@ function torbutton_array_to_hexdigits(array) {
// Bug 1506 P4: Control port interaction. Needed for New Identity.
//
-// Executes a command on the control port.
-// Return a string response upon success and null upon error.
-function torbutton_send_ctrl_cmd(command) {
-
- // We spin the event queue until it is empty and we can be sure that sending
- // NEWNYM is not leading to a deadlock (see bug 9531 comment 23 for an
- // invstigation on why and when this may happen). This is surrounded by
- // suppressing/unsuppressing user initiated events in a window's document to
- // be sure that these events are not interfering with processing events being
- // in the event queue.
- var thread = Services.tm.currentThread;
- m_tb_domWindowUtils.suppressEventHandling(true);
- while (thread.processNextEvent(false)) {}
- m_tb_domWindowUtils.suppressEventHandling(false);
-
+// Asynchronously executes a command on the control port.
+// returns the response as a string, or null on error
+async function torbutton_send_ctrl_cmd(command) {
+ const getErrorMessage = e => (e && (e.torMessage || e.message)) || "";
+ let response = null;
try {
- let sts = Cc["@mozilla.org/network/socket-transport-service;1"]
- .getService(Ci.nsISocketTransportService);
- let socket;
- if (m_tb_control_ipc_file) {
- socket = sts.createUnixDomainTransport(m_tb_control_ipc_file);
- } else {
- socket = sts.createTransport([], m_tb_control_host,
- m_tb_control_port, null);
- }
-
- // If we don't get a response from the control port in 2 seconds, someting is wrong..
- socket.setTimeout(Ci.nsISocketTransport.TIMEOUT_READ_WRITE, 2);
-
- var input = socket.openInputStream(3, 1, 1); // 3 == OPEN_BLOCKING|OPEN_UNBUFFERED
- var output = socket.openOutputStream(3, 1, 1); // 3 == OPEN_BLOCKING|OPEN_UNBUFFERED
-
- var inputStream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
- var outputStream = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
+ const avoidCache = true;
+ let torController = controller(e => { throw e; }, avoidCache);
- inputStream.setInputStream(input);
- outputStream.setOutputStream(output);
-
- var auth_cmd = "AUTHENTICATE "+m_tb_control_pass+"\r\n";
- outputStream.writeBytes(auth_cmd, auth_cmd.length);
-
- var bytes = torbutton_socket_readline(inputStream);
-
- if (bytes.indexOf("250") != 0) {
- torbutton_safelog(4, "Unexpected auth response on control port "+m_tb_control_desc+":", bytes);
- return null;
+ let bytes = await torController.sendCommand(command);
+ if (!bytes.startsWith("250")) {
+ throw `Unexpected command response on control port '${bytes}'`;
}
+ response = bytes.slice(4);
- outputStream.writeBytes(command, command.length);
- bytes = torbutton_socket_readline(inputStream);
- if(bytes.indexOf("250") != 0) {
- torbutton_safelog(4, "Unexpected command response on control port "+m_tb_control_desc+":", bytes);
- return null;
- }
-
- // Closing these streams prevents a shutdown hang on Mac OS. See bug 10201.
- inputStream.close();
- outputStream.close();
- socket.close(Cr.NS_OK);
- return bytes.substr(4);
- } catch(e) {
- torbutton_log(4, "Exception on control port "+e);
- return null;
+ torController.close();
+ } catch(err) {
+ let msg = getErrorMessage(err);
+ torbutton_log(4, `Error: ${msg}`);
}
+ return response;
}
// Bug 1506 P4: Needed for New IP Address
@@ -800,7 +757,7 @@ async function torbutton_do_new_identity() {
torbutton_log(5, "Torbutton cannot safely newnym. It does not have access to the Tor Control Port.");
window.alert(warning);
} else {
- if (!torbutton_send_ctrl_cmd("SIGNAL NEWNYM\r\n")) {
+ if (!await torbutton_send_ctrl_cmd("SIGNAL NEWNYM")) {
var warning = torbutton_get_property_string("torbutton.popup.no_newnym");
torbutton_log(5, "Torbutton was unable to request a new circuit from Tor");
window.alert(warning);
@@ -930,7 +887,7 @@ function torbutton_use_nontor_proxy()
torbutton_do_new_identity();
}
-function torbutton_do_tor_check()
+async function torbutton_do_tor_check()
{
let checkSvc = Cc["@torproject.org/torbutton-torCheckService;1"]
.getService(Ci.nsISupports).wrappedJSObject;
@@ -948,7 +905,7 @@ function torbutton_do_tor_check()
!env.exists(kEnvUseTransparentProxy) &&
!env.exists(kEnvSkipControlPortTest) &&
m_tb_prefs.getBoolPref("extensions.torbutton.local_tor_check")) {
- if (torbutton_local_tor_check())
+ if (await torbutton_local_tor_check())
checkSvc.statusOfTorCheck = checkSvc.kCheckSuccessful;
else {
// The check failed. Update toolbar icon and tooltip.
@@ -961,7 +918,7 @@ function torbutton_do_tor_check()
}
}
-function torbutton_local_tor_check()
+async function torbutton_local_tor_check()
{
let didLogError = false;
@@ -972,7 +929,7 @@ function torbutton_local_tor_check()
// Ask tor for its SOCKS listener address and port and compare to the
// browser preferences.
const kCmdArg = "net/listeners/socks";
- let resp = torbutton_send_ctrl_cmd("GETINFO " + kCmdArg + "\r\n");
+ let resp = await torbutton_send_ctrl_cmd("GETINFO " + kCmdArg);
if (!resp)
return false;
@@ -1116,9 +1073,9 @@ function torbutton_initiate_remote_tor_check() {
}
} // torbutton_initiate_remote_tor_check()
-function torbutton_tor_check_ok()
+async function torbutton_tor_check_ok()
{
- torbutton_do_tor_check();
+ await torbutton_do_tor_check();
let checkSvc = Cc["@torproject.org/torbutton-torCheckService;1"]
.getService(Ci.nsISupports).wrappedJSObject;
return (checkSvc.kCheckFailed != checkSvc.statusOfTorCheck);
@@ -1486,8 +1443,6 @@ function torbutton_new_window(event)
progress.addProgressListener(torbutton_resizelistener,
Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
}
-
- torbutton_do_tor_check();
}
// Bug 1506 P2: This is only needed because we have observers
diff --git a/modules/tor-control-port.js b/modules/tor-control-port.js
index a3e72dd5..7891f0ee 100644
--- a/modules/tor-control-port.js
+++ b/modules/tor-control-port.js
@@ -82,7 +82,9 @@ io.pumpInputStream = function (inputStream, onInputData, onError) {
onInputData(chunk);
awaitNextChunk();
} catch (err) {
- onError(err);
+ if (err.result !== Cr.NS_BASE_STREAM_CLOSED) {
+ onError(err);
+ }
}
}
}, 0, 0, Services.tm.currentThread);
@@ -285,9 +287,9 @@ io.controlSocket = function (ipcFile, host, port, password, onError) {
// Pass asynchronous notifications to notification dispatcher.
mainDispatcher.addCallback(/^650/, notificationDispatcher.pushMessage);
// Log in to control port.
- sendCommand("authenticate " + (password || ""));
+ sendCommand("authenticate " + (password || "")).catch(onError);
// Activate needed events.
- sendCommand("setevents stream");
+ sendCommand("setevents stream").catch(onError);
return { close : socket.close, sendCommand : sendCommand,
addNotificationCallback : notificationDispatcher.addCallback,
removeNotificationCallback : notificationDispatcher.removeCallback };
@@ -677,7 +679,7 @@ let tor = {};
// __tor.controllerCache__.
// A map from "unix:socketpath" or "host:port" to controller objects. Prevents
// redundant instantiation of control sockets.
-tor.controllerCache = {};
+tor.controllerCache = new Map();
// __tor.controller(ipcFile, host, port, password, onError)__.
// Creates a tor controller at the given ipcFile or host and port, with the
@@ -697,7 +699,8 @@ tor.controller = function (ipcFile, host, port, password, onError) {
watchEvent : (type, filter, onData) =>
event.watchEvent(socket, type, filter, onData),
isOpen : () => isOpen,
- close : () => { isOpen = false; socket.close(); }
+ close : () => { isOpen = false; socket.close(); },
+ sendCommand: cmd => socket.sendCommand(cmd),
};
};
@@ -732,23 +735,40 @@ var configureControlPortModule = function (ipcFile, host, port, password) {
// let replyPromise = c.getInfo("ip-to-country/16.16.16.16");
// // Close the controller permanently
// c.close();
-var controller = function (onError) {
+var controller = function (onError, avoidCache) {
if (!controlPortInfo.ipcFile && !controlPortInfo.host)
throw new Error("Please call configureControlPortModule first");
const dest = (controlPortInfo.ipcFile)
? `unix:${controlPortInfo.ipcFile.path}`
: `${controlPortInfo.host}:${controlPortInfo.port}`;
- const maybeController = tor.controllerCache[dest];
- if (maybeController && maybeController.isOpen())
- return maybeController;
-
- tor.controllerCache[dest] = tor.controller(controlPortInfo.ipcFile,
- controlPortInfo.host,
- controlPortInfo.port,
- controlPortInfo.password,
- onError);
- return tor.controllerCache[dest];
+
+ // constructor shorthand
+ const newTorController =
+ () => {
+ return tor.controller(
+ controlPortInfo.ipcFile,
+ controlPortInfo.host,
+ controlPortInfo.port,
+ controlPortInfo.password,
+ onError);
+ };
+
+ // avoid cache so always return a new controller
+ if (avoidCache) {
+ return newTorController();
+ }
+
+ // first check our cache and see if we already have one
+ let cachedController = tor.controllerCache.get(dest);
+ if (cachedController && cachedController.isOpen()) {
+ return cachedController;
+ }
+
+ // create a new one and store in the map
+ cachedController = newTorController();
+ tor.controllerCache.set(dest, cachedController);
+ return cachedController;
};
// Export functions for external use.
1
0

[torbutton/master] Bug 40042: Add missing parameter of createTransport
by sysrqb@torproject.org 27 Aug '21
by sysrqb@torproject.org 27 Aug '21
27 Aug '21
commit 9ec2e841a778cda4dabd38e6198ab8f0dfced4fc
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Wed Aug 25 15:18:06 2021 +0000
Bug 40042: Add missing parameter of createTransport
---
modules/tor-control-port.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modules/tor-control-port.js b/modules/tor-control-port.js
index 7891f0ee..4215c763 100644
--- a/modules/tor-control-port.js
+++ b/modules/tor-control-port.js
@@ -55,7 +55,7 @@ io.asyncSocketStreams = function (ipcFile, host, port) {
if (ipcFile) {
socketTransport = sts.createUnixDomainTransport(ipcFile);
} else {
- socketTransport = sts.createTransport([], host, port, null);
+ socketTransport = sts.createTransport([], host, port, null, null);
}
// Open unbuffered asynchronous outputStream.
1
0

[torbutton/master] Bug 40045: Teach the controller about status_client
by sysrqb@torproject.org 27 Aug '21
by sysrqb@torproject.org 27 Aug '21
27 Aug '21
commit 70ca32ee396a155c213feb2fd38fc97d9f6eab4f
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Wed Aug 25 15:19:01 2021 +0000
Bug 40045: Teach the controller about status_client
In addition, the controller now can return raw messages instead of
parsing them itself.
---
modules/tor-control-port.js | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/modules/tor-control-port.js b/modules/tor-control-port.js
index 4215c763..c372c1ae 100644
--- a/modules/tor-control-port.js
+++ b/modules/tor-control-port.js
@@ -645,6 +645,7 @@ let event = {};
// data.
event.parsers = {
"stream" : info.streamStatusParser,
+ "status_client" : (data) => data,
// Currently unused:
// "circ" : info.circuitStatusParser,
};
@@ -662,11 +663,14 @@ event.messageToData = function (type, message) {
// data is passed to the onData callback. Returns a zero arg function that
// stops watching the event. Note: we only observe `"650" SP...` events
// currently (no `650+...` or `650-...` events).
-event.watchEvent = function (controlSocket, type, filter, onData) {
+event.watchEvent = function (controlSocket, type, filter, onData, raw=false) {
return controlSocket.addNotificationCallback(new RegExp("^650 " + type),
function (message) {
let data = event.messageToData(type, message);
if (filter === null || filter(data)) {
+ if (raw) {
+ return onData(message);
+ }
onData(data);
}
});
@@ -696,8 +700,8 @@ tor.controller = function (ipcFile, host, port, password, onError) {
isPermanent),
onionAuthRemove : (hsAddress) =>
onionAuth.remove(socket, hsAddress),
- watchEvent : (type, filter, onData) =>
- event.watchEvent(socket, type, filter, onData),
+ watchEvent : (type, filter, onData, raw=false) =>
+ event.watchEvent(socket, type, filter, onData, raw),
isOpen : () => isOpen,
close : () => { isOpen = false; socket.close(); },
sendCommand: cmd => socket.sendCommand(cmd),
1
0

[torbutton/master] Bug 40043: Delete all plugin-related protections
by sysrqb@torproject.org 27 Aug '21
by sysrqb@torproject.org 27 Aug '21
27 Aug '21
commit 0197c6fec132dd0d672fb1f13b5cdb3ad58c57b7
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Wed Aug 25 18:57:34 2021 +0000
Bug 40043: Delete all plugin-related protections
---
chrome/content/torbutton.js | 138 ++------------------------------------------
1 file changed, 5 insertions(+), 133 deletions(-)
diff --git a/chrome/content/torbutton.js b/chrome/content/torbutton.js
index 8c016b39..c05dd605 100644
--- a/chrome/content/torbutton.js
+++ b/chrome/content/torbutton.js
@@ -38,8 +38,6 @@ var m_tb_prefs = Services.prefs;
var m_tb_wasinited = false;
var m_tb_is_main_window = false;
-var m_tb_confirming_plugins = false;
-
var m_tb_control_ipc_file = null; // Set if using IPC (UNIX domain socket).
var m_tb_control_port = null; // Set if using TCP.
var m_tb_control_host = null; // Set if using TCP.
@@ -73,13 +71,8 @@ var torbutton_unique_pref_observer =
m_tb_prefs.addObserver("extensions.torbutton", this, false);
m_tb_prefs.addObserver("browser.privatebrowsing.autostart", this, false);
m_tb_prefs.addObserver("javascript", this, false);
- m_tb_prefs.addObserver("plugin.disable", this, false);
m_tb_prefs.addObserver("privacy.resistFingerprinting", this, false);
m_tb_prefs.addObserver("privacy.resistFingerprinting.letterboxing", this, false);
-
- // We observe xpcom-category-entry-added for plugins w/ Gecko-Content-Viewers
- var observerService = Services.obs;
- observerService.addObserver(this, "xpcom-category-entry-added");
},
unregister: function()
@@ -87,12 +80,8 @@ var torbutton_unique_pref_observer =
m_tb_prefs.removeObserver("extensions.torbutton", this);
m_tb_prefs.removeObserver("browser.privatebrowsing.autostart", this);
m_tb_prefs.removeObserver("javascript", this);
- m_tb_prefs.removeObserver("plugin.disable", this);
m_tb_prefs.removeObserver("privacy.resistFingerprinting", this);
m_tb_prefs.removeObserver("privacy.resistFingerprinting.letterboxing", this);
-
- var observerService = Services.obs;
- observerService.removeObserver(this, "xpcom-category-entry-added");
},
// topic: what event occurred
@@ -100,38 +89,9 @@ var torbutton_unique_pref_observer =
// data: which pref has been changed (relative to subject)
observe: function(subject, topic, data)
{
- if (topic == "xpcom-category-entry-added") {
- // Hrmm. should we inspect subject too? it's just mime type..
- subject.QueryInterface(Ci.nsISupportsCString);
- if (data == "Gecko-Content-Viewers" &&
- !m_tb_prefs.getBoolPref("extensions.torbutton.startup") &&
- m_tb_prefs.getBoolPref("extensions.torbutton.confirm_plugins")) {
- torbutton_log(3, "Got plugin enabled notification: "+subject);
-
- /* We need to protect this call with a flag becuase we can
- * get multiple observer events for each mime type a plugin
- * registers. Thankfully, these notifications arrive only on
- * the main thread, *however*, our confirmation dialog suspends
- * execution and allows more events to arrive until it is answered
- */
- if (!m_tb_confirming_plugins) {
- m_tb_confirming_plugins = true;
- torbutton_confirm_plugins();
- m_tb_confirming_plugins = false;
- } else {
- torbutton_log(3, "Skipping notification for mime type: "+subject);
- }
- }
- return;
- }
-
if (topic != "nsPref:changed") return;
switch (data) {
- case "plugin.disable":
- torbutton_toggle_plugins(
- m_tb_prefs.getBoolPref("plugin.disable"));
- break;
case "browser.privatebrowsing.autostart":
torbutton_update_disk_prefs();
break;
@@ -348,67 +308,6 @@ var torbutton_abouttor_message_handler = {
}
};
-function torbutton_confirm_plugins() {
- var any_plugins_enabled = false;
- var PH=Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
- var P=PH.getPluginTags({});
- for(var i=0; i<P.length; i++) {
- if (!P[i].disabled)
- any_plugins_enabled = true;
- }
-
- if (!any_plugins_enabled) {
- torbutton_log(3, "False positive on plugin notification. Ignoring");
- return;
- }
-
- torbutton_log(3, "Confirming plugin usage.");
-
- var prompts = Services.prompt;
-
- // Display two buttons, both with string titles.
- var flags = prompts.STD_YES_NO_BUTTONS + prompts.BUTTON_DELAY_ENABLE;
-
- var message = torbutton_get_property_string("torbutton.popup.confirm_plugins");
- var askAgainText = torbutton_get_property_string("torbutton.popup.never_ask_again");
- var askAgain = {value: false};
-
- var wm = Services.wm;
- var win = wm.getMostRecentWindow("navigator:browser");
- var no_plugins = (prompts.confirmEx(win, "", message, flags, null, null, null,
- askAgainText, askAgain) == 1);
-
- m_tb_prefs.setBoolPref("extensions.torbutton.confirm_plugins", !askAgain.value);
-
- // The pref observer for "plugin.disable" will set the appropriate plugin state.
- // So, we only touch the pref if it has changed.
- if (no_plugins !=
- m_tb_prefs.getBoolPref("plugin.disable"))
- m_tb_prefs.setBoolPref("plugin.disable", no_plugins);
- else
- torbutton_toggle_plugins(no_plugins);
-
- // Now, if any tabs were open to about:addons, reload them. Our popup
- // messed up that page.
- var browserEnumerator = wm.getEnumerator("navigator:browser");
-
- // Check each browser instance for our URL
- while (browserEnumerator.hasMoreElements()) {
- var browserWin = browserEnumerator.getNext();
- var tabbrowser = browserWin.gBrowser;
-
- // Check each tab of this browser instance
- var numTabs = tabbrowser.browsers.length;
- for (var index = 0; index < numTabs; index++) {
- var currentBrowser = tabbrowser.getBrowserAtIndex(index);
- if ("about:addons" == currentBrowser.currentURI.spec) {
- torbutton_log(3, "Got browser: "+currentBrowser.currentURI.spec);
- currentBrowser.reload();
- }
- }
- }
-}
-
// Bug 1506 P4: Control port interaction. Needed for New Identity.
function torbutton_socket_readline(input) {
var str = "";
@@ -530,7 +429,7 @@ torbutton_new_identity = async function() {
}
/* The "New Identity" implementation does the following:
- * 1. Disables Javascript and plugins on all tabs
+ * 1. Disables Javascript
* 2. Clears state:
* a. OCSP
* b. Cache + image cache
@@ -544,9 +443,8 @@ torbutton_new_identity = async function() {
* j. permissions
* k. site security settings (e.g. HSTS)
* l. IndexedDB and other DOM storage
- * m. plugin data
- * n. media devices
- * o. predictor network data
+ * m. media devices
+ * n. predictor network data
* 3. Sends tor the NEWNYM signal to get a new circuit
* 4. Opens a new window with the default homepage
* 5. Closes this window
@@ -696,14 +594,12 @@ async function torbutton_do_new_identity() {
}
torbutton_log(3, "New Identity: Clearing storage");
- torbutton_log(3, "New Identity: Clearing plugin data");
torbutton_log(3, "New Identity: Clearing media devices");
torbutton_log(3, "New Identity: Clearing predictor network data");
try {
await clearData(
Services.clearData.CLEAR_DOM_STORAGES |
- Services.clearData.CLEAR_PLUGIN_DATA |
Services.clearData.CLEAR_MEDIA_DEVICES |
Services.clearData.CLEAR_PREDICTOR_NETWORK_DATA
);
@@ -1081,27 +977,6 @@ async function torbutton_tor_check_ok()
return (checkSvc.kCheckFailed != checkSvc.statusOfTorCheck);
}
-// Bug 1506 P5: Despite the name, this is the way we disable
-// plugins for Tor Browser, too.
-//
-// toggles plugins: true for disabled, false for enabled
-function torbutton_toggle_plugins(disable_plugins) {
- var PH=Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
- var P=PH.getPluginTags({});
- for(var i=0; i<P.length; i++) {
- if ("enabledState" in P[i]) { // FF24
- // FIXME: DOCDOC the reasoning for the isDisabled check, or remove it.
- var isDisabled = (P[i].enabledState == Ci.nsIPluginTag.STATE_DISABLED);
- if (!isDisabled && disable_plugins)
- P[i].enabledState = Ci.nsIPluginTag.STATE_DISABLED;
- else if (isDisabled && !disable_plugins)
- P[i].enabledState = Ci.nsIPluginTag.STATE_CLICKTOPLAY;
- } else if (P[i].disabled != disable_plugins) { // FF17
- P[i].disabled=disable_plugins;
- }
- }
-}
-
function torbutton_update_disk_prefs() {
var mode = m_tb_prefs.getBoolPref("browser.privatebrowsing.autostart");
@@ -1194,7 +1069,7 @@ function torbutton_clear_cookies() {
cm.removeAll();
}
-// -------------- JS/PLUGIN HANDLING CODE ---------------------
+// -------------- JS HANDLING CODE ---------------------
// Bug 1506 P3: Defense in depth. Disables JS and events for New Identity.
function torbutton_disable_browser_js(browser) {
var eventSuppressor = null;
@@ -1233,6 +1108,7 @@ function torbutton_disable_browser_js(browser) {
function torbutton_disable_window_js(win) {
var browser = win.gBrowser;
if (!browser) {
+ // TODO is this still needed?
torbutton_log(5, "No browser for plugin window...");
return;
}
@@ -1328,10 +1204,6 @@ function torbutton_do_main_window_startup()
function torbutton_do_startup()
{
if(m_tb_prefs.getBoolPref("extensions.torbutton.startup")) {
- // Bug 1506: Still want to do this
- torbutton_toggle_plugins(
- m_tb_prefs.getBoolPref("plugin.disable"));
-
// Bug 1506: Should probably be moved to an XPCOM component
torbutton_do_main_window_startup();
1
0

27 Aug '21
commit 580e2c01a607dbe07c680041a1e33d9dd750b617
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Wed Aug 25 14:30:10 2021 +0000
Bug 40004: Convert tl-protocol to async.
We resolve the issue of deadlocks within Firefox, and other unknown
bugs, during initialization by using asynchronous programming in the
controller implementation. At the same time, we take advantage of
torbutton's async 'controller' module instead of duplicating logic.
---
src/chrome/content/network-settings.js | 125 ++++++++--------
src/components/tl-process.js | 10 +-
src/components/tl-protocol.js | 261 ++++++++++++---------------------
3 files changed, 159 insertions(+), 237 deletions(-)
diff --git a/src/chrome/content/network-settings.js b/src/chrome/content/network-settings.js
index 81d7138..5a3d441 100644
--- a/src/chrome/content/network-settings.js
+++ b/src/chrome/content/network-settings.js
@@ -115,7 +115,7 @@ var gBridgeDBBridges = undefined; // Array of bridge lines.
var gBridgeDBRequestEventListeners = [];
-function initDialogCommon()
+async function initDialogCommon()
{
loadSharedXUL();
@@ -268,10 +268,10 @@ function resizeDialogToFitContent()
}
-function initDialog()
+async function initDialog()
{
gIsInitialBootstrap = window.arguments[0];
- initDialogCommon();
+ await initDialogCommon();
if (window.arguments.length > 1)
gInitialPanelID = window.arguments[1];
@@ -297,8 +297,8 @@ function initDialog()
if (haveWizard)
{
// Add wizardfinish event handler.
- document.addEventListener("wizardfinish", (aEvent) => {
- if (!onWizardFinish())
+ document.addEventListener("wizardfinish", function (aEvent) {
+ if (!(onWizardFinish()))
aEvent.preventDefault();
});
@@ -375,9 +375,9 @@ function initDialog()
}
-function initLocaleDialog()
+async function initLocaleDialog()
{
- initDialogCommon();
+ await initDialogCommon();
// Add wizardfinish event handler.
document.addEventListener("wizardfinish", (aEvent) => {
@@ -590,22 +590,22 @@ function getWizard()
}
-function onWizardFirstPanelConnect()
+async function onWizardFirstPanelConnect()
{
// If the user configured bridge or proxy settings, prompt before
// discarding their data.
if (isBridgeConfigured() || isProxyConfigured())
showPanel(kWizardDiscardSettingsPageID);
else
- removeSettingsAndConnect()
+ await removeSettingsAndConnect()
}
-function removeSettingsAndConnect()
+async function removeSettingsAndConnect()
{
- applySettings(true); // Use default settings.
+ await applySettings(true); // Use default settings.
if (!gTorProcessService.TorIsBootstrapDone)
- readTorSettings(); // Ensure UI matches the settings that were used.
+ await readTorSettings(); // Ensure UI matches the settings that were used.
}
@@ -648,10 +648,10 @@ function onBridgeTypeRadioChange()
}
-function onOpenBridgeDBRequestPrompt()
+async function onOpenBridgeDBRequestPrompt()
{
// Obtain the meek client path and args from the tor configuration.
- let reply = gProtocolSvc.TorGetConf("ClientTransportPlugin");
+ let reply = await gProtocolSvc.TorGetConf("ClientTransportPlugin");
if (!gProtocolSvc.TorCommandSucceeded(reply))
return;
@@ -908,8 +908,9 @@ var gObserver = {
showCopyLogButton(true);
if (kTorBootstrapErrorTopic == aTopic)
{
- stopTorBootstrap();
- showErrorMessage(aSubject.wrappedJSObject, true);
+ stopTorBootstrap().then((value) => {
+ showErrorMessage(aSubject.wrappedJSObject, true);
+ });
}
return;
}
@@ -1019,7 +1020,7 @@ function updateBootstrapProgress(aStatusObj)
}
-function readTorSettings()
+async function readTorSettings()
{
TorLauncherLogger.log(2, "readTorSettings " +
"----------------------------------------------");
@@ -1028,8 +1029,8 @@ function readTorSettings()
try
{
// TODO: retrieve > 1 key at one time inside initProxySettings() et al.
- didSucceed = initBridgeSettings() &&
- initProxySettings() && initFirewallSettings();
+ didSucceed = await initBridgeSettings() &&
+ await initProxySettings() && await initFirewallSettings();
}
catch (e) { TorLauncherLogger.safelog(4, "Error in readTorSettings: ", e); }
@@ -1048,13 +1049,13 @@ function readTorSettings()
}
-function onTorStarted()
+async function onTorStarted()
{
- if (readTorSettings())
+ if (await readTorSettings())
{
showPanel();
if (gInitialPanelID)
- advanceToWizardPanel(gInitialPanelID);
+ await advanceToWizardPanel(gInitialPanelID);
}
}
@@ -1087,7 +1088,7 @@ function showPanel(aPanelID)
// This function assumes that you are starting on the first page.
-function advanceToWizardPanel(aPanelID)
+async function advanceToWizardPanel(aPanelID)
{
var wizard = getWizard();
if (!wizard)
@@ -1095,7 +1096,7 @@ function advanceToWizardPanel(aPanelID)
if (kWizardProgressPageID == aPanelID)
{
- showProgressPanel();
+ await showProgressPanel();
return;
}
@@ -1592,7 +1593,8 @@ function onWizardFinish()
return false;
}
- return applySettings(false);
+ applySettings(false).then(result => { if (result) window.setTimeout(function() { close(); }, 0);});
+ return false;
}
@@ -1616,19 +1618,20 @@ function onNetworkSettingsFinish()
return false;
}
- return applySettings(false);
+ applySettings(false).then(result => { if (result) window.setTimeout(function() { close(); }, 0);});
+ return false;
}
// When the progress panel is open, cancel stops bootstrapping... unless
// we are showing an error, in which case the action is "Reconfigure".
-function onProgressCancelOrReconfigure(aWizard)
+async function onProgressCancelOrReconfigure(aWizard)
{
let progressContent = document.getElementById("progressContent");
if (!progressContent ||
!progressContent.hasAttribute("isShowingReconfigure"))
{
- stopTorBootstrap();
+ await stopTorBootstrap();
}
if (aWizard)
@@ -1737,10 +1740,10 @@ function closeHelp()
// Returns true if successful.
-function initProxySettings()
+async function initProxySettings()
{
let proxyType, proxyAddrPort, proxyUsername, proxyPassword;
- let reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks4Proxy, null);
+ let reply = await gProtocolSvc.TorGetConfStr(kTorConfKeySocks4Proxy, null);
if (!gProtocolSvc.TorCommandSucceeded(reply))
return false;
@@ -1751,7 +1754,7 @@ function initProxySettings()
}
else
{
- reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks5Proxy, null);
+ reply = await gProtocolSvc.TorGetConfStr(kTorConfKeySocks5Proxy, null);
if (!gProtocolSvc.TorCommandSucceeded(reply))
return false;
@@ -1759,12 +1762,12 @@ function initProxySettings()
{
proxyType = "SOCKS5";
proxyAddrPort = reply.retVal;
- reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks5ProxyUsername, null);
+ reply = await gProtocolSvc.TorGetConfStr(kTorConfKeySocks5ProxyUsername, null);
if (!gProtocolSvc.TorCommandSucceeded(reply))
return false;
proxyUsername = reply.retVal;
- reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks5ProxyPassword, null);
+ reply = await gProtocolSvc.TorGetConfStr(kTorConfKeySocks5ProxyPassword, null);
if (!gProtocolSvc.TorCommandSucceeded(reply))
return false;
@@ -1772,7 +1775,7 @@ function initProxySettings()
}
else
{
- reply = gProtocolSvc.TorGetConfStr(kTorConfKeyHTTPSProxy, null);
+ reply = await gProtocolSvc.TorGetConfStr(kTorConfKeyHTTPSProxy, null);
if (!gProtocolSvc.TorCommandSucceeded(reply))
return false;
@@ -1780,7 +1783,7 @@ function initProxySettings()
{
proxyType = "HTTP";
proxyAddrPort = reply.retVal;
- reply = gProtocolSvc.TorGetConfStr(
+ reply = await gProtocolSvc.TorGetConfStr(
kTorConfKeyHTTPSProxyAuthenticator, null);
if (!gProtocolSvc.TorCommandSucceeded(reply))
return false;
@@ -1818,13 +1821,13 @@ function initProxySettings()
// Returns true if successful.
-function initFirewallSettings()
+async function initFirewallSettings()
{
if (getWizard())
return true; // The wizard does not directly expose firewall settings.
var allowedPorts;
- var reply = gProtocolSvc.TorGetConfStr(kTorConfKeyReachableAddresses, null);
+ var reply = await gProtocolSvc.TorGetConfStr(kTorConfKeyReachableAddresses, null);
if (!gProtocolSvc.TorCommandSucceeded(reply))
return false;
@@ -1854,7 +1857,7 @@ function initFirewallSettings()
// Returns true if successful.
-function initBridgeSettings()
+async function initBridgeSettings()
{
let typeList = TorLauncherUtil.defaultBridgeTypes;
let canUseDefaultBridges = (typeList && (typeList.length > 0));
@@ -1871,14 +1874,14 @@ function initBridgeSettings()
{
showMenuListPlaceholderText(kDefaultBridgeTypeMenuList);
- let reply = gProtocolSvc.TorGetConfBool(kTorConfKeyUseBridges, false);
+ let reply = await gProtocolSvc.TorGetConfBool(kTorConfKeyUseBridges, false);
if (!gProtocolSvc.TorCommandSucceeded(reply))
return false;
useBridges = reply.retVal;
// Get the list of configured bridges from tor.
- let bridgeReply = gProtocolSvc.TorGetConf(kTorConfKeyBridgeList);
+ let bridgeReply = await gProtocolSvc.TorGetConf(kTorConfKeyBridgeList);
if (!gProtocolSvc.TorCommandSucceeded(bridgeReply))
return false;
@@ -1953,21 +1956,21 @@ function initBridgeSettings()
// Returns true if settings were successfully applied.
-function applySettings(aUseDefaults)
+async function applySettings(aUseDefaults)
{
TorLauncherLogger.log(2, "applySettings ---------------------" +
"----------------------------------------------");
var didSucceed = false;
try
{
- didSucceed = applyBridgeSettings(aUseDefaults) &&
- applyProxySettings(aUseDefaults) &&
- applyFirewallSettings(aUseDefaults);
+ didSucceed = await applyBridgeSettings(aUseDefaults) &&
+ await applyProxySettings(aUseDefaults) &&
+ await applyFirewallSettings(aUseDefaults);
}
catch (e) { TorLauncherLogger.safelog(4, "Error in applySettings: ", e); }
if (didSucceed)
- useSettings();
+ await useSettings();
TorLauncherLogger.log(2, "applySettings done");
@@ -1975,11 +1978,11 @@ function applySettings(aUseDefaults)
}
-function useSettings()
+async function useSettings()
{
var settings = {};
settings[kTorConfKeyDisableNetwork] = false;
- let didApply = setConfAndReportErrors(settings, null);
+ let didApply = await setConfAndReportErrors(settings, null);
if (!didApply)
return;
@@ -1997,7 +2000,7 @@ function useSettings()
gIsPostRestartBootstrapNeeded = false;
- gProtocolSvc.TorSendCommand("SAVECONF");
+ await gProtocolSvc.TorSendCommand("SAVECONF");
gTorProcessService.TorClearBootstrapError();
// If bootstrapping has finished or we are not responsible for starting
@@ -2009,11 +2012,11 @@ function useSettings()
return;
}
- showProgressPanel();
+ await showProgressPanel();
}
-function stopTorBootstrap()
+async function stopTorBootstrap()
{
// Tell tor to disable use of the network; this should stop the bootstrap
// process.
@@ -2023,7 +2026,7 @@ function stopTorBootstrap()
let settings = {};
settings["DisableNetwork"] = true;
let errObj = {};
- if (!gProtocolSvc.TorSetConfWithReply(settings, errObj))
+ if (!await gProtocolSvc.TorSetConfWithReply(settings, errObj))
TorLauncherLogger.log(5, kErrorPrefix + errObj.details);
}
catch(e)
@@ -2033,7 +2036,7 @@ function stopTorBootstrap()
}
-function showProgressPanel()
+async function showProgressPanel()
{
let progressContent = document.getElementById("progressContent");
if (progressContent)
@@ -2072,7 +2075,7 @@ function showProgressPanel()
// Request the most recent bootstrap status info so that a
// TorBootstrapStatus notification is generated as soon as possible.
- gProtocolSvc.TorRetrieveBootstrapStatus();
+ await gProtocolSvc.TorRetrieveBootstrapStatus();
// Also start a fail-safe timer to ensure that the progress bar is displayed
// within 2 seconds in all cases.
@@ -2089,14 +2092,14 @@ function showProgressMeterIfNoError()
// Returns true if settings were successfully applied.
-function applyProxySettings(aUseDefaults)
+async function applyProxySettings(aUseDefaults)
{
let settings = aUseDefaults ? getDefaultProxySettings()
: getAndValidateProxySettings(false);
if (!settings)
return false;
- return setConfAndReportErrors(settings, "configureSettings");
+ return await setConfAndReportErrors(settings, "configureSettings");
}
@@ -2187,7 +2190,7 @@ function reportValidationError(aStrKey)
// Returns true if settings were successfully applied.
-function applyFirewallSettings(aUseDefaults)
+async function applyFirewallSettings(aUseDefaults)
{
let settings;
if (aUseDefaults)
@@ -2200,7 +2203,7 @@ function applyFirewallSettings(aUseDefaults)
if (!settings)
return false;
- return setConfAndReportErrors(settings, null);
+ return await setConfAndReportErrors(settings, null);
}
@@ -2327,7 +2330,7 @@ function initDefaultBridgeTypeMenu()
// Returns true if settings were successfully applied.
-function applyBridgeSettings(aUseDefaults)
+async function applyBridgeSettings(aUseDefaults)
{
let settings = (aUseDefaults) ? getDefaultBridgeSettings()
: getAndValidateBridgeSettings();
@@ -2337,7 +2340,7 @@ function applyBridgeSettings(aUseDefaults)
if (aUseDefaults)
TorLauncherUtil.setCharPref(kPrefDefaultBridgeType, "");
- return setConfAndReportErrors(settings, "configureSettings");
+ return await setConfAndReportErrors(settings, "configureSettings");
}
@@ -2450,10 +2453,10 @@ function parseAndValidateBridges(aStr)
// Returns true if successful.
// aShowOnErrorPanelID is only used when displaying the wizard.
-function setConfAndReportErrors(aSettingsObj, aShowOnErrorPanelID)
+async function setConfAndReportErrors(aSettingsObj, aShowOnErrorPanelID)
{
var errObj = {};
- var didSucceed = gProtocolSvc.TorSetConfWithReply(aSettingsObj, errObj);
+ var didSucceed = await gProtocolSvc.TorSetConfWithReply(aSettingsObj, errObj);
if (!didSucceed)
{
if (aShowOnErrorPanelID)
diff --git a/src/components/tl-process.js b/src/components/tl-process.js
index a4374f9..bafc295 100644
--- a/src/components/tl-process.js
+++ b/src/components/tl-process.js
@@ -86,7 +86,7 @@ TorProcessService.prototype =
lockFactory: function(aDoLock) {},
// nsIObserver implementation.
- observe: function(aSubject, aTopic, aParam)
+ observe: async function(aSubject, aTopic, aParam)
{
const kOpenNetworkSettingsTopic = "TorOpenNetworkSettings";
const kUserQuitTopic = "TorUserRequestedQuit";
@@ -254,7 +254,7 @@ TorProcessService.prototype =
// We configure default bridges each time we start tor in case
// new default bridge preference values are available (e.g., due
// to a TBB update).
- this._configureDefaultBridges();
+ await this._configureDefaultBridges();
}
this.mObsSvc.notifyObservers(null, "TorProcessIsReady", null);
@@ -706,7 +706,7 @@ TorProcessService.prototype =
return this.kDefaultBridgesStatus_InUse;
},
- _configureDefaultBridges: function()
+ _configureDefaultBridges: async function()
{
var settings = {};
var bridgeArray = TorLauncherUtil.defaultBridges;
@@ -714,7 +714,7 @@ TorProcessService.prototype =
settings["UseBridges"] = useBridges;
settings["Bridge"] = bridgeArray;
var errObj = {};
- var didSucceed = this.mProtocolSvc.TorSetConfWithReply(settings, errObj);
+ var didSucceed = await this.mProtocolSvc.TorSetConfWithReply(settings, errObj);
// If the network settings wizard was not opened at startup, enable the
// network so that bootstrapping will proceed with the default bridges.
@@ -722,7 +722,7 @@ TorProcessService.prototype =
{
settings = {};
settings["DisableNetwork"] = false;
- if (!this.mProtocolSvc.TorSetConfWithReply(settings,
+ if (!await this.mProtocolSvc.TorSetConfWithReply(settings,
(didSucceed) ? errObj : null))
{
didSucceed = false;
diff --git a/src/components/tl-protocol.js b/src/components/tl-protocol.js
index 0e8075a..93b22bb 100644
--- a/src/components/tl-protocol.js
+++ b/src/components/tl-protocol.js
@@ -14,12 +14,16 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
+XPCOMUtils.defineLazyModuleGetters(this, {
+ setTimeout: "resource://gre/modules/Timer.jsm",
+});
XPCOMUtils.defineLazyModuleGetter(this, "TorLauncherUtil",
"resource://torlauncher/modules/tl-util.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TorLauncherLogger",
"resource://torlauncher/modules/tl-logger.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
+let { configureControlPortModule, controller } = Cu.import("resource://torbutton/modules/tor-control-port.js", {});
function TorProtocolService()
@@ -198,6 +202,12 @@ function TorProtocolService()
TorLauncherLogger.log(3, "SOCKS host: " + this.mSOCKSPortInfo.host);
TorLauncherLogger.log(3, "SOCKS port: " + this.mSOCKSPortInfo.port);
}
+
+ // Set the global control port info parameters.
+ // These values may be overwritten by torbutton when it initializes, but
+ // torbutton's values *should* be identical.
+ configureControlPortModule(this.mControlIPCFile, this.mControlHost,
+ this.mControlPort, this.mControlPassword);
}
catch(e)
{
@@ -323,13 +333,13 @@ TorProtocolService.prototype =
// Perform a GETCONF command.
// If a fatal error occurs, null is returned. Otherwise, a reply object is
// returned.
- TorGetConf: function(aKey)
+ TorGetConf: async function(aKey)
{
if (!aKey || (aKey.length < 1))
return null;
var cmd = "GETCONF";
- var reply = this.TorSendCommand(cmd, aKey);
+ var reply = await this.TorSendCommand(cmd, aKey);
if (!this.TorCommandSucceeded(reply))
return reply;
@@ -338,9 +348,9 @@ TorProtocolService.prototype =
// Returns a reply object. If the GETCONF command succeeded, reply.retVal
// is set (if there is no setting for aKey, it is set to aDefault).
- TorGetConfStr: function(aKey, aDefault)
+ TorGetConfStr: async function(aKey, aDefault)
{
- var reply = this.TorGetConf(aKey);
+ var reply = await this.TorGetConf(aKey);
if (this.TorCommandSucceeded(reply))
{
if (reply.lineArray.length > 0)
@@ -354,9 +364,9 @@ TorProtocolService.prototype =
// Returns a reply object. If the GETCONF command succeeded, reply.retVal
// is set (if there is no setting for aKey, it is set to aDefault).
- TorGetConfBool: function(aKey, aDefault)
+ TorGetConfBool: async function(aKey, aDefault)
{
- var reply = this.TorGetConf(aKey);
+ var reply = await this.TorGetConf(aKey);
if (this.TorCommandSucceeded(reply))
{
if (reply.lineArray.length > 0)
@@ -376,7 +386,7 @@ TorProtocolService.prototype =
// passed in the SETCONF command.
// If a fatal error occurs, null is returned. Otherwise, a reply object is
// returned.
- TorSetConf: function(aSettingsObj)
+ TorSetConf: async function(aSettingsObj)
{
if (!aSettingsObj)
return null;
@@ -420,14 +430,14 @@ TorProtocolService.prototype =
return null;
}
- return this.TorSendCommand("SETCONF", cmdArgs);
+ return await this.TorSendCommand("SETCONF", cmdArgs);
}, // TorSetConf()
// Returns true if successful.
// Upon failure, aErrorObj.details will be set to a string.
- TorSetConfWithReply: function(aSettingsObj, aErrorObj)
+ TorSetConfWithReply: async function(aSettingsObj, aErrorObj)
{
- var reply = this.TorSetConf(aSettingsObj);
+ var reply = await this.TorSetConf(aSettingsObj);
var didSucceed = this.TorCommandSucceeded(reply);
if (!didSucceed)
{
@@ -450,11 +460,11 @@ TorProtocolService.prototype =
},
// If successful, sends a "TorBootstrapStatus" notification.
- TorRetrieveBootstrapStatus: function()
+ TorRetrieveBootstrapStatus: async function()
{
var cmd = "GETINFO";
var key = "status/bootstrap-phase";
- var reply = this.TorSendCommand(cmd, key);
+ var reply = await this.TorSendCommand(cmd, key);
if (!this.TorCommandSucceeded(reply))
{
TorLauncherLogger.log(4, "TorRetrieveBootstrapStatus: command failed");
@@ -548,7 +558,7 @@ TorProtocolService.prototype =
// Executes a command on the control port.
// Return a reply object or null if a fatal error occurs.
- TorSendCommand: function(aCmd, aArgs)
+ TorSendCommand: async function(aCmd, aArgs)
{
var reply;
for (var attempt = 0; !reply && (attempt < 2); ++attempt)
@@ -556,10 +566,10 @@ TorProtocolService.prototype =
var conn;
try
{
- conn = this._getConnection();
+ conn = await this._getConnection();
if (conn)
{
- reply = this._sendCommand(conn, aCmd, aArgs)
+ reply = await conn.sendCommand(aCmd + (aArgs ? " " + aArgs : ""));
if (reply)
this._returnConnection(conn); // Return for reuse.
else
@@ -573,6 +583,22 @@ TorProtocolService.prototype =
}
}
+ // We failed to acquire the controller after multiple attempts.
+ // Try again after some time.
+ if (!conn) {
+ TorLauncherLogger.safelog(2, "TorSendCommand: Acquiring control connection failed: ", aCmd + ", " + aArgs);
+ let thisTorSendCommand = this.TorSendCommand.bind(this);
+ return await new Promise(resolve => setTimeout(function() {
+ TorLauncherLogger.safelog(2, "TorSendCommand: Trying again, resolving TorSendCommand: ", aCmd + ", " + aArgs);
+ resolve(thisTorSendCommand(aCmd, aArgs));
+ }, 250)
+ )};
+
+ if (!reply)
+ return reply;
+
+ reply = this.TorParseCommandResponse(reply);
+
return reply;
}, // TorSendCommand()
@@ -581,6 +607,21 @@ TorProtocolService.prototype =
return !!(aReply && (this.kCmdStatusOK == aReply.statusCode));
},
+ // Helper function for converting a raw controller response into a parsed object.
+ TorParseCommandResponse: function(reply)
+ {
+ if (!reply)
+ return {};
+ let lines = reply.split("\r\n");
+ reply = {};
+ for (let line in lines) {
+ if (this._parseOneReplyLine(lines[line], reply) || reply._parseError) {
+ break;
+ }
+ }
+ return reply;
+ },
+
// TorCleanupConnection() is called during browser shutdown.
TorCleanupConnection: function()
{
@@ -588,12 +629,12 @@ TorProtocolService.prototype =
this._shutDownEventMonitor();
},
- TorStartEventMonitor: function()
+ TorStartEventMonitor: async function()
{
if (this.mEventMonitorConnection)
return;
- var conn = this._openAuthenticatedConnection(true);
+ var conn = await this._openAuthenticatedConnection(true);
if (!conn)
{
TorLauncherLogger.log(4,
@@ -603,7 +644,9 @@ TorProtocolService.prototype =
// TODO: optionally monitor INFO and DEBUG log messages.
var events = "STATUS_CLIENT NOTICE WARN ERR";
- var reply = this._sendCommand(conn, "SETEVENTS", events);
+ //var events = "STATUS_CLIENT WARN ERR";
+ var reply = await conn.sendCommand("SETEVENTS " + events);
+ reply = this.TorParseCommandResponse(reply);
if (!this.TorCommandSucceeded(reply))
{
TorLauncherLogger.log(4, "SETEVENTS failed");
@@ -671,9 +714,9 @@ TorProtocolService.prototype =
// Return true if a control connection is established (will create a
// connection if necessary).
- TorHaveControlConnection: function()
+ TorHaveControlConnection: async function()
{
- var conn = this._getConnection();
+ var conn = await this._getConnection();
this._returnConnection(conn);
return (conn != null);
},
@@ -703,7 +746,7 @@ TorProtocolService.prototype =
// inStream // nsIInputStream
// binInStream // nsIBinaryInputStream
// binOutStream // nsIBinaryOutputStream
- _getConnection: function()
+ _getConnection: async function()
{
if (this.mControlConnection)
{
@@ -714,7 +757,7 @@ TorProtocolService.prototype =
}
}
else
- this.mControlConnection = this._openAuthenticatedConnection(false);
+ this.mControlConnection = await this._openAuthenticatedConnection(false);
if (this.mControlConnection)
this.mControlConnection.inUse = true;
@@ -728,101 +771,27 @@ TorProtocolService.prototype =
this.mControlConnection.inUse = false;
},
- _openAuthenticatedConnection: function(aIsEventConnection)
+ _openAuthenticatedConnection: async function(aIsEventConnection)
{
var conn;
- try
- {
- let sts = Cc["@mozilla.org/network/socket-transport-service;1"]
- .getService(Ci.nsISocketTransportService);
- let socket;
- if (this.mControlIPCFile)
- {
- let exists = this.mControlIPCFile.exists();
- if (!exists)
- {
- TorLauncherLogger.log(5, "Control port IPC object does not exist: " +
- this.mControlIPCFile.path);
- }
- else
- {
- let isSpecial = this.mControlIPCFile.isSpecial();
- if (!isSpecial)
- {
- TorLauncherLogger.log(5,
- "Control port IPC object is not a special file: " +
- this.mControlIPCFile.path);
- }
- else
- {
- TorLauncherLogger.log(2, "Opening control connection to " +
- this.mControlIPCFile.path);
- socket = sts.createUnixDomainTransport(this.mControlIPCFile);
- }
- }
- }
- else
- {
- TorLauncherLogger.log(2, "Opening control connection to " +
- this.mControlHost + ":" + this.mControlPort);
- socket = sts.createTransport([], this.mControlHost,
- this.mControlPort, null);
- }
-
- if (!socket)
- return null;
-
- // Our event monitor connection is non-blocking and unbuffered (an
- // asyncWait() call is used so we only read data when we know that
- // some is available).
- // Our main control connection is blocking and unbuffered (using
- // buffering may prevent data from being sent before we enter a
- // blocking readBytes() call.
- var flags = (aIsEventConnection) ? 0
- : socket.OPEN_BLOCKING | socket.OPEN_UNBUFFERED;
- // If using a blocking socket, we set segment size and count to 1 to
- // avoid buffering inside the Mozilla code. See Tor ticket # 8642.
- var segSize = (aIsEventConnection) ? 0 : 1;
- var segCount = (aIsEventConnection) ? 0 : 1;
- var inStream = socket.openInputStream(flags, segSize, segCount);
- var outStream = socket.openOutputStream(flags, segSize, segCount);
-
- var binInStream = Cc["@mozilla.org/binaryinputstream;1"]
- .createInstance(Ci.nsIBinaryInputStream);
- var binOutStream = Cc["@mozilla.org/binaryoutputstream;1"]
- .createInstance(Ci.nsIBinaryOutputStream);
- binInStream.setInputStream(inStream);
- binOutStream.setOutputStream(outStream);
- conn = { useCount: 0, socket: socket, inStream: inStream,
- binInStream: binInStream, binOutStream: binOutStream };
-
- // AUTHENTICATE
- var pwdArg = this._strEscape(this.mControlPassword);
- if (pwdArg && (pwdArg.length > 0) && (pwdArg.charAt(0) != '"'))
- {
- // Surround non-hex strings with double quotes.
- const kIsHexRE = /^[A-Fa-f0-9]*$/;
- if (!kIsHexRE.test(pwdArg))
- pwdArg = '"' + pwdArg + '"';
- }
- var reply = this._sendCommand(conn, "AUTHENTICATE", pwdArg);
- if (!this.TorCommandSucceeded(reply))
- {
- TorLauncherLogger.log(4, "authenticate failed");
- return null;
- }
+ try {
+ const avoidCache = true;
+ conn = controller(e => { throw e; }, avoidCache);
if (!aIsEventConnection && TorLauncherUtil.shouldStartAndOwnTor &&
!TorLauncherUtil.shouldOnlyConfigureTor)
{
// Try to become the primary controller (TAKEOWNERSHIP).
- reply = this._sendCommand(conn, "TAKEOWNERSHIP", null);
+ const takeOwnership = "TAKEOWNERSHIP";
+ let reply = await conn.sendCommand(takeOwnership);
+ reply = this.TorParseCommandResponse(reply);
if (!this.TorCommandSucceeded(reply))
TorLauncherLogger.log(4, "take ownership failed");
else
{
- reply = this._sendCommand(conn, "RESETCONF",
- "__OwningControllerProcess");
+ const resetConf = "RESETCONF __OwningControllerProcess";
+ reply = await conn.sendCommand(takeOwnership);
+ reply = this.TorParseCommandResponse(reply);
if (!this.TorCommandSucceeded(reply))
TorLauncherLogger.log(4, "clear owning controller process failed");
}
@@ -952,6 +921,7 @@ TorProtocolService.prototype =
aReplyObj._parseError = false;
}
+
if (aLine.length < 4)
{
TorLauncherLogger.safelog(4, "Unexpected response: ", aLine);
@@ -1396,77 +1366,26 @@ TorProtocolService.prototype =
return;
var _this = this;
- var eventReader = // An implementation of nsIInputStreamCallback.
- {
- onInputStreamReady: function(aInStream)
- {
- if (!_this.mEventMonitorConnection ||
- (_this.mEventMonitorConnection.inStream != aInStream))
- {
- return;
- }
-
- try
- {
- var binStream = _this.mEventMonitorConnection.binInStream;
- var bytes = binStream.readBytes(binStream.available());
- if (!_this.mEventMonitorBuffer)
- _this.mEventMonitorBuffer = bytes;
- else
- _this.mEventMonitorBuffer += bytes;
- _this._processEventData();
-
- _this._waitForEventData();
- }
- catch (e)
- {
- // Probably we got here because tor exited. If tor is restarted by
- // Tor Launcher, the event monitor will be restarted too.
- TorLauncherLogger.safelog(4, "Event monitor read error", e);
- _this._shutDownEventMonitor();
- }
- }
- };
-
- var curThread = Cc["@mozilla.org/thread-manager;1"].getService()
- .currentThread;
- var asyncInStream = this.mEventMonitorConnection.inStream
- .QueryInterface(Ci.nsIAsyncInputStream);
- asyncInStream.asyncWait(eventReader, 0, 0, curThread);
+ this.mEventMonitorConnection.watchEvent("STATUS_CLIENT", null, function (data) {
+ return _this._processEventData.bind(_this, data)();
+ }, true);
},
- _processEventData: function()
+ _processEventData: function(line)
{
- var replyData = this.mEventMonitorBuffer;
- if (!replyData)
+ if (!line)
return;
- var idx = -1;
- do
+ TorLauncherLogger.safelog(2, "Event response: ", line);
+ if (!this.mEventMonitorInProgressReply)
+ this.mEventMonitorInProgressReply = {};
+ var replyObj = this.mEventMonitorInProgressReply;
+ var isComplete = this._parseOneReplyLine(line, replyObj);
+ if (isComplete)
{
- idx = replyData.indexOf('\n');
- if (idx >= 0)
- {
- let line = replyData.substring(0, idx);
- replyData = replyData.substring(idx + 1);
- let len = line.length;
- if ((len > 0) && ('\r' == line.substr(len - 1)))
- line = line.substr(0, len - 1);
-
- TorLauncherLogger.safelog(2, "Event response: ", line);
- if (!this.mEventMonitorInProgressReply)
- this.mEventMonitorInProgressReply = {};
- var replyObj = this.mEventMonitorInProgressReply;
- var isComplete = this._parseOneReplyLine(line, replyObj);
- if (isComplete)
- {
- this._processEventReply(replyObj);
- this.mEventMonitorInProgressReply = null;
- }
- }
- } while ((idx >= 0) && replyData)
-
- this.mEventMonitorBuffer = replyData;
+ this._processEventReply(replyObj);
+ this.mEventMonitorInProgressReply = null;
+ }
},
_processEventReply: function(aReply)
1
0

27 Aug '21
commit 3b22e7671322c6f1d200c8b5f08ac3965f57bd1e
Author: Matthew Finkel <sysrqb(a)torproject.org>
Date: Wed Aug 25 15:05:10 2021 +0000
Bug 40004: Cleanup unused/unneeded code
---
src/components/tl-process.js | 16 ---------
src/components/tl-protocol.js | 79 -------------------------------------------
2 files changed, 95 deletions(-)
diff --git a/src/components/tl-process.js b/src/components/tl-process.js
index bafc295..f45c17c 100644
--- a/src/components/tl-process.js
+++ b/src/components/tl-process.js
@@ -100,22 +100,6 @@ TorProcessService.prototype =
if ("profile-after-change" == aTopic)
{
- // Initialize the DNS service here (as early as possible). This
- // avoids a deadlock that can occur inside TorProtocolService's
- // _openAuthenticatedConnection() function. What happens in the
- // deadlock case is that a Necko socket thread tries to dispatch
- // initialization of the DNS service to the main thread while the
- // main thread is blocked in a writeBytes() call inside the
- // _sendCommand() function. The ultimate solution is to change
- // our control port socket to use asynchronous I/O.
- // References:
- // netwerk/dns/nsDNSService2.cpp nsDNSService::GetSingleton()
- // https://bugzilla.mozilla.org/show_bug.cgi?id=1625151 (the
- // fix for this bug introduced the deadlock because it changed
- // DNS service initialization to occur on the main thread).
- const dns = Cc["@mozilla.org/network/dns-service;1"]
- .getService(Ci.nsIDNSService);
-
this.mObsSvc.addObserver(this, "quit-application-granted", false);
this.mObsSvc.addObserver(this, kOpenNetworkSettingsTopic, false);
this.mObsSvc.addObserver(this, kUserQuitTopic, false);
diff --git a/src/components/tl-protocol.js b/src/components/tl-protocol.js
index 93b22bb..ceb5a0c 100644
--- a/src/components/tl-protocol.js
+++ b/src/components/tl-protocol.js
@@ -827,85 +827,6 @@ TorProtocolService.prototype =
this.mControlConnection = null;
},
- _setSocketTimeout: function(aConn)
- {
- if (aConn && aConn.socket)
- aConn.socket.setTimeout(Ci.nsISocketTransport.TIMEOUT_READ_WRITE, 15);
- },
-
- _clearSocketTimeout: function(aConn)
- {
- if (aConn && aConn.socket)
- {
- var secs = Math.pow(2,32) - 1; // UINT32_MAX
- aConn.socket.setTimeout(Ci.nsISocketTransport.TIMEOUT_READ_WRITE, secs);
- }
- },
-
- _sendCommand: function(aConn, aCmd, aArgs)
- {
- var reply;
- if (aConn)
- {
- var cmd = aCmd;
- if (aArgs)
- cmd += ' ' + aArgs;
- TorLauncherLogger.safelog(2, "Sending Tor command: ", cmd);
- cmd += "\r\n";
-
- ++aConn.useCount;
- this._setSocketTimeout(aConn);
- // TODO: should handle NS_BASE_STREAM_WOULD_BLOCK here.
- aConn.binOutStream.writeBytes(cmd, cmd.length);
- reply = this._torReadReply(aConn.binInStream);
- this._clearSocketTimeout(aConn);
- }
-
- return reply;
- },
-
- // Returns a reply object. Blocks until entire reply has been received.
- _torReadReply: function(aInput)
- {
- var replyObj = {};
- do
- {
- var line = this._torReadLine(aInput);
- TorLauncherLogger.safelog(2, "Command response: ", line);
- } while (!this._parseOneReplyLine(line, replyObj));
-
- return (replyObj._parseError) ? null : replyObj;
- },
-
- // Returns a string. Blocks until a line has been received.
- _torReadLine: function(aInput)
- {
- var str = "";
- while(true)
- {
- try
- {
-// TODO: readBytes() will sometimes hang if the control connection is opened
-// immediately after tor opens its listener socket. Why?
- let bytes = aInput.readBytes(1);
- if ('\n' == bytes)
- break;
-
- str += bytes;
- }
- catch (e)
- {
- if (e.result != Cr.NS_BASE_STREAM_WOULD_BLOCK)
- throw e;
- }
- }
-
- var len = str.length;
- if ((len > 0) && ('\r' == str.substr(len - 1)))
- str = str.substr(0, len - 1);
- return str;
- },
-
// Returns false if more lines are needed. The first time, callers
// should pass an empty aReplyObj.
// Parsing errors are indicated by aReplyObj._parseError = true.
1
0
commit 19aabb81a033afef39f85a9ef0117f92d4522bb8
Author: gus <gus(a)torproject.org>
Date: Fri Aug 27 17:29:35 2021 -0300
Closes #255
---
content/about/jobs/rust-dev/contents.lr | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/content/about/jobs/rust-dev/contents.lr b/content/about/jobs/rust-dev/contents.lr
index 2950759d..b61a0e0b 100644
--- a/content/about/jobs/rust-dev/contents.lr
+++ b/content/about/jobs/rust-dev/contents.lr
@@ -6,7 +6,7 @@ section: about
---
section_id: about
---
-active: yes
+active: no
---
title: Software Developer, Rust
---
1
0

[translation/tor-launcher-network-settings_completed] https://gitweb.torproject.org/translation.git/commit/?h=tor-launcher-network-settings_completed
by translation@torproject.org 27 Aug '21
by translation@torproject.org 27 Aug '21
27 Aug '21
commit da81ac254bc393c711103f829d2e4308ad4f8e25
Author: Translation commit bot <translation(a)torproject.org>
Date: Fri Aug 27 18:17:44 2021 +0000
https://gitweb.torproject.org/translation.git/commit/?h=tor-launcher-networ…
---
it/network-settings.dtd | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/it/network-settings.dtd b/it/network-settings.dtd
index aeadf75c90..fc9ddc9bf4 100644
--- a/it/network-settings.dtd
+++ b/it/network-settings.dtd
@@ -66,6 +66,9 @@
<!ENTITY torPreferences.torSettings "Impostazioni di Tor">
<!ENTITY torPreferences.torSettingsDescription "Tor Browser indirizza il tuo traffico nella rete Tor, gestita da migliaia di volontari in tutto il mondo." >
<!ENTITY torPreferences.learnMore "Maggiori informazioni">
+<!ENTITY torPreferences.quickstart "Quickstart">
+<!ENTITY torPreferences.quickstartDescription "Quickstart permette a Tor Browser di connettersi automaticamente.">
+<!ENTITY torPreferences.quickstartCheckbox "Connetti sempre automaticamente">
<!ENTITY torPreferences.bridges "Bridges">
<!ENTITY torPreferences.bridgesDescription "I bridge ti aiutano ad accedere alla rete Tor in luoghi dove Tor viene bloccato. A seconda di dove ti trovi, un bridge può funzionare meglio di un altro.">
<!ENTITY torPreferences.useBridge "Usa un bridge">
@@ -89,4 +92,5 @@
<!ENTITY torConnect.tryAgainMessage "">
<!ENTITY torConnect.connectingConcise "">
<!ENTITY torConnect.connectedConcise "">
+<!ENTITY torConnect.notConnectedConcise "Non Connesso">
<!ENTITY torConnect.copyLog "">
1
0