diff --git a/install/build_exe.bat b/install/build_exe.bat index c1b357fa..1f5faf45 100644 --- a/install/build_exe.bat +++ b/install/build_exe.bat @@ -8,10 +8,10 @@ REM download tor python install\get-tor-windows.py REM sign onionshare-gui.exe -signtool.exe sign /v /d "OnionShare" /a /tr http://timestamp.globalsign.com/scripts/timstamp.dll /fd sha256 dist\onionshare\onionshare-gui.exe +REM signtool.exe sign /v /d "OnionShare" /a /tr http://timestamp.globalsign.com/scripts/timstamp.dll /fd sha256 dist\onionshare\onionshare-gui.exe REM build an installer, dist\OnionShare_Setup.exe -makensis.exe install\onionshare.nsi +REM makensis.exe install\onionshare.nsi REM sign OnionShare_Setup.exe -signtool.exe sign /v /d "OnionShare" /a /tr http://timestamp.globalsign.com/scripts/timstamp.dll /fd sha256 dist\OnionShare_Setup.exe +REM signtool.exe sign /v /d "OnionShare" /a /tr http://timestamp.globalsign.com/scripts/timstamp.dll /fd sha256 dist\OnionShare_Setup.exe diff --git a/install/pyinstaller.spec b/install/pyinstaller.spec index 50be975d..14b0d822 100644 --- a/install/pyinstaller.spec +++ b/install/pyinstaller.spec @@ -13,6 +13,7 @@ a = Analysis( ('../share/license.txt', 'share'), ('../share/version.txt', 'share'), ('../share/wordlist.txt', 'share'), + ('../share/torrc_template-windows', 'share'), ('../share/images/*', 'share/images'), ('../share/locale/*', 'share/locale'), ('../share/html/*', 'share/html') diff --git a/onionshare/helpers.py b/onionshare/helpers.py index a7873942..9bd26f3e 100644 --- a/onionshare/helpers.py +++ b/onionshare/helpers.py @@ -53,6 +53,22 @@ def get_resource_path(filename): return os.path.join(prefix, filename) +def get_tor_paths(): + p = get_platform() + if p == 'Linux': + tor_path = '/usr/bin/tor' + tor_geo_ip_file_path = '/usr/share/tor/geoip' + tor_geo_ipv6_file_path = '/usr/share/tor/geoip6' + elif p == 'Windows': + base_path = os.path.join(os.path.dirname(os.path.dirname(get_resource_path(''))), 'tor') + tor_path = os.path.join(os.path.join(base_path, 'Tor'), "tor.exe") + tor_geo_ip_file_path = os.path.join(os.path.join(os.path.join(base_path, 'Data'), 'Tor'), 'geoip') + tor_geo_ipv6_file_path = os.path.join(os.path.join(os.path.join(base_path, 'Data'), 'Tor'), 'geoip6') + elif p == 'Darwin': + # TODO: implement + pass + + return (tor_path, tor_geo_ip_file_path, tor_geo_ipv6_file_path) def get_version(): """ diff --git a/onionshare/onion.py b/onionshare/onion.py index 3df5eada..81e1dfd5 100644 --- a/onionshare/onion.py +++ b/onionshare/onion.py @@ -21,7 +21,7 @@ along with this program. If not, see . from stem.control import Controller from stem import ProtocolError from stem.connection import MissingPassword, UnreadableCookieFile, AuthenticationFailure -import os, sys, tempfile, shutil, urllib, platform, subprocess, time, shlex +import os, sys, tempfile, shutil, urllib, platform, subprocess, time, shlex, socket, random from . import socks from . import helpers, strings @@ -133,16 +133,7 @@ class Onion(object): 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 + (self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path) = helpers.get_tor_paths() # The tor process self.tor_p = None @@ -156,28 +147,47 @@ class Onion(object): # 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() + + if system == 'Windows': + # Windows needs to use network ports, doesn't support unix sockets + torrc_template = open(helpers.get_resource_path('torrc_template-windows')).read() + self.tor_control_port = self._get_available_port() + self.tor_control_socket = None + self.tor_cookie_auth_file = os.path.join(self.tor_data_directory.name, 'cookie') + self.tor_socks_port_file = None + self.tor_socks_port = self._get_available_port() + self.tor_torrc = os.path.join(self.tor_data_directory.name, 'torrc') + else: + # Linux and Mac can use unix sockets + torrc_template = open(helpers.get_resource_path('torrc_template')).read() + self.tor_control_port = None + 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 = 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('{{control_port}}', str(self.tor_control_port)) + torrc_template = torrc_template.replace('{{control_socket}}', str(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) + torrc_template = torrc_template.replace('{{socks_port}}', str(self.tor_socks_port)) open(self.tor_torrc, 'w').write(torrc_template) # Open tor in a subprocess, wait for the controller to start start_ts = time.time() - self.tor_proc = subprocess.Popen([self.tor_path, '-f', self.tor_torrc], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + self.tor_proc = subprocess.Popen([self.tor_path, '-f', self.tor_torrc], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) time.sleep(0.2) # Connect to the controller - self.c = Controller.from_socket_file(path=self.tor_control_socket) - self.c.authenticate() + if system == 'Windows': + self.c = Controller.from_port(port=self.tor_control_port) + self.c.authenticate() + else: + elf.c = Controller.from_socket_file(path=self.tor_control_socket) + self.c.authenticate() while True: res = self.c.get_info("status/bootstrap-phase") @@ -370,3 +380,19 @@ class Onion(object): if self.tor_proc: self.tor_proc.terminate() self.tor_proc = None + + def _get_available_port(self): + """ + Find a random available port + """ + tmpsock = socket.socket() + while True: + try: + tmpsock.bind(("127.0.0.1", random.randint(1000, 65535))) + break + except OSError: + pass + port = tmpsock.getsockname()[1] + tmpsock.close() + + return port diff --git a/share/torrc_template-windows b/share/torrc_template-windows new file mode 100644 index 00000000..38a5bf1e --- /dev/null +++ b/share/torrc_template-windows @@ -0,0 +1,9 @@ +DataDirectory {{data_directory}} +SocksPort {{socks_port}} +ControlPort {{control_port}} +CookieAuthentication 1 +CookieAuthFile {{cookie_auth_file}} +AvoidDiskWrites 1 +Log notice stdout +GeoIPFile {{geo_ip_file}} +GeoIPv6File {{geo_ipv6_file}}