mirror of
https://github.com/onionshare/onionshare.git
synced 2024-12-26 07:49:48 -05:00
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
This commit is contained in:
parent
dc82a99d2a
commit
169be518eb
@ -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
|
||||
# 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)
|
||||
|
||||
if self.settings.get('connection_type') == 'automatic':
|
||||
# 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()
|
||||
|
@ -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()
|
||||
try:
|
||||
onion = Onion(settings=settings)
|
||||
|
||||
else:
|
||||
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):
|
||||
"""
|
||||
|
@ -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"
|
||||
}
|
||||
|
9
share/torrc_template
Normal file
9
share/torrc_template
Normal file
@ -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}}
|
Loading…
Reference in New Issue
Block a user