[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [torbutton/master] Bug 20111: use Unix domain sockets for SOCKS port by default
commit f4980a6c647ea780eacc922846e81c0d992cbd13
Author: Kathy Brade <brade@xxxxxxxxxxxxxxxxx>
Date: Tue Oct 11 15:37:47 2016 -0400
Bug 20111: use Unix domain sockets for SOCKS port by default
Retrieve SOCKS port configuration from Tor Launcher if available.
Support the TOR_SOCKS_IPC_PATH environment variable.
Consistently use IPC to refer to Unix domain sockets.
Enhance torbutton_local_tor_check() to correctly handle spaces and
escaped characters within the 'GETINFO net/listeners/socks' response.
Within startup-observer.js, use Services.jsm, Cc and similar
constants, and remove unused code.
---
src/chrome/content/tor-circuit-display.js | 12 +--
src/chrome/content/torbutton.js | 64 +++++++++-------
src/components/startup-observer.js | 117 +++++++++++++++++++-----------
src/modules/tor-control-port.js | 51 +++++++------
src/modules/utils.js | 101 +++++++++++++++++++++++++-
5 files changed, 242 insertions(+), 103 deletions(-)
diff --git a/src/chrome/content/tor-circuit-display.js b/src/chrome/content/tor-circuit-display.js
index f1cf2aa..c58c6d7 100644
--- a/src/chrome/content/tor-circuit-display.js
+++ b/src/chrome/content/tor-circuit-display.js
@@ -6,7 +6,7 @@
// with docco.js to produce pretty documentation.
//
// This script is to be embedded in torbutton.xul. It defines a single global
-// function, createTorCircuitDisplay(socketFile, host, port, password), which
+// function, createTorCircuitDisplay(ipcFile, host, port, password), which
// activates the automatic Tor circuit display for the current tab and any
// future tabs.
//
@@ -16,9 +16,9 @@
/* global document, gBrowser, Components */
// ### Main function
-// __createTorCircuitDisplay(socketFile, host, port, password, enablePrefName)__.
+// __createTorCircuitDisplay(ipcFile, host, port, password, enablePrefName)__.
// The single function that prepares tor circuit display. Connects to a tor
-// control port with the given socketFile or host plus port, and password, and
+// control port with the given ipcFile or host plus port, and password, and
// binds to a named bool pref whose value determines whether the circuit display
// is enabled or disabled.
let createTorCircuitDisplay = (function () {
@@ -312,11 +312,11 @@ let syncDisplayWithSelectedTab = (function() {
// ## Main function
-// __setupDisplay(socketFile, host, port, password, enablePrefName)__.
+// __setupDisplay(ipcFile, host, port, password, enablePrefName)__.
// Once called, the Tor circuit display will be started whenever
// the "enablePref" is set to true, and stopped when it is set to false.
// A reference to this function (called createTorCircuitDisplay) is exported as a global.
-let setupDisplay = function (socketFile, host, port, password, enablePrefName) {
+let setupDisplay = function (ipcFile, host, port, password, enablePrefName) {
let myController = null,
stopCollectingIsolationData = null,
stop = function() {
@@ -330,7 +330,7 @@ let setupDisplay = function (socketFile, host, port, password, enablePrefName) {
},
start = function () {
if (!myController) {
- myController = controller(socketFile, host, port || 9151, password,
+ myController = controller(ipcFile, host, port || 9151, password,
function (err) {
// An error has occurred.
logger.eclog(5, err);
diff --git a/src/chrome/content/torbutton.js b/src/chrome/content/torbutton.js
index d2824cb..9a8b9e2 100644
--- a/src/chrome/content/torbutton.js
+++ b/src/chrome/content/torbutton.js
@@ -10,6 +10,7 @@
let { LoadContextInfo } = Cu.import('resource://gre/modules/LoadContextInfo.jsm');
let { Services } = Cu.import("resource://gre/modules/Services.jsm");
let { showDialog } = Cu.import("resource://torbutton/modules/utils.js");
+let { unescapeTorString } = Cu.import("resource://torbutton/modules/utils.js");
const k_tb_last_browser_version_pref = "extensions.torbutton.lastBrowserVersion";
const k_tb_browser_update_needed_pref = "extensions.torbutton.updateNeeded";
@@ -33,9 +34,9 @@ var m_tb_window_width = window.outerWidth;
var m_tb_tbb = false;
-var m_tb_control_socket_file = null; // Set if using a UNIX domain socket.
-var m_tb_control_port = null; // Set if not using a socket.
-var m_tb_control_host = null; // Set if not using a socket.
+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.
var m_tb_control_pass = null;
var m_tb_control_desc = null; // For logging.
@@ -327,15 +328,15 @@ function torbutton_init() {
m_tb_control_pass = tlps.TorGetPassword(false);
} catch(e) {}
- // Try to get control port socket (an nsIFile) from Tor Launcher, since
- // Tor Launcher knows how to handle its own preferences and how to
+ // Try to get the control port IPC file (an nsIFile) from Tor Launcher,
+ // since Tor Launcher knows how to handle its own preferences and how to
// resolve relative paths.
try {
- m_tb_control_socket_file = tlps.TorGetControlSocketFile();
+ m_tb_control_ipc_file = tlps.TorGetControlIPCFile();
} catch(e) {}
- if (m_tb_control_socket_file) {
- m_tb_control_desc = m_tb_control_socket_file.path;
+ if (m_tb_control_ipc_file) {
+ m_tb_control_desc = m_tb_control_ipc_file.path;
} else {
if (environ.exists("TOR_CONTROL_PORT")) {
m_tb_control_port = environ.get("TOR_CONTROL_PORT");
@@ -438,7 +439,7 @@ function torbutton_init() {
torbutton_notify_if_update_needed();
torbutton_update_sync_ui();
- createTorCircuitDisplay(m_tb_control_socket_file, m_tb_control_host,
+ createTorCircuitDisplay(m_tb_control_ipc_file, m_tb_control_host,
m_tb_control_port, m_tb_control_pass,
"extensions.torbutton.display_circuit");
@@ -1009,8 +1010,8 @@ function torbutton_send_ctrl_cmd(command) {
let sts = Cc["@mozilla.org/network/socket-transport-service;1"]
.getService(Ci.nsISocketTransportService);
let socket;
- if (m_tb_control_socket_file) {
- socket = sts.createUnixDomainTransport(m_tb_control_socket_file);
+ if (m_tb_control_ipc_file) {
+ socket = sts.createUnixDomainTransport(m_tb_control_ipc_file);
} else {
socket = sts.createTransport(null, 0, m_tb_control_host,
m_tb_control_port, null);
@@ -1350,7 +1351,7 @@ function torbutton_do_new_identity() {
torbutton_log(3, "New Identity: Sending NEWNYM");
// We only support TBB for newnym.
- if (!m_tb_control_pass || (!m_tb_control_socket_file && !m_tb_control_port)) {
+ if (!m_tb_control_pass || (!m_tb_control_ipc_file && !m_tb_control_port)) {
var warning = torbutton_get_property_string("torbutton.popup.no_newnym");
torbutton_log(5, "Torbutton cannot safely newnym. It does not have access to the Tor Control Port.");
window.alert(warning);
@@ -1508,7 +1509,7 @@ function torbutton_do_tor_check()
const kEnvUseTransparentProxy = "TOR_TRANSPROXY";
var env = Cc["@mozilla.org/process/environment;1"]
.getService(Ci.nsIEnvironment);
- if ((m_tb_control_socket_file || m_tb_control_port) &&
+ if ((m_tb_control_ipc_file || m_tb_control_port) &&
!env.exists(kEnvUseTransparentProxy) &&
!env.exists(kEnvSkipControlPortTest) &&
m_tb_prefs.getBoolPref("extensions.torbutton.local_tor_check")) {
@@ -1559,19 +1560,20 @@ function torbutton_local_tor_check()
}
// Sample response: net/listeners/socks="127.0.0.1:9149" "127.0.0.1:9150"
- // First, check for command argument prefix.
+ // First, check for and remove the command argument prefix.
if (0 != resp.indexOf(kCmdArg + '=')) {
logUnexpectedResponse();
return false;
}
+ resp = resp.substr(kCmdArg.length + 1);
// Retrieve configured proxy settings and check each listener against them.
- // When a Unix domain socket is configured, a file URL should be present in
- // network.proxy.socks.
+ // When the SOCKS prefs are set to use IPC (e.g., a Unix domain socket), a
+ // file URL should be present in network.proxy.socks.
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1211567
let socksAddr = m_tb_prefs.getCharPref("network.proxy.socks");
let socksPort = m_tb_prefs.getIntPref("network.proxy.socks_port");
- let socketPath;
+ let socksIPCPath;
if (socksAddr && socksAddr.startsWith("file:")) {
// Convert the file URL to a file path.
try {
@@ -1579,19 +1581,29 @@ function torbutton_local_tor_check()
.getService(Ci.nsIIOService);
let fph = ioService.getProtocolHandler("file")
.QueryInterface(Ci.nsIFileProtocolHandler);
- socketPath = fph.getFileFromURLSpec(socksAddr).path;
+ socksIPCPath = fph.getFileFromURLSpec(socksAddr).path;
} catch (e) {
- torbutton_log(5, "Local Tor check: Unix domain socket error: " + e);
+ torbutton_log(5, "Local Tor check: IPC file error: " + e);
return false;
}
} else {
socksAddr = removeBrackets(socksAddr);
}
- let addrArray = resp.substr(kCmdArg.length + 1).split(' ');
+ // Split into quoted strings. This code is adapted from utils.splitAtSpaces()
+ // within tor-control-port.js; someday this code should use the entire
+ // tor-control-port.js framework.
+ let addrArray = [];
+ resp.replace(/((\S*?"(.*?)")+\S*|\S+)/g, function (a, captured) {
+ addrArray.push(captured);
+ });
+
let foundSocksListener = false;
for (let i = 0; !foundSocksListener && (i < addrArray.length); ++i) {
- let addr = addrArray[i];
+ let addr;
+ try { addr = unescapeTorString(addrArray[i]); } catch (e) {}
+ if (!addr)
+ continue;
// Remove double quotes if present.
let len = addr.length;
@@ -1599,14 +1611,14 @@ function torbutton_local_tor_check()
addr = addr.substring(1, len - 1);
if (addr.startsWith("unix:")) {
- if (!socketPath)
+ if (!socksIPCPath)
continue;
// Check against the configured UNIX domain socket proxy.
let path = addr.substring(5);
- torbutton_log(2, "Tor socks listener (socket): " + path);
- foundSocksListener = (socketPath === path);
- } else if (!socketPath) {
+ torbutton_log(2, "Tor socks listener (Unix domain socket): " + path);
+ foundSocksListener = (socksIPCPath === path);
+ } else if (!socksIPCPath) {
// Check against the configured TCP proxy. We expect addr:port where addr
// may be an IPv6 address; that is, it may contain colon characters.
// Also, we remove enclosing square brackets before comparing addresses
@@ -2088,7 +2100,7 @@ function torbutton_check_protections()
// See https://trac.torproject.org/projects/tor/ticket/10353 for more info.
document.getElementById("torbutton-cookie-protector").hidden = m_tb_prefs.getBoolPref("browser.privatebrowsing.autostart");
- if (!m_tb_control_pass || (!m_tb_control_socket_file && !m_tb_control_port)) {
+ if (!m_tb_control_pass || (!m_tb_control_ipc_file && !m_tb_control_port)) {
document.getElementById("torbutton-new-identity").disabled = true;
}
diff --git a/src/components/startup-observer.js b/src/components/startup-observer.js
index f083482..6698b0b 100644
--- a/src/components/startup-observer.js
+++ b/src/components/startup-observer.js
@@ -15,6 +15,13 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
+ "resource://gre/modules/FileUtils.jsm");
+
// Module specific constants
const kMODULE_NAME = "Startup";
@@ -22,10 +29,9 @@ const kMODULE_CONTRACTID = "@torproject.org/startup-observer;1";
const kMODULE_CID = Components.ID("06322def-6fde-4c06-aef6-47ae8e799629");
function StartupObserver() {
- this.logger = Components.classes["@torproject.org/torbutton-logger;1"]
- .getService(Components.interfaces.nsISupports).wrappedJSObject;
- this._prefs = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefBranch);
+ this.logger = Cc["@torproject.org/torbutton-logger;1"]
+ .getService(Ci.nsISupports).wrappedJSObject;
+ this._prefs = Services.prefs;
this.logger.log(3, "Startup Observer created");
var env = Cc["@mozilla.org/process/environment;1"]
@@ -61,41 +67,74 @@ StartupObserver.prototype = {
// some weird proxy caching code that showed up in FF15.
// Otherwise, homepage domain loads fail forever.
setProxySettings: function() {
+ if (!this.is_tbb)
+ return;
+
// Bug 1506: Still want to get these env vars
- var environ = Components.classes["@mozilla.org/process/environment;1"]
- .getService(Components.interfaces.nsIEnvironment);
-
- if (environ.exists("TOR_SOCKS_PORT")) {
- if (this.is_tbb) {
- this._prefs.setIntPref('network.proxy.socks_port',
- parseInt(environ.get("TOR_SOCKS_PORT")));
- this._prefs.setBoolPref('network.proxy.socks_remote_dns', true);
- this._prefs.setIntPref('network.proxy.type', 1);
+ let environ = Cc["@mozilla.org/process/environment;1"]
+ .getService(Ci.nsIEnvironment);
+ if (environ.exists("TOR_TRANSPROXY")) {
+ this.logger.log(3, "Resetting Tor settings to transproxy");
+ this._prefs.setBoolPref("network.proxy.socks_remote_dns", false);
+ this._prefs.setIntPref("network.proxy.type", 0);
+ this._prefs.setIntPref("network.proxy.socks_port", 0);
+ this._prefs.setCharPref("network.proxy.socks", "");
+ } else {
+ // Try to retrieve SOCKS proxy settings from Tor Launcher.
+ let socksPortInfo;
+ try {
+ let tlps = Cc["@torproject.org/torlauncher-protocol-service;1"]
+ .getService(Ci.nsISupports).wrappedJSObject;
+ socksPortInfo = tlps.TorGetSOCKSPortInfo();
+ } catch(e) {}
+
+ // If Tor Launcher is not available, check environment variables.
+ if (!socksPortInfo) {
+ socksPortInfo = { ipcFile: undefined, host: undefined, port: 0 };
+
+ let isWindows = Services.appinfo.OS === "WINNT";
+ if (!isWindows && environ.exists("TOR_SOCKS_IPC_PATH")) {
+ socksPortInfo.ipcFile = new FileUtils.File(
+ environ.get("TOR_SOCKS_IPC_PATH"));
+ }
+ else
+ {
+ if (environ.exists("TOR_SOCKS_HOST"))
+ socksPortInfo.host = environ.get("TOR_SOCKS_HOST");
+ if (environ.exists("TOR_SOCKS_PORT"))
+ socksPortInfo.port = parseInt(environ.get("TOR_SOCKS_PORT"));
+ }
}
- this.logger.log(3, "Reset socks port to "+environ.get("TOR_SOCKS_PORT"));
- }
- if (environ.exists("TOR_SOCKS_HOST")) {
- if (this.is_tbb) {
- this._prefs.setCharPref('network.proxy.socks', environ.get("TOR_SOCKS_HOST"));
+ // Adjust network.proxy prefs.
+ if (socksPortInfo.ipcFile) {
+ let fph = Services.io.getProtocolHandler("file")
+ .QueryInterface(Ci.nsIFileProtocolHandler);
+ let fileURI = fph.newFileURI(socksPortInfo.ipcFile);
+ this.logger.log(3, "Reset socks to "+fileURI.spec);
+ this._prefs.setCharPref("network.proxy.socks", fileURI.spec);
+ this._prefs.setIntPref("network.proxy.socks_port", 0);
+ } else {
+ if (socksPortInfo.host) {
+ this._prefs.setCharPref("network.proxy.socks", socksPortInfo.host);
+ this.logger.log(3, "Reset socks host to "+socksPortInfo.host);
+ }
+ if (socksPortInfo.port) {
+ this._prefs.setIntPref("network.proxy.socks_port",
+ socksPortInfo.port);
+ this.logger.log(3, "Reset socks port to "+socksPortInfo.port);
+ }
}
- }
- if (environ.exists("TOR_TRANSPROXY")) {
- this.logger.log(3, "Resetting Tor settings to transproxy");
- if (this.is_tbb) {
- this._prefs.setBoolPref('network.proxy.socks_remote_dns', false);
- this._prefs.setIntPref('network.proxy.type', 0);
- this._prefs.setIntPref('network.proxy.socks_port', 0);
- this._prefs.setCharPref('network.proxy.socks', "");
+ if (socksPortInfo.ipcFile || socksPortInfo.host || socksPortInfo.port) {
+ this._prefs.setBoolPref("network.proxy.socks_remote_dns", true);
+ this._prefs.setIntPref("network.proxy.type", 1);
}
}
// Force prefs to be synced to disk
- var prefService = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefService);
- prefService.savePrefFile(null);
-
+ this._prefs.savePrefFile(null);
+
this.logger.log(3, "Synced network settings to environment.");
},
@@ -109,16 +148,14 @@ StartupObserver.prototype = {
}
// In all cases, force prefs to be synced to disk
- var prefService = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefService);
- prefService.savePrefFile(null);
+ this._prefs.savePrefFile(null);
},
QueryInterface: function(iid) {
- if (iid.equals(Components.interfaces.nsISupports)) {
+ if (iid.equals(Ci.nsISupports)) {
return this;
}
- if(iid.equals(Components.interfaces.nsIClassInfo)) {
+ if(iid.equals(Ci.nsIClassInfo)) {
return this;
}
return this;
@@ -141,12 +178,4 @@ StartupObserver.prototype = {
};
-/**
-* XPCOMUtils.generateNSGetFactory was introduced in Mozilla 2 (Firefox 4).
-* XPCOMUtils.generateNSGetModule is for Mozilla 1.9.2 (Firefox 3.6).
-*/
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-if (XPCOMUtils.generateNSGetFactory)
- var NSGetFactory = XPCOMUtils.generateNSGetFactory([StartupObserver]);
-else
- var NSGetModule = XPCOMUtils.generateNSGetModule([StartupObserver]);
+var NSGetFactory = XPCOMUtils.generateNSGetFactory([StartupObserver]);
diff --git a/src/modules/tor-control-port.js b/src/modules/tor-control-port.js
index f23daed..a7f0434 100644
--- a/src/modules/tor-control-port.js
+++ b/src/modules/tor-control-port.js
@@ -10,7 +10,7 @@
// let { controller } = Components.utils.import("path/to/tor-control-port.js");
//
// See the last function defined in this file:
-// controller(socketFile, host, port, password, onError)
+// controller(ipcFile, host, port, password, onError)
// for usage of the controller function.
/* jshint esnext: true */
@@ -42,18 +42,18 @@ log("Loading tor-control-port.js\n");
// I/O utilities namespace
let io = {};
-// __io.asyncSocketStreams(socketFile, host, port)__.
+// __io.asyncSocketStreams(ipcFile, host, port)__.
// Creates a pair of asynchronous input and output streams for a socket at the
-// given socketFile or host and port.
-io.asyncSocketStreams = function (socketFile, host, port) {
+// given ipcFile or host and port.
+io.asyncSocketStreams = function (ipcFile, host, port) {
let sts = Cc["@mozilla.org/network/socket-transport-service;1"]
.getService(Components.interfaces.nsISocketTransportService),
UNBUFFERED = Ci.nsITransport.OPEN_UNBUFFERED;
// Create an instance of a socket transport.
let socketTransport;
- if (socketFile) {
- socketTransport = sts.createUnixDomainTransport(socketFile);
+ if (ipcFile) {
+ socketTransport = sts.createUnixDomainTransport(ipcFile);
} else {
socketTransport = sts.createTransport(null, 0, host, port, null);
}
@@ -99,16 +99,15 @@ io.pumpInputStream = function (inputStream, onInputData, onError) {
} }, null);
};
-// __io.asyncSocket(socketFile, host, port, onInputData, onError)__.
-// Creates an asynchronous, text-oriented UNIX domain socket (if socketFile
-// is defined) or TCP socket at host:port.
+// __io.asyncSocket(ipcFile, host, port, onInputData, onError)__.
+// Creates an asynchronous, text-oriented IPC socket (if ipcFile is defined)
+// or a TCP socket at host:port.
// The onInputData callback should accept a single argument, which will be called
// repeatedly, whenever incoming text arrives. Returns a socket object with two methods:
// socket.write(text) and socket.close(). onError will be passed the error object
// whenever a write fails.
-io.asyncSocket = function (socketFile, host, port, onInputData, onError) {
- let [inputStream, outputStream] = io.asyncSocketStreams(socketFile, host,
- port),
+io.asyncSocket = function (ipcFile, host, port, onInputData, onError) {
+ let [inputStream, outputStream] = io.asyncSocketStreams(ipcFile, host, port),
pendingWrites = [];
// Run an input stream pump to send incoming data to the onInputData callback.
io.pumpInputStream(inputStream, onInputData, onError);
@@ -253,8 +252,8 @@ io.matchRepliesToCommands = function (asyncSend, dispatcher) {
});
};
-// __io.controlSocket(socketFile, host, port, password, onError)__.
-// Instantiates and returns a socket to a tor ControlPort at socketFile or
+// __io.controlSocket(ipcFile, host, port, password, onError)__.
+// Instantiates and returns a socket to a tor ControlPort at ipcFile or
// host:port, authenticating with the given password. onError is called with an
// error object as its single argument whenever an error occurs. Example:
//
@@ -269,11 +268,11 @@ io.matchRepliesToCommands = function (asyncSend, dispatcher) {
// socket.removeNotificationCallback(callback);
// // Close the socket permanently
// socket.close();
-io.controlSocket = function (socketFile, host, port, password, onError) {
+io.controlSocket = function (ipcFile, host, port, password, onError) {
// Produce a callback dispatcher for Tor messages.
let mainDispatcher = io.callbackDispatcher(),
// Open the socket and convert format to Tor messages.
- socket = io.asyncSocket(socketFile, host, port,
+ socket = io.asyncSocket(ipcFile, host, port,
io.onDataFromOnLine(
io.onLineFromOnMessage(mainDispatcher.pushMessage)),
onError),
@@ -620,12 +619,12 @@ let tor = {};
// redundant instantiation of control sockets.
tor.controllerCache = {};
-// __tor.controller(socketFile, host, port, password, onError)__.
-// Creates a tor controller at the given socketFile or host and port, with the
+// __tor.controller(ipcFile, host, port, password, onError)__.
+// Creates a tor controller at the given ipcFile or host and port, with the
// given password.
// onError returns asynchronously whenever a connection error occurs.
-tor.controller = function (socketFile, host, port, password, onError) {
- let socket = io.controlSocket(socketFile, host, port, password, onError),
+tor.controller = function (ipcFile, host, port, password, onError) {
+ let socket = io.controlSocket(ipcFile, host, port, password, onError),
isOpen = true;
return { getInfo : key => info.getInfo(socket, key),
getConf : key => info.getConf(socket, key),
@@ -638,11 +637,11 @@ tor.controller = function (socketFile, host, port, password, onError) {
// ## Export
-// __controller(socketFile, host, port, password, onError)__.
+// __controller(ipcFile, host, port, password, onError)__.
// Instantiates and returns a controller object connected to a tor ControlPort
-// on socketFile or at host:port, authenticating with the given password, if
+// on ipcFile or at host:port, authenticating with the given password, if
// the controller doesn't yet exist. Otherwise returns the existing controller
-// to the given socketFile or host:port.
+// to the given ipcFile or host:port.
// onError is called with an error object as its single argument whenever
// an error occurs. Example:
//
@@ -653,13 +652,13 @@ tor.controller = function (socketFile, host, port, password, onError) {
// let replyPromise = c.getInfo("ip-to-country/16.16.16.16");
// // Close the controller permanently
// c.close();
-var controller = function (socketFile, host, port, password, onError) {
- let dest = (socketFile) ? "unix:" + socketFile.path : host + ":" + port,
+var controller = function (ipcFile, host, port, password, onError) {
+ let dest = (ipcFile) ? "unix:" + ipcFile.path : host + ":" + port,
maybeController = tor.controllerCache[dest];
return (tor.controllerCache[dest] =
(maybeController && maybeController.isOpen()) ?
maybeController :
- tor.controller(socketFile, host, port, password, onError));
+ tor.controller(ipcFile, host, port, password, onError));
};
// Export the controller function for external use.
diff --git a/src/modules/utils.js b/src/modules/utils.js
index 514ef51..b303485 100644
--- a/src/modules/utils.js
+++ b/src/modules/utils.js
@@ -74,5 +74,104 @@ var showDialog = function (parent, url, name, features) {
}
};
+// ## Tor control protocol utility functions
+
+let _torControl = {
+ // Unescape Tor Control string aStr (removing surrounding "" and \ escapes).
+ // Based on Vidalia's src/common/stringutil.cpp:string_unescape().
+ // Returns the unescaped string. Throws upon failure.
+ // Within Tor Launcher, the file components/tl-protocol.js also contains a
+ // copy of _strUnescape().
+ _strUnescape: function(aStr)
+ {
+ if (!aStr)
+ return aStr;
+
+ var len = aStr.length;
+ if ((len < 2) || ('"' != aStr.charAt(0)) || ('"' != aStr.charAt(len - 1)))
+ return aStr;
+
+ const kHexRE = /[0-9A-Fa-f]{2}/;
+ const kOctalRE = /[0-7]{3}/;
+ var rv = "";
+ var i = 1;
+ var lastCharIndex = len - 2;
+ while (i <= lastCharIndex)
+ {
+ var c = aStr.charAt(i);
+ if ('\\' == c)
+ {
+ if (++i > lastCharIndex)
+ throw new Error("missing character after \\");
+
+ c = aStr.charAt(i);
+ if ('n' == c)
+ rv += '\n';
+ else if ('r' == c)
+ rv += '\r';
+ else if ('t' == c)
+ rv += '\t';
+ else if ('x' == c)
+ {
+ if ((i + 2) > lastCharIndex)
+ throw new Error("not enough hex characters");
+
+ let s = aStr.substr(i + 1, 2);
+ if (!kHexRE.test(s))
+ throw new Error("invalid hex characters");
+
+ let val = parseInt(s, 16);
+ rv += String.fromCharCode(val);
+ i += 3;
+ }
+ else if (this._isDigit(c))
+ {
+ let s = aStr.substr(i, 3);
+ if ((i + 2) > lastCharIndex)
+ throw new Error("not enough octal characters");
+
+ if (!kOctalRE.test(s))
+ throw new Error("invalid octal characters");
+
+ let val = parseInt(s, 8);
+ rv += String.fromCharCode(val);
+ i += 3;
+ }
+ else // "\\" and others
+ {
+ rv += c;
+ ++i;
+ }
+ }
+ else if ('"' == c)
+ throw new Error("unescaped \" within string");
+ else
+ {
+ rv += c;
+ ++i;
+ }
+ }
+
+ // Convert from UTF-8 to Unicode. TODO: is UTF-8 always used in protocol?
+ return decodeURIComponent(escape(rv));
+ }, // _strUnescape()
+
+ // Within Tor Launcher, the file components/tl-protocol.js also contains a
+ // copy of _isDigit().
+ _isDigit: function(aChar)
+ {
+ const kRE = /^\d$/;
+ return aChar && kRE.test(aChar);
+ },
+}; // _torControl
+
+// __unescapeTorString(str, resultObj)__.
+// Unescape Tor Control string str (removing surrounding "" and \ escapes).
+// Returns the unescaped string. Throws upon failure.
+var unescapeTorString = function(str) {
+ return _torControl._strUnescape(str);
+};
+
// Export utility functions for external use.
-let EXPORTED_SYMBOLS = ["bindPrefAndInit", "getPrefValue", "getEnv", "showDialog"];
+let EXPORTED_SYMBOLS = ["bindPrefAndInit", "getPrefValue", "getEnv",
+ "showDialog", "unescapeTorString"];
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits