[tor-commits] [tor-launcher/master] Bug 13252 - Do not store data in the app bundle

gk at torproject.org gk at torproject.org
Sat Mar 19 20:13:43 UTC 2016


commit 64d3139e72587372223d0795ca715991d7423adb
Author: Kathy Brade <brade at pearlcrescent.com>
Date:   Mon Mar 14 11:15:43 2016 -0400

    Bug 13252 - Do not store data in the app bundle
    
    Add support for a "side-by-side" directory structure where
    the writable data is stored in the TorBrowser-Data/ directory
    next to the application directory.
---
 src/chrome/locale/en/torlauncher.properties |   6 +-
 src/components/tl-process.js                | 232 +++++++++++++++++++++-------
 src/defaults/preferences/prefs.js           |   9 +-
 3 files changed, 184 insertions(+), 63 deletions(-)

diff --git a/src/chrome/locale/en/torlauncher.properties b/src/chrome/locale/en/torlauncher.properties
index 02be756..0ef4437 100644
--- a/src/chrome/locale/en/torlauncher.properties
+++ b/src/chrome/locale/en/torlauncher.properties
@@ -1,4 +1,4 @@
-### Copyright (c) 2014, The Tor Project, Inc.
+### Copyright (c) 2016, The Tor Project, Inc.
 ### See LICENSE for licensing information.
 
 torlauncher.error_title=Tor Launcher
@@ -13,8 +13,8 @@ torlauncher.tor_bootstrap_failed_details=%1$S failed (%2$S).
 
 torlauncher.unable_to_start_tor=Unable to start Tor.\n\n%S
 torlauncher.tor_missing=The Tor executable is missing.
-torlauncher.torrc_missing=The torrc file is missing.
-torlauncher.datadir_missing=The Tor data directory does not exist.
+torlauncher.torrc_missing=The torrc file is missing and could not be created.
+torlauncher.datadir_missing=The Tor data directory does not exist and could not be created.
 torlauncher.password_hash_missing=Failed to get hashed password.
 
 torlauncher.failed_to_get_settings=Unable to retrieve Tor settings.\n\n%S
diff --git a/src/components/tl-process.js b/src/components/tl-process.js
index bb327dc..ccbee12 100644
--- a/src/components/tl-process.js
+++ b/src/components/tl-process.js
@@ -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:
@@ -16,6 +16,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 TorProcessService()
 {
@@ -287,7 +289,11 @@ TorProcessService.prototype =
   mProtocolSvc: null,
   mTorProcess: null,    // nsIProcess
   mTorProcessStartTime: null, // JS Date.now()
-  mTorFileBaseDir: null,      // nsIFile (cached)
+  // 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.
@@ -305,10 +311,13 @@ TorProcessService.prototype =
       // Ideally, we would cd to the Firefox application directory before
       // starting tor (but we don't know how to do that).  Instead, we
       // rely on the TBB launcher to start Firefox from the right place.
-      var exeFile = this._getTorFile("tor");
-      var torrcFile = this._getTorFile("torrc");
-      var torrcDefaultsFile = this._getTorFile("torrc-defaults");
-      var dataDir = this._getTorFile("tordatadir");
+
+      // 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 hashedPassword = this.mProtocolSvc.TorGetPassword(true);
 
       var detailsKey;
@@ -331,11 +340,13 @@ TorProcessService.prototype =
         return;
       }
 
-      var geoipFile = dataDir.clone();
-      geoipFile.append("geoip");
 
-      var geoip6File = dataDir.clone();
-      geoip6File.append("geoip6");
+      // The geoip and geoip6 files are in the same directory as torrc-defaults.
+      var geoipFile = torrcDefaultsFile.clone();
+      geoipFile.leafName = "geoip";
+
+      var geoip6File = torrcDefaultsFile.clone();
+      geoip6File.leafName = "geoip6";
 
       var args = [];
       if (torrcDefaultsFile)
@@ -663,25 +674,65 @@ TorProcessService.prototype =
   },
 
   // Returns an nsIFile.
-  // If file doesn't exist, null is returned.
-  _getTorFile: function(aTorFileType)
+  // If aCreate is true and the file doesn't exist, it is created.
+  _getTorFile: function(aTorFileType, aCreate)
   {
     if (!aTorFileType)
       return null;
 
-    var isRelativePath = true;
-    var prefName = "extensions.torlauncher." + aTorFileType + "_path";
-    var path = TorLauncherUtil.getCharPref(prefName);
+    let isRelativePath = true;
+    let isUserData = (aTorFileType != "tor") &&
+                     (aTorFileType != "torrc-defaults");
+    let prefName = "extensions.torlauncher." + aTorFileType + "_path";
+    let path = TorLauncherUtil.getCharPref(prefName);
     if (path)
     {
-      var re = (TorLauncherUtil.isWindows) ?  /^[A-Za-z]:\\/ : /^\//;
+      let re = (TorLauncherUtil.isWindows) ?  /^[A-Za-z]:\\/ : /^\//;
       isRelativePath = !re.test(path);
     }
     else
     {
       // Get default path.
-      if (TorLauncherUtil.isWindows)
+      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)
@@ -693,6 +744,7 @@ TorProcessService.prototype =
       }
       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)
@@ -700,7 +752,7 @@ TorProcessService.prototype =
         else if ("torrc" == aTorFileType)
           path = "Data/Tor/torrc";
         else if ("tordatadir" == aTorFileType)
-          path = "Data/Tor/";
+          path = "Data/Tor";
       }
     }
 
@@ -709,51 +761,20 @@ TorProcessService.prototype =
 
     try
     {
-      var f;
+      let f;
       if (isRelativePath)
       {
-        // Turn into an absolute path.
-        if (!this.mTorFileBaseDir)
+        // Turn 'path' into an absolute path.
+        if (this._isUserDataOutsideOfAppDir)
         {
-          var topDir;
-          var appInfo = Cc["@mozilla.org/xre/app-info;1"]
-                          .getService(Ci.nsIXULAppInfo);
-          if (appInfo.ID == this.kThunderbirdID || appInfo.ID == this.kInstantbirdID)
-          {
-            topDir = Cc["@mozilla.org/file/directory_service;1"]
-                       .getService(Ci.nsIProperties).get("CurProcD", Ci.nsIFile);
-            topDir.append("extensions");
-            topDir.append(this.kTorLauncherExtPath);
-          }
-          else
-          {
-            // For Firefox, paths are relative to the top of the TBB install.
-            var tbbBrowserDepth = 0; // Windows and Linux
-            if (TorLauncherUtil.isAppVersionAtLeast("21.0"))
-            {
-              // In FF21+, CurProcD is the "browser" directory that is next to
-              // the firefox binary, e.g., <TorFileBaseDir>/Browser/browser
-              ++tbbBrowserDepth;
-            }
-            if (TorLauncherUtil.isMac)
-              tbbBrowserDepth += 2;
-
-            topDir = Cc["@mozilla.org/file/directory_service;1"]
-                    .getService(Ci.nsIProperties).get("CurProcD", Ci.nsIFile);
-            while (tbbBrowserDepth > 0)
-            {
-              var didRemove = (topDir.leafName != ".");
-              topDir = topDir.parent;
-              if (didRemove)
-                tbbBrowserDepth--;
-            }
-          }
-
-          topDir.append("TorBrowser");
-          this.mTorFileBaseDir = topDir;
+          let baseDir = isUserData ? this._dataDir : this._appDir;
+          f = baseDir.clone();
+        }
+        else
+        {
+          f = this._appDir.clone();
+          f.append("TorBrowser");
         }
-
-        f = this.mTorFileBaseDir.clone();
         f.appendRelativePath(path);
       }
       else
@@ -762,6 +783,22 @@ TorProcessService.prototype =
         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) {}
@@ -780,6 +817,83 @@ TorProcessService.prototype =
     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
+      // for the existence of the TorBrowser-Data/ directory.
+      try
+      {
+        let f = this._appDir.parent;
+        f.append("TorBrowser-Data");
+        this.mIsUserDataOutsideOfAppDir = f.exists() && f.isDirectory();
+      }
+      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);
+      if ((appInfo.ID == this.kThunderbirdID) ||
+          (appInfo.ID == this.kInstantbirdID))
+      {
+        // For TorBirdy and Tor Messenger the Tor Launcher extension
+        // directory is returned.
+        topDir.append("extensions");
+        topDir.append(this.kTorLauncherExtPath);
+      }
+      else  // Tor Browser
+      {
+        // 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;
+        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.
+  // May throw.
+  get _dataDir()
+  {
+    if (!this.mDataDir)
+    {
+      let f = this._appDir.parent.clone();
+      f.append("TorBrowser-Data");
+      this.mDataDir = f;
+    }
+
+    return this.mDataDir;
+  }, // get _dataDir
+
   _getpid: function()
   {
     // Use nsIXULRuntime.processID if it is available.
diff --git a/src/defaults/preferences/prefs.js b/src/defaults/preferences/prefs.js
index 3057f6a..2c0a95e 100644
--- a/src/defaults/preferences/prefs.js
+++ b/src/defaults/preferences/prefs.js
@@ -12,8 +12,15 @@ pref("extensions.torlauncher.control_port", 9151);
 pref("extensions.torlauncher.start_tor", true);
 pref("extensions.torlauncher.prompt_at_startup", true);
 
-// All path prefs. are relative to the firefox executable's directory
+// 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.
 pref("extensions.torlauncher.tor_path", "");
+
+// The torrc_path and tordatadir_path are relative to the data directory,
+// which is TorBrowser-Data/ if it exists as a sibling of the application
+// directory. If TorBrowser-Data/ does not exist, these paths are relative
+// to the TorBrowser/ directory within the application directory.
 pref("extensions.torlauncher.torrc_path", "");
 pref("extensions.torlauncher.tordatadir_path", "");
 



More information about the tor-commits mailing list