[Pkg-privacy-commits] [onionshare] 127/256: Connecting to Tor in bundled mode now creates a temporary tor data dir, starts a new tor process, and connects to it. Also, refactored Settings dialog to allow Linux to use bundled tor as well

Ulrike Uhlig ulrike at moszumanska.debian.org
Fri May 26 12:53:26 UTC 2017


This is an automated email from the git hooks/post-receive script.

ulrike pushed a commit to branch master
in repository onionshare.

commit 169be518eb9140cfdffa611afa82eb5592cf9873
Author: Micah Lee <micah at micahflee.com>
Date:   Thu Apr 13 22:22:34 2017 -0700

    Connecting to Tor in bundled mode now creates a temporary tor data dir, starts a new tor process, and connects to it. Also, refactored Settings dialog to allow Linux to use bundled tor as well
---
 onionshare/onion.py               | 88 ++++++++++++++++++++++++++++++++-------
 onionshare_gui/settings_dialog.py | 29 ++++---------
 share/locale/en.json              |  3 +-
 share/torrc_template              |  9 ++++
 4 files changed, 92 insertions(+), 37 deletions(-)

diff --git a/onionshare/onion.py b/onionshare/onion.py
index ccfdd4b..1018153 100644
--- a/onionshare/onion.py
+++ b/onionshare/onion.py
@@ -21,7 +21,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 from stem.control import Controller
 from stem import ProtocolError
 from stem.connection import MissingPassword, UnreadableCookieFile, AuthenticationFailure
-import os, sys, tempfile, shutil, urllib, platform
+import os, sys, tempfile, shutil, urllib, platform, subprocess, time, shlex
 
 from . import socks
 from . import helpers, strings
@@ -103,6 +103,8 @@ class Onion(object):
         self.stealth = stealth
         self.service_id = None
 
+        system = platform.system()
+
         # Either use settings that are passed in, or load them from disk
         if settings:
             self.settings = settings
@@ -110,21 +112,73 @@ class Onion(object):
             self.settings = Settings()
             self.settings.load()
 
+        # Is bundled tor supported?
+        if (system == 'Windows' or system == 'Darwin') and getattr(sys, 'onionshare_dev_mode', False):
+            bundle_tor_supported = False
+        else:
+            bundle_tor_supported = True
+
+        # Set the path of the tor binary, for bundled tor
+        if system == 'Linux':
+            self.tor_path = '/usr/bin/tor'
+            self.tor_geo_ip_file_path = '/usr/share/tor/geoip'
+            self.tor_geo_ipv6_file_path = '/usr/share/tor/geoip6'
+        elif system == 'Windows':
+            # TODO: implement
+            pass
+        elif system == 'Darwin':
+            # TODO: implement
+            pass
+
+        # The tor process
+        self.tor_p = None
+
         # Try to connect to Tor
         self.c = None
 
         if self.settings.get('connection_type') == 'bundled':
-            dev_mode = getattr(sys, 'onionshare_dev_mode', False)
-            p = platform.system()
-
-            if (p != 'Windows' and p != 'Darwin') or dev_mode:
+            if not bundle_tor_supported:
                 raise BundledTorNotSupported(strings._('settings_error_bundled_tor_not_supported'))
 
-            # TODO: actually implement bundled Tor
-
-        if self.settings.get('connection_type') == 'automatic':
+            # Create a torrc for this session
+            self.tor_data_directory = tempfile.TemporaryDirectory()
+            self.tor_control_socket = os.path.join(self.tor_data_directory.name, 'control_socket')
+            self.tor_cookie_auth_file = os.path.join(self.tor_data_directory.name, 'cookie')
+            self.tor_socks_port_file = os.path.join(self.tor_data_directory.name, 'socks_socket')
+            self.tor_socks_port = 'unix:{}'.format(self.tor_socks_port_file)
+            self.tor_torrc = os.path.join(self.tor_data_directory.name, 'torrc')
+            torrc_template = open(helpers.get_resource_path('torrc_template')).read()
+            torrc_template = torrc_template.replace('{{data_directory}}',   self.tor_data_directory.name)
+            torrc_template = torrc_template.replace('{{control_socket}}',   self.tor_control_socket)
+            torrc_template = torrc_template.replace('{{cookie_auth_file}}', self.tor_cookie_auth_file)
+            torrc_template = torrc_template.replace('{{geo_ip_file}}',      self.tor_geo_ip_file_path)
+            torrc_template = torrc_template.replace('{{geo_ipv6_file}}',    self.tor_geo_ipv6_file_path)
+            torrc_template = torrc_template.replace('{{socks_port}}',       self.tor_socks_port)
+            open(self.tor_torrc, 'w').write(torrc_template)
+
+            # Open tor in a subprocess, wait for the controller to start
+            self.tor_proc = subprocess.Popen([self.tor_path, '-f', self.tor_torrc], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            time.sleep(0.2)
+
+            # Connect to the controller
+            self.c = Controller.from_socket_file(path=self.tor_control_socket)
+            self.c.authenticate()
+
+            while True:
+                res = self.c.get_info("status/bootstrap-phase")
+                res_parts = shlex.split(res)
+                progress = res_parts[2].split('=')[1]
+                summary = res_parts[4].split('=')[1]
+
+                # "\033[K" clears the rest of the line
+                print("{}: {}% - {}{}".format(strings._('connecting_to_tor'), progress, summary, "\033[K"), end="\r")
+                if summary == 'Done':
+                    print("")
+                    break
+                time.sleep(0.2)
+
+        elif self.settings.get('connection_type') == 'automatic':
             # Automatically try to guess the right way to connect to Tor Browser
-            p = platform.system()
 
             # Try connecting to control port
             found_tor = False
@@ -152,7 +206,7 @@ class Onion(object):
                 socket_file_path = ''
                 if not found_tor:
                     try:
-                        if p == 'Darwin':
+                        if system == 'Darwin':
                             socket_file_path = os.path.expanduser('~/Library/Application Support/TorBrowser-Data/Tor/control.socket')
 
                         self.c = Controller.from_socket_file(path=socket_file_path)
@@ -164,12 +218,12 @@ class Onion(object):
             # guessing the socket file name next
             if not found_tor:
                 try:
-                    if p == 'Linux':
+                    if system == 'Linux':
                         socket_file_path = '/run/user/{}/Tor/control.socket'.format(os.geteuid())
-                    elif p == 'Darwin':
+                    elif system == 'Darwin':
                         # TODO: figure out the unix socket path in OS X
                         socket_file_path = '/run/user/{}/Tor/control.socket'.format(os.geteuid())
-                    elif p == 'Windows':
+                    elif system == 'Windows':
                         # Windows doesn't support unix sockets
                         raise TorErrorAutomatic(strings._('settings_error_automatic'))
 
@@ -276,12 +330,16 @@ class Onion(object):
 
     def cleanup(self):
         """
-        Stop onion services that were created earlier.
+        Stop onion services that were created earlier. If there's a tor subprocess running, kill it.
         """
-        # cleanup the ephemeral onion service
+        # Cleanup the ephemeral onion service
         if self.service_id:
             try:
                 self.c.remove_ephemeral_hidden_service(self.service_id)
             except:
                 pass
             self.service_id = None
+
+        # Stop tor process
+        if self.tor_proc:
+            self.tor_proc.terminate()
diff --git a/onionshare_gui/settings_dialog.py b/onionshare_gui/settings_dialog.py
index 13c6255..6cb6cdf 100644
--- a/onionshare_gui/settings_dialog.py
+++ b/onionshare_gui/settings_dialog.py
@@ -25,7 +25,6 @@ from onionshare.settings import Settings
 from onionshare.onion import *
 
 from .alert import Alert
-from .tor_dialog import TorDialog
 
 class SettingsDialog(QtWidgets.QDialog):
     """
@@ -74,16 +73,10 @@ class SettingsDialog(QtWidgets.QDialog):
         self.connection_type_bundled_radio = QtWidgets.QRadioButton(strings._('gui_settings_connection_type_bundled_option', True))
         self.connection_type_bundled_radio.toggled.connect(self.connection_type_bundled_toggled)
 
-        # Bundled Tor only works in Windows and Mac
+        # Bundled Tor doesn't work on dev mode in Windows or Mac
         p = platform.system()
-        if (p == 'Windows' or p == 'Darwin'):
-            # Bundled Tor doesn't work on dev mode
-            if getattr(sys, 'onionshare_dev_mode', False):
-                self.connection_type_bundled_radio.setEnabled(False)
-        else:
-            # If not using Windows or Mac, disable and hide bundled Tor
+        if (p == 'Windows' or p == 'Darwin') and getattr(sys, 'onionshare_dev_mode', False):
             self.connection_type_bundled_radio.setEnabled(False)
-            self.connection_type_bundled_radio.hide()
 
         # Automatic
         self.connection_type_automatic_radio = QtWidgets.QRadioButton(strings._('gui_settings_connection_type_automatic_option', True))
@@ -285,20 +278,14 @@ class SettingsDialog(QtWidgets.QDialog):
         """
         settings = self.settings_from_fields()
 
-        # If using bundled Tor, first connect to Tor
-        if settings.get('connection_type') == 'bundled':
-            tor_dialog = TorDialog()
-            tor_dialog.start()
-
-        else:
-            try:
-                onion = Onion(settings=settings)
+        try:
+            onion = Onion(settings=settings)
 
-                # If an exception hasn't been raised yet, the Tor settings work
-                Alert(strings._('settings_test_success', True).format(onion.tor_version, onion.supports_ephemeral, onion.supports_stealth))
+            # If an exception hasn't been raised yet, the Tor settings work
+            Alert(strings._('settings_test_success', True).format(onion.tor_version, onion.supports_ephemeral, onion.supports_stealth))
 
-            except (TorErrorInvalidSetting, TorErrorAutomatic, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile, TorErrorAuthError, TorErrorProtocolError, BundledTorNotSupported) as e:
-                Alert(e.args[0], QtWidgets.QMessageBox.Warning)
+        except (TorErrorInvalidSetting, TorErrorAutomatic, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile, TorErrorAuthError, TorErrorProtocolError, BundledTorNotSupported) as e:
+            Alert(e.args[0], QtWidgets.QMessageBox.Warning)
 
     def save_clicked(self):
         """
diff --git a/share/locale/en.json b/share/locale/en.json
index c0db438..e50f93e 100644
--- a/share/locale/en.json
+++ b/share/locale/en.json
@@ -90,5 +90,6 @@
     "error_tor_protocol_error": "Error talking to the Tor controller.\nIf you're using Whonix, check out https://www.whonix.org/wiki/onionshare to make OnionShare work.",
     "gui_tor_window_title": "Tor Connection",
     "gui_tor_button_close": "Close",
-    "gui_tor_button_restart": "Restart Tor"
+    "gui_tor_button_restart": "Restart Tor",
+    "connecting_to_tor": "Connecting to the Tor network"
 }
diff --git a/share/torrc_template b/share/torrc_template
new file mode 100644
index 0000000..464adf3
--- /dev/null
+++ b/share/torrc_template
@@ -0,0 +1,9 @@
+DataDirectory {{data_directory}}
+SocksPort {{socks_port}}
+ControlSocket {{control_socket}}
+CookieAuthentication 1
+CookieAuthFile {{cookie_auth_file}}
+AvoidDiskWrites 1
+Log notice stdout
+GeoIPFile {{geo_ip_file}}
+GeoIPv6File {{geo_ipv6_file}}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/onionshare.git



More information about the Pkg-privacy-commits mailing list