[tbb-commits] [tor-launcher/master] Bug 14272: Make Tor Launcher work with Unix Domain Socket option
gk at torproject.org
gk at torproject.org
Thu Sep 1 07:57:22 UTC 2016
commit 8871259c966755233b134a5ddb2b4926539d25c6
Author: Kathy Brade <brade at pearlcrescent.com>
Date: Wed Aug 31 15:26:08 2016 -0400
Bug 14272: Make Tor Launcher work with Unix Domain Socket option
On non-Windows platforms, use a Unix domain socket by default for the
Tor control port. New preferences:
extensions.torlauncher.control_port_use_socket (Boolean)
extensions.torlauncher.control_socket_path (path string)
New environment variable: TOR_CONTROL_SOCKET
When starting tor, always include a ControlPort argument so that
users can use environment variables to switch between the two control
port types.
Add a public TorGetControlSocketFile() function that Torbutton will
use to retrieve the socket file (an nsIFile) when a Unix domain
socket is in use.
Moved the getTorFile() function to our utilities module.
---
src/components/tl-process.js | 253 +++----------------------------------
src/components/tl-protocol.js | 100 ++++++++++++---
src/defaults/preferences/prefs.js | 14 ++-
src/modules/tl-util.jsm | 257 +++++++++++++++++++++++++++++++++++++-
4 files changed, 370 insertions(+), 254 deletions(-)
diff --git a/src/components/tl-process.js b/src/components/tl-process.js
index 8e42feb..c1bbdda 100644
--- a/src/components/tl-process.js
+++ b/src/components/tl-process.js
@@ -31,8 +31,6 @@ TorProcessService.prototype =
{
kContractID : "@torproject.org/torlauncher-process-service;1",
kServiceName : "Tor Launcher Process Service",
- kThunderbirdID: "{3550f703-e582-4d05-9a08-453d09bdfdc6}",
- kInstantbirdID: "{33cb9019-c295-46dd-be21-8c4936574bee}",
kClassID: Components.ID("{FE7B4CAF-BCF4-4848-8BFF-EFA66C9AFDA1}"),
kTorLauncherExtPath: "tor-launcher at torproject.org", // This could vary.
@@ -308,11 +306,6 @@ TorProcessService.prototype =
mProtocolSvc: null,
mTorProcess: null, // nsIProcess
mTorProcessStartTime: null, // JS Date.now()
- // mIsUserDataOutsideOfAppDir is true when TorBrowser-Data is used.
- // (cached; access via this._isUserDataOutsideOfAppDir)
- mIsUserDataOutsideOfAppDir: undefined,
- mAppDir: null, // nsIFile (cached; access via this._appDir)
- mDataDir: null, // nsIFile (cached; access via this._dataDir)
mControlConnTimer: null,
mControlConnDelayMS: 0,
mQuitSoon: false, // Quit was requested by the user; do so soon.
@@ -333,11 +326,14 @@ TorProcessService.prototype =
// Get the Tor data directory first so it is created before we try to
// construct paths to files that will be inside it.
- var dataDir = this._getTorFile("tordatadir", true);
- var exeFile = this._getTorFile("tor", false);
- var torrcFile = this._getTorFile("torrc", true);
- var torrcDefaultsFile = this._getTorFile("torrc-defaults", false);
+ var dataDir = TorLauncherUtil.getTorFile("tordatadir", true);
+ var exeFile = TorLauncherUtil.getTorFile("tor", false);
+ var torrcFile = TorLauncherUtil.getTorFile("torrc", true);
+ var torrcDefaultsFile =
+ TorLauncherUtil.getTorFile("torrc-defaults", false);
var hashedPassword = this.mProtocolSvc.TorGetPassword(true);
+ var controlSocketFile = this.mProtocolSvc.TorGetControlSocketFile();
+ var controlPort = this.mProtocolSvc.TorGetControlPort();
var detailsKey;
if (!exeFile)
@@ -359,7 +355,6 @@ TorProcessService.prototype =
return;
}
-
// The geoip and geoip6 files are in the same directory as torrc-defaults.
var geoipFile = torrcDefaultsFile.clone();
geoipFile.leafName = "geoip";
@@ -384,6 +379,19 @@ TorProcessService.prototype =
args.push("HashedControlPassword");
args.push(hashedPassword);
+ // Include a ControlPort argument to support switching between
+ // a TCP port and a Unix domain socket.
+ let controlPortArg;
+ if (controlSocketFile)
+ controlPortArg = "unix:" + controlSocketFile.path;
+ else if (controlPort)
+ controlPortArg = "" + controlPort;
+ if (controlPortArg)
+ {
+ args.push("ControlPort");
+ args.push(controlPortArg);
+ }
+
var pid = this._getpid();
if (0 != pid)
{
@@ -692,227 +700,6 @@ TorProcessService.prototype =
return argsArray;
},
- // Returns an nsIFile.
- // If aCreate is true and the file doesn't exist, it is created.
- _getTorFile: function(aTorFileType, aCreate)
- {
- if (!aTorFileType)
- return null;
-
- let isRelativePath = true;
- let isUserData = (aTorFileType != "tor") &&
- (aTorFileType != "torrc-defaults");
- let prefName = "extensions.torlauncher." + aTorFileType + "_path";
- let path = TorLauncherUtil.getCharPref(prefName);
- if (path)
- {
- let re = (TorLauncherUtil.isWindows) ? /^[A-Za-z]:\\/ : /^\//;
- isRelativePath = !re.test(path);
- }
- else
- {
- // Get default path.
- if (this._isUserDataOutsideOfAppDir)
- {
- // This block is used for the TorBrowser-Data/ case.
- if (TorLauncherUtil.isWindows)
- {
- if ("tor" == aTorFileType)
- path = "TorBrowser\\Tor\\tor.exe";
- else if ("torrc-defaults" == aTorFileType)
- path = "TorBrowser\\Tor\\torrc-defaults";
- else if ("torrc" == aTorFileType)
- path = "Tor\\torrc";
- else if ("tordatadir" == aTorFileType)
- path = "Tor";
- }
- else if (TorLauncherUtil.isMac)
- {
- if ("tor" == aTorFileType)
- path = "Contents/Resources/TorBrowser/Tor/tor";
- else if ("torrc-defaults" == aTorFileType)
- path = "Contents/Resources/TorBrowser/Tor/torrc-defaults";
- else if ("torrc" == aTorFileType)
- path = "Tor/torrc";
- else if ("tordatadir" == aTorFileType)
- path = "Tor";
- }
- else // Linux and others.
- {
- if ("tor" == aTorFileType)
- path = "TorBrowser/Tor/tor";
- else if ("torrc-defaults" == aTorFileType)
- path = "TorBrowser/Tor/torrc-defaults";
- else if ("torrc" == aTorFileType)
- path = "Tor/torrc";
- else if ("tordatadir" == aTorFileType)
- path = "Tor";
- }
- }
- else if (TorLauncherUtil.isWindows)
- {
- // This block is used for the non-TorBrowser-Data/ case.
- if ("tor" == aTorFileType)
- path = "Tor\\tor.exe";
- else if ("torrc-defaults" == aTorFileType)
- path = "Data\\Tor\\torrc-defaults";
- else if ("torrc" == aTorFileType)
- path = "Data\\Tor\\torrc";
- else if ("tordatadir" == aTorFileType)
- path = "Data\\Tor";
- }
- else // Linux, Mac OS and others.
- {
- // This block is also used for the non-TorBrowser-Data/ case.
- if ("tor" == aTorFileType)
- path = "Tor/tor";
- else if ("torrc-defaults" == aTorFileType)
- path = "Data/Tor/torrc-defaults";
- else if ("torrc" == aTorFileType)
- path = "Data/Tor/torrc";
- else if ("tordatadir" == aTorFileType)
- path = "Data/Tor";
- }
- }
-
- if (!path)
- return null;
-
- try
- {
- let f;
- if (isRelativePath)
- {
- // Turn 'path' into an absolute path.
- if (this._isUserDataOutsideOfAppDir)
- {
- let baseDir = isUserData ? this._dataDir : this._appDir;
- f = baseDir.clone();
- }
- else
- {
- f = this._appDir.clone();
- f.append("TorBrowser");
- }
- f.appendRelativePath(path);
- }
- else
- {
- f = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
- f.initWithPath(path);
- }
-
- if (!f.exists() && aCreate)
- {
- try
- {
- if ("tordatadir" == aTorFileType)
- f.create(f.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
- else
- f.create(f.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
- }
- catch (e)
- {
- TorLauncherLogger.safelog(4, "unable to create " + f.path + ": ", e);
- return null;
- }
- }
-
- if (f.exists())
- {
- try { f.normalize(); } catch(e) {}
-
- return f;
- }
-
- TorLauncherLogger.log(4, aTorFileType + " file not found: " + f.path);
- }
- catch(e)
- {
- TorLauncherLogger.safelog(4, "_getTorFile " + aTorFileType +
- " failed for " + path + ": ", e);
- }
-
- return null; // File not found or error (logged above).
- }, // _getTorFile()
-
- get _isUserDataOutsideOfAppDir()
- {
- if (this.mIsUserDataOutsideOfAppDir == undefined)
- {
- // Determine if we are using a "side-by-side" data model by checking
- // whether the user profile is outside of the app directory.
- try
- {
- let ds = Cc["@mozilla.org/file/directory_service;1"]
- .getService(Ci.nsIProperties);
- let profDir = ds.get("ProfD", Ci.nsIFile);
- this.mIsUserDataOutsideOfAppDir = !this._appDir.contains(profDir);
- }
- catch (e)
- {
- this.mIsUserDataOutsideOfAppDir = false;
- }
- }
-
- return this.mIsUserDataOutsideOfAppDir;
- }, // get _isUserDataOutsideOfAppDir
-
- // Returns an nsIFile that points to the application directory.
- // May throw.
- get _appDir()
- {
- if (!this.mAppDir)
- {
- let topDir = Cc["@mozilla.org/file/directory_service;1"]
- .getService(Ci.nsIProperties).get("CurProcD", Ci.nsIFile);
- let appInfo = Cc["@mozilla.org/xre/app-info;1"]
- .getService(Ci.nsIXULAppInfo);
- // On Linux and Windows, we want to return the Browser/ directory.
- // Because topDir ("CurProcD") points to Browser/browser on those
- // platforms, we need to go up one level.
- // On Mac OS, we want to return the TorBrowser.app/ directory.
- // Because topDir points to Contents/Resources/browser on Mac OS,
- // we need to go up 3 levels.
- let tbbBrowserDepth = (TorLauncherUtil.isMac) ? 3 : 1;
- if ((appInfo.ID == this.kThunderbirdID) ||
- (appInfo.ID == this.kInstantbirdID))
- {
- // On Thunderbird/Instantbird, the topDir is the root dir and not
- // browser/, so we need to iterate one level less than Firefox.
- --tbbBrowserDepth;
- }
-
- while (tbbBrowserDepth > 0)
- {
- let didRemove = (topDir.leafName != ".");
- topDir = topDir.parent;
- if (didRemove)
- tbbBrowserDepth--;
- }
-
- this.mAppDir = topDir;
- }
-
- return this.mAppDir;
- }, // get _appDir
-
- // Returns an nsIFile that points to the TorBrowser-Data/ directory.
- // This function is only used when this._isUserDataOutsideOfAppDir == true.
- // May throw.
- get _dataDir()
- {
- if (!this.mDataDir)
- {
- let ds = Cc["@mozilla.org/file/directory_service;1"]
- .getService(Ci.nsIProperties);
- let profDir = ds.get("ProfD", Ci.nsIFile);
- this.mDataDir = profDir.parent.parent;
- }
-
- return this.mDataDir;
- }, // get _dataDir
-
_getpid: function()
{
// Use nsIXULRuntime.processID if it is available.
diff --git a/src/components/tl-protocol.js b/src/components/tl-protocol.js
index fdc2394..d394b53 100644
--- a/src/components/tl-protocol.js
+++ b/src/components/tl-protocol.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, The Tor Project, Inc.
+// Copyright (c) 2016, The Tor Project, Inc.
// See LICENSE for licensing information.
// TODO: Some code came from torbutton.js (pull in copyright and license?)
//
@@ -17,6 +17,8 @@ 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");
function TorProtocolService()
@@ -31,23 +33,44 @@ function TorProtocolService()
try
{
- var env = Cc["@mozilla.org/process/environment;1"]
+ let isWindows = TorLauncherUtil.isWindows;
+ let env = Cc["@mozilla.org/process/environment;1"]
.getService(Ci.nsIEnvironment);
-
- if (env.exists("TOR_CONTROL_HOST"))
- this.mControlHost = env.get("TOR_CONTROL_HOST");
- else
+ // Determine how Tor Launcher will connect to the Tor control port.
+ // Environment variables get top priority followed by preferences.
+ if (!isWindows && env.exists("TOR_CONTROL_SOCKET"))
{
- this.mControlHost = TorLauncherUtil.getCharPref(
- "extensions.torlauncher.control_host", "127.0.0.1");
+ let socketPath = env.get("TOR_CONTROL_SOCKET");
+ this.mControlSocketFile = new FileUtils.File(socketPath);
}
-
- if (env.exists("TOR_CONTROL_PORT"))
- this.mControlPort = parseInt(env.get("TOR_CONTROL_PORT"), 10);
else
{
- this.mControlPort = TorLauncherUtil.getIntPref(
+ // Check for TCP host and port environment variables.
+ if (env.exists("TOR_CONTROL_HOST"))
+ this.mControlHost = env.get("TOR_CONTROL_HOST");
+ if (env.exists("TOR_CONTROL_PORT"))
+ this.mControlPort = parseInt(env.get("TOR_CONTROL_PORT"), 10);
+
+ let useSocket = !isWindows && TorLauncherUtil.getBoolPref(
+ "extensions.torlauncher.control_port_use_socket", true);
+ if (!this.mControlHost && !this.mControlPort && useSocket)
+ {
+ this.mControlSocketFile = TorLauncherUtil.getTorFile("control_socket",
+ false);
+ }
+ else
+ {
+ if (!this.mControlHost)
+ {
+ this.mControlHost = TorLauncherUtil.getCharPref(
+ "extensions.torlauncher.control_host", "127.0.0.1");
+ }
+ if (!this.mControlPort)
+ {
+ this.mControlPort = TorLauncherUtil.getIntPref(
"extensions.torlauncher.control_port", 9151);
+ }
+ }
}
// Populate mControlPassword so it is available when starting tor.
@@ -141,6 +164,19 @@ TorProtocolService.prototype =
kCmdStatusOK: 250,
kCmdStatusEventNotification: 650,
+ TorGetControlSocketFile: function()
+ {
+ if (!this.mControlSocketFile)
+ return undefined;
+
+ return this.mControlSocketFile.clone();
+ },
+
+ TorGetControlPort: function()
+ {
+ return this.mControlPort;
+ },
+
// Returns Tor password string or null if an error occurs.
TorGetPassword: function(aPleaseHash)
{
@@ -512,6 +548,7 @@ TorProtocolService.prototype =
mConsoleSvc: null,
mControlPort: null,
mControlHost: null,
+ mControlSocketFile: null, // An nsIFile if using a UNIX domain socket.
mControlPassword: null, // JS string that contains hex-encoded password.
mControlConnection: null, // This is cached and reused.
mEventMonitorConnection: null,
@@ -560,12 +597,43 @@ TorProtocolService.prototype =
var conn;
try
{
- var sts = Cc["@mozilla.org/network/socket-transport-service;1"]
+ let sts = Cc["@mozilla.org/network/socket-transport-service;1"]
.getService(Ci.nsISocketTransportService);
- TorLauncherLogger.log(2, "Opening control connection to " +
+ let socket;
+ if (this.mControlSocketFile)
+ {
+ let exists = this.mControlSocketFile.exists();
+ if (!exists)
+ {
+ TorLauncherLogger.log(5, "Control port socket does not exist: " +
+ this.mControlSocketFile.path);
+ }
+ else
+ {
+ let isSpecial = this.mControlSocketFile.isSpecial();
+ if (!isSpecial)
+ {
+ TorLauncherLogger.log(5, "Control port socket is not a socket: " +
+ this.mControlSocketFile.path);
+ }
+ else
+ {
+ TorLauncherLogger.log(2, "Opening control connection to socket " +
+ this.mControlSocketFile.path);
+ socket = sts.createUnixDomainTransport(this.mControlSocketFile);
+ }
+ }
+ }
+ else
+ {
+ TorLauncherLogger.log(2, "Opening control connection to " +
this.mControlHost + ":" + this.mControlPort);
- var socket = sts.createTransport(null, 0, this.mControlHost,
- this.mControlPort, null);
+ socket = sts.createTransport(null, 0, 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
diff --git a/src/defaults/preferences/prefs.js b/src/defaults/preferences/prefs.js
index 2c0a95e..500fe2f 100644
--- a/src/defaults/preferences/prefs.js
+++ b/src/defaults/preferences/prefs.js
@@ -2,16 +2,24 @@
pref("intl.locale.matchOS", true);
pref("extensions.torlauncher.prompt_for_locale", true);
+pref("extensions.torlauncher.start_tor", true);
+pref("extensions.torlauncher.prompt_at_startup", true);
+
pref("extensions.torlauncher.loglevel", 4); // 1=verbose, 2=debug, 3=info, 4=note, 5=warn
pref("extensions.torlauncher.logmethod", 1); // 0=stdout, 1=errorconsole, 2=debuglog
pref("extensions.torlauncher.max_tor_log_entries", 1000);
+// By default, a Unix domain socket at a default location is used for
+// the Tor control port.
+// Change control_port_use_socket to false to use a TCP connection
+// instead, as defined by control_host and control_port.
+// Modify control_socket_path to override the default socket location. If a
+// relative path is used, it is handled like torrc_path (see below).
+pref("extensions.torlauncher.control_port_use_socket", true);
+pref("extensions.torlauncher.control_socket_path", "");
pref("extensions.torlauncher.control_host", "127.0.0.1");
pref("extensions.torlauncher.control_port", 9151);
-pref("extensions.torlauncher.start_tor", true);
-pref("extensions.torlauncher.prompt_at_startup", true);
-
// The tor_path is relative to the application directory. On Linux and
// Windows this is the Browser/ directory that contains the firefox
// executables, and on Mac OS it is the TorBrowser.app directory.
diff --git a/src/modules/tl-util.jsm b/src/modules/tl-util.jsm
index 7f93f39..992ef5b 100644
--- a/src/modules/tl-util.jsm
+++ b/src/modules/tl-util.jsm
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, The Tor Project, Inc.
+// Copyright (c) 2016, The Tor Project, Inc.
// See LICENSE for licensing information.
//
// vim: set sw=2 sts=2 ts=8 et syntax=javascript:
@@ -11,14 +11,19 @@ let EXPORTED_SYMBOLS = [ "TorLauncherUtil" ];
const Cc = Components.classes;
const Ci = Components.interfaces;
+const Cu = Components.utils;
const kPropBundleURI = "chrome://torlauncher/locale/torlauncher.properties";
const kPropNamePrefix = "torlauncher.";
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "TorLauncherLogger",
+ "resource://torlauncher/modules/tl-logger.jsm");
+
let TorLauncherUtil = // Public
{
get isMac()
{
- return ("Darwin" == TLUtilInternal._OS);
+ return TLUtilInternal._isMac;
},
get isWindows()
@@ -381,6 +386,163 @@ let TorLauncherUtil = // Public
return undefined;
},
+
+ // Returns an nsIFile.
+ // If aTorFileType is "control_socket", aCreate is ignored and there is
+ // no requirement that the socket exist.
+ // For all other file types, null is returned if the file does not exist
+ // and it cannot be created (it will be created if aCreate is true).
+ getTorFile: function(aTorFileType, aCreate)
+ {
+ if (!aTorFileType)
+ return null;
+
+ let isRelativePath = true;
+ let isUserData = (aTorFileType != "tor") &&
+ (aTorFileType != "torrc-defaults");
+ let isControlSocket = ("control_socket" == aTorFileType);
+ let prefName = "extensions.torlauncher." + aTorFileType + "_path";
+ let path = this.getCharPref(prefName);
+ if (path)
+ {
+ let re = (this.isWindows) ? /^[A-Za-z]:\\/ : /^\//;
+ isRelativePath = !re.test(path);
+ }
+ else
+ {
+ // Get default path.
+ if (TLUtilInternal._isUserDataOutsideOfAppDir)
+ {
+ // This block is used for the TorBrowser-Data/ case.
+ if (this.isWindows)
+ {
+ if ("tor" == aTorFileType)
+ path = "TorBrowser\\Tor\\tor.exe";
+ else if ("torrc-defaults" == aTorFileType)
+ path = "TorBrowser\\Tor\\torrc-defaults";
+ else if ("torrc" == aTorFileType)
+ path = "Tor\\torrc";
+ else if ("tordatadir" == aTorFileType)
+ path = "Tor";
+ }
+ else if (this.isMac)
+ {
+ if ("tor" == aTorFileType)
+ path = "Contents/Resources/TorBrowser/Tor/tor";
+ else if ("torrc-defaults" == aTorFileType)
+ path = "Contents/Resources/TorBrowser/Tor/torrc-defaults";
+ else if ("torrc" == aTorFileType)
+ path = "Tor/torrc";
+ else if ("tordatadir" == aTorFileType)
+ path = "Tor";
+ else if (isControlSocket)
+ path = "Tor/control.socket";
+ }
+ else // Linux and others.
+ {
+ if ("tor" == aTorFileType)
+ path = "TorBrowser/Tor/tor";
+ else if ("torrc-defaults" == aTorFileType)
+ path = "TorBrowser/Tor/torrc-defaults";
+ else if ("torrc" == aTorFileType)
+ path = "Tor/torrc";
+ else if ("tordatadir" == aTorFileType)
+ path = "Tor";
+ else if (isControlSocket)
+ path = "Tor/control.socket";
+ }
+ }
+ else if (this.isWindows)
+ {
+ // This block is used for the non-TorBrowser-Data/ case.
+ if ("tor" == aTorFileType)
+ path = "Tor\\tor.exe";
+ else if ("torrc-defaults" == aTorFileType)
+ path = "Data\\Tor\\torrc-defaults";
+ else if ("torrc" == aTorFileType)
+ path = "Data\\Tor\\torrc";
+ else if ("tordatadir" == aTorFileType)
+ path = "Data\\Tor";
+ }
+ else // Linux, Mac OS and others.
+ {
+ // This block is also used for the non-TorBrowser-Data/ case.
+ if ("tor" == aTorFileType)
+ path = "Tor/tor";
+ else if ("torrc-defaults" == aTorFileType)
+ path = "Data/Tor/torrc-defaults";
+ else if ("torrc" == aTorFileType)
+ path = "Data/Tor/torrc";
+ else if ("tordatadir" == aTorFileType)
+ path = "Data/Tor";
+ else if (isControlSocket)
+ path = "Data/Tor/control.socket";
+ }
+ }
+
+ if (!path)
+ return null;
+
+ try
+ {
+ let f;
+ if (isRelativePath)
+ {
+ // Turn 'path' into an absolute path.
+ if (TLUtilInternal._isUserDataOutsideOfAppDir)
+ {
+ let baseDir = isUserData ? TLUtilInternal._dataDir
+ : TLUtilInternal._appDir;
+ f = baseDir.clone();
+ }
+ else
+ {
+ f = TLUtilInternal._appDir.clone();
+ f.append("TorBrowser");
+ }
+ f.appendRelativePath(path);
+ }
+ else
+ {
+ f = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
+ f.initWithPath(path);
+ }
+
+ if (!f.exists() && !isControlSocket && aCreate)
+ {
+ try
+ {
+ if ("tordatadir" == aTorFileType)
+ f.create(f.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
+ else
+ f.create(f.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE);
+ }
+ catch (e)
+ {
+ TorLauncherLogger.safelog(4, "unable to create " + f.path + ": ", e);
+ return null;
+ }
+ }
+
+ // If the file exists or the control socket was requested, normalize
+ // the path and return a file object. The control socket will be
+ // created by tor.
+ if (f.exists() || isControlSocket)
+ {
+ try { f.normalize(); } catch(e) {}
+ return f;
+ }
+
+ TorLauncherLogger.log(4, aTorFileType + " file not found: " + f.path);
+ }
+ catch(e)
+ {
+ TorLauncherLogger.safelog(4, "getTorFile " + aTorFileType +
+ " failed for " + path + ": ", e);
+ }
+
+ return null; // File not found or error (logged above).
+ }, // getTorFile()
};
@@ -389,9 +551,17 @@ Object.freeze(TorLauncherUtil);
let TLUtilInternal = // Private
{
+ kThunderbirdID: "{3550f703-e582-4d05-9a08-453d09bdfdc6}",
+ kInstantbirdID: "{33cb9019-c295-46dd-be21-8c4936574bee}",
+
mPrefsSvc : null,
mStringBundle : null,
mOS : "",
+ // mIsUserDataOutsideOfAppDir is true when TorBrowser-Data is used.
+ mIsUserDataOutsideOfAppDir: undefined, // Boolean (cached; access via
+ // this._isUserDataOutsideOfAppDir)
+ mAppDir: null, // nsIFile (cached; access via this._appDir)
+ mDataDir: null, // nsIFile (cached; access via this._dataDir)
_init: function()
{
@@ -421,6 +591,89 @@ let TLUtilInternal = // Private
return this.mOS;
},
+
+ get _isMac()
+ {
+ return ("Darwin" == this._OS);
+ },
+
+ get _isUserDataOutsideOfAppDir()
+ {
+ if (this.mIsUserDataOutsideOfAppDir == undefined)
+ {
+ // Determine if we are using a "side-by-side" data model by checking
+ // whether the user profile is outside of the app directory.
+ try
+ {
+ let ds = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIProperties);
+ let profDir = ds.get("ProfD", Ci.nsIFile);
+ this.mIsUserDataOutsideOfAppDir = !this._appDir.contains(profDir);
+ }
+ catch (e)
+ {
+ this.mIsUserDataOutsideOfAppDir = false;
+ }
+ }
+
+ return this.mIsUserDataOutsideOfAppDir;
+ }, // get _isUserDataOutsideOfAppDir
+
+ // Returns an nsIFile that points to the application directory.
+ // May throw.
+ get _appDir()
+ {
+ if (!this.mAppDir)
+ {
+ let topDir = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIProperties).get("CurProcD", Ci.nsIFile);
+ let appInfo = Cc["@mozilla.org/xre/app-info;1"]
+ .getService(Ci.nsIXULAppInfo);
+ // On Linux and Windows, we want to return the Browser/ directory.
+ // Because topDir ("CurProcD") points to Browser/browser on those
+ // platforms, we need to go up one level.
+ // On Mac OS, we want to return the TorBrowser.app/ directory.
+ // Because topDir points to Contents/Resources/browser on Mac OS,
+ // we need to go up 3 levels.
+ let tbbBrowserDepth = (this._isMac) ? 3 : 1;
+ if ((appInfo.ID == this.kThunderbirdID) ||
+ (appInfo.ID == this.kInstantbirdID))
+ {
+ // On Thunderbird/Instantbird, the topDir is the root dir and not
+ // browser/, so we need to iterate one level less than Firefox.
+ --tbbBrowserDepth;
+ }
+
+ while (tbbBrowserDepth > 0)
+ {
+ let didRemove = (topDir.leafName != ".");
+ topDir = topDir.parent;
+ if (didRemove)
+ tbbBrowserDepth--;
+ }
+
+ this.mAppDir = topDir;
+ }
+
+ return this.mAppDir;
+ }, // get _appDir
+
+ // Returns an nsIFile that points to the TorBrowser-Data/ directory.
+ // This function is only used when this._isUserDataOutsideOfAppDir == true.
+ // May throw.
+ get _dataDir()
+ {
+ if (!this.mDataDir)
+ {
+ let ds = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIProperties);
+ let profDir = ds.get("ProfD", Ci.nsIFile);
+ this.mDataDir = profDir.parent.parent;
+ }
+
+ return this.mDataDir;
+ }, // get _dataDir
+
};
More information about the tbb-commits
mailing list