mirror of
https://github.com/onionshare/onionshare.git
synced 2024-12-26 07:49:48 -05:00
Completely refactor common to make a Common class, and pass that class down into all parts of the program
This commit is contained in:
parent
49e352d131
commit
50409167d4
@ -20,7 +20,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
import os, sys, time, argparse, threading
|
import os, sys, time, argparse, threading
|
||||||
|
|
||||||
from . import strings, common
|
from . import strings
|
||||||
|
from .common import Common
|
||||||
from .web import Web
|
from .web import Web
|
||||||
from .onion import *
|
from .onion import *
|
||||||
from .onionshare import OnionShare
|
from .onionshare import OnionShare
|
||||||
@ -31,11 +32,13 @@ def main(cwd=None):
|
|||||||
The main() function implements all of the logic that the command-line version of
|
The main() function implements all of the logic that the command-line version of
|
||||||
onionshare uses.
|
onionshare uses.
|
||||||
"""
|
"""
|
||||||
|
common = Common()
|
||||||
|
|
||||||
strings.load_strings(common)
|
strings.load_strings(common)
|
||||||
print(strings._('version_string').format(common.get_version()))
|
print(strings._('version_string').format(common.version))
|
||||||
|
|
||||||
# OnionShare CLI in OSX needs to change current working directory (#132)
|
# OnionShare CLI in OSX needs to change current working directory (#132)
|
||||||
if common.get_platform() == 'Darwin':
|
if common.platform == 'Darwin':
|
||||||
if cwd:
|
if cwd:
|
||||||
os.chdir(cwd)
|
os.chdir(cwd)
|
||||||
|
|
||||||
@ -69,8 +72,7 @@ def main(cwd=None):
|
|||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
# Debug mode?
|
# Debug mode?
|
||||||
if debug:
|
common.debug = debug
|
||||||
common.set_debug(debug)
|
|
||||||
|
|
||||||
# Validate filenames
|
# Validate filenames
|
||||||
if not receive:
|
if not receive:
|
||||||
@ -86,7 +88,7 @@ def main(cwd=None):
|
|||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
# Load settings
|
# Load settings
|
||||||
settings = Settings(config)
|
settings = Settings(common, config)
|
||||||
settings.load()
|
settings.load()
|
||||||
|
|
||||||
# In receive mode, validate downloads dir
|
# In receive mode, validate downloads dir
|
||||||
@ -105,10 +107,10 @@ def main(cwd=None):
|
|||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
# Create the Web object
|
# Create the Web object
|
||||||
web = Web(debug, stay_open, False, receive)
|
web = Web(common, stay_open, False, receive)
|
||||||
|
|
||||||
# Start the Onion object
|
# Start the Onion object
|
||||||
onion = Onion()
|
onion = Onion(common)
|
||||||
try:
|
try:
|
||||||
onion.connect(settings=False, config=config)
|
onion.connect(settings=False, config=config)
|
||||||
except (TorTooOld, TorErrorInvalidSetting, TorErrorAutomatic, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile, TorErrorAuthError, TorErrorProtocolError, BundledTorNotSupported, BundledTorTimeout) as e:
|
except (TorTooOld, TorErrorInvalidSetting, TorErrorAutomatic, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile, TorErrorAuthError, TorErrorProtocolError, BundledTorNotSupported, BundledTorTimeout) as e:
|
||||||
@ -119,7 +121,7 @@ def main(cwd=None):
|
|||||||
|
|
||||||
# Start the onionshare app
|
# Start the onionshare app
|
||||||
try:
|
try:
|
||||||
app = OnionShare(onion, local_only, stay_open, shutdown_timeout)
|
app = OnionShare(common, onion, local_only, stay_open, shutdown_timeout)
|
||||||
app.set_stealth(stealth)
|
app.set_stealth(stealth)
|
||||||
app.start_onion_service()
|
app.start_onion_service()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
@ -29,15 +29,27 @@ import tempfile
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
debug = False
|
class Common(object):
|
||||||
|
"""
|
||||||
|
The Common object is shared amongst all parts of OnionShare.
|
||||||
|
"""
|
||||||
|
def __init__(self, debug=False):
|
||||||
|
self.debug = debug
|
||||||
|
|
||||||
|
# The platform OnionShare is running on
|
||||||
|
self.platform = platform.system()
|
||||||
|
if self.platform.endswith('BSD'):
|
||||||
|
self.platform = 'BSD'
|
||||||
|
|
||||||
def log(module, func, msg=None):
|
# The current version of OnionShare
|
||||||
|
with open(self.get_resource_path('version.txt')) as f:
|
||||||
|
self.version = f.read().strip()
|
||||||
|
|
||||||
|
def log(self, module, func, msg=None):
|
||||||
"""
|
"""
|
||||||
If debug mode is on, log error messages to stdout
|
If debug mode is on, log error messages to stdout
|
||||||
"""
|
"""
|
||||||
global debug
|
if self.debug:
|
||||||
if debug:
|
|
||||||
timestamp = time.strftime("%b %d %Y %X")
|
timestamp = time.strftime("%b %d %Y %X")
|
||||||
|
|
||||||
final_msg = "[{}] {}.{}".format(timestamp, module, func)
|
final_msg = "[{}] {}.{}".format(timestamp, module, func)
|
||||||
@ -45,31 +57,13 @@ def log(module, func, msg=None):
|
|||||||
final_msg = '{}: {}'.format(final_msg, msg)
|
final_msg = '{}: {}'.format(final_msg, msg)
|
||||||
print(final_msg)
|
print(final_msg)
|
||||||
|
|
||||||
|
def get_resource_path(self, filename):
|
||||||
def set_debug(new_debug):
|
|
||||||
global debug
|
|
||||||
debug = new_debug
|
|
||||||
|
|
||||||
|
|
||||||
def get_platform():
|
|
||||||
"""
|
|
||||||
Returns the platform OnionShare is running on.
|
|
||||||
"""
|
|
||||||
plat = platform.system()
|
|
||||||
if plat.endswith('BSD'):
|
|
||||||
plat = 'BSD'
|
|
||||||
return plat
|
|
||||||
|
|
||||||
|
|
||||||
def get_resource_path(filename):
|
|
||||||
"""
|
"""
|
||||||
Returns the absolute path of a resource, regardless of whether OnionShare is installed
|
Returns the absolute path of a resource, regardless of whether OnionShare is installed
|
||||||
systemwide, and whether regardless of platform
|
systemwide, and whether regardless of platform
|
||||||
"""
|
"""
|
||||||
p = get_platform()
|
|
||||||
|
|
||||||
# On Windows, and in Windows dev mode, switch slashes in incoming filename to backslackes
|
# On Windows, and in Windows dev mode, switch slashes in incoming filename to backslackes
|
||||||
if p == 'Windows':
|
if self.platform == 'Windows':
|
||||||
filename = filename.replace('/', '\\')
|
filename = filename.replace('/', '\\')
|
||||||
|
|
||||||
if getattr(sys, 'onionshare_dev_mode', False):
|
if getattr(sys, 'onionshare_dev_mode', False):
|
||||||
@ -79,41 +73,39 @@ def get_resource_path(filename):
|
|||||||
# While running tests during stdeb bdist_deb, look 3 directories up for the share folder
|
# While running tests during stdeb bdist_deb, look 3 directories up for the share folder
|
||||||
prefix = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(prefix)))), 'share')
|
prefix = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(prefix)))), 'share')
|
||||||
|
|
||||||
elif p == 'BSD' or p == 'Linux':
|
elif self.platform == 'BSD' or self.platform == 'Linux':
|
||||||
# Assume OnionShare is installed systemwide in Linux, since we're not running in dev mode
|
# Assume OnionShare is installed systemwide in Linux, since we're not running in dev mode
|
||||||
prefix = os.path.join(sys.prefix, 'share/onionshare')
|
prefix = os.path.join(sys.prefix, 'share/onionshare')
|
||||||
|
|
||||||
elif getattr(sys, 'frozen', False):
|
elif getattr(sys, 'frozen', False):
|
||||||
# Check if app is "frozen"
|
# Check if app is "frozen"
|
||||||
# https://pythonhosted.org/PyInstaller/#run-time-information
|
# https://pythonhosted.org/PyInstaller/#run-time-information
|
||||||
if p == 'Darwin':
|
if self.platform == 'Darwin':
|
||||||
prefix = os.path.join(sys._MEIPASS, 'share')
|
prefix = os.path.join(sys._MEIPASS, 'share')
|
||||||
elif p == 'Windows':
|
elif self.platform == 'Windows':
|
||||||
prefix = os.path.join(os.path.dirname(sys.executable), 'share')
|
prefix = os.path.join(os.path.dirname(sys.executable), 'share')
|
||||||
|
|
||||||
return os.path.join(prefix, filename)
|
return os.path.join(prefix, filename)
|
||||||
|
|
||||||
|
def get_tor_paths(self):
|
||||||
def get_tor_paths():
|
if self.platform == 'Linux':
|
||||||
p = get_platform()
|
|
||||||
if p == 'Linux':
|
|
||||||
tor_path = '/usr/bin/tor'
|
tor_path = '/usr/bin/tor'
|
||||||
tor_geo_ip_file_path = '/usr/share/tor/geoip'
|
tor_geo_ip_file_path = '/usr/share/tor/geoip'
|
||||||
tor_geo_ipv6_file_path = '/usr/share/tor/geoip6'
|
tor_geo_ipv6_file_path = '/usr/share/tor/geoip6'
|
||||||
obfs4proxy_file_path = '/usr/bin/obfs4proxy'
|
obfs4proxy_file_path = '/usr/bin/obfs4proxy'
|
||||||
elif p == 'Windows':
|
elif self.platform == 'Windows':
|
||||||
base_path = os.path.join(os.path.dirname(os.path.dirname(get_resource_path(''))), 'tor')
|
base_path = os.path.join(os.path.dirname(os.path.dirname(self.get_resource_path(''))), 'tor')
|
||||||
tor_path = os.path.join(os.path.join(base_path, 'Tor'), 'tor.exe')
|
tor_path = os.path.join(os.path.join(base_path, 'Tor'), 'tor.exe')
|
||||||
obfs4proxy_file_path = os.path.join(os.path.join(base_path, 'Tor'), 'obfs4proxy.exe')
|
obfs4proxy_file_path = os.path.join(os.path.join(base_path, 'Tor'), 'obfs4proxy.exe')
|
||||||
tor_geo_ip_file_path = os.path.join(os.path.join(os.path.join(base_path, 'Data'), 'Tor'), 'geoip')
|
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')
|
tor_geo_ipv6_file_path = os.path.join(os.path.join(os.path.join(base_path, 'Data'), 'Tor'), 'geoip6')
|
||||||
elif p == 'Darwin':
|
elif self.platform == 'Darwin':
|
||||||
base_path = os.path.dirname(os.path.dirname(os.path.dirname(get_resource_path(''))))
|
base_path = os.path.dirname(os.path.dirname(os.path.dirname(self.get_resource_path(''))))
|
||||||
tor_path = os.path.join(base_path, 'Resources', 'Tor', 'tor')
|
tor_path = os.path.join(base_path, 'Resources', 'Tor', 'tor')
|
||||||
tor_geo_ip_file_path = os.path.join(base_path, 'Resources', 'Tor', 'geoip')
|
tor_geo_ip_file_path = os.path.join(base_path, 'Resources', 'Tor', 'geoip')
|
||||||
tor_geo_ipv6_file_path = os.path.join(base_path, 'Resources', 'Tor', 'geoip6')
|
tor_geo_ipv6_file_path = os.path.join(base_path, 'Resources', 'Tor', 'geoip6')
|
||||||
obfs4proxy_file_path = os.path.join(base_path, 'Resources', 'Tor', 'obfs4proxy')
|
obfs4proxy_file_path = os.path.join(base_path, 'Resources', 'Tor', 'obfs4proxy')
|
||||||
elif p == 'BSD':
|
elif self.platform == 'BSD':
|
||||||
tor_path = '/usr/local/bin/tor'
|
tor_path = '/usr/local/bin/tor'
|
||||||
tor_geo_ip_file_path = '/usr/local/share/tor/geoip'
|
tor_geo_ip_file_path = '/usr/local/share/tor/geoip'
|
||||||
tor_geo_ipv6_file_path = '/usr/local/share/tor/geoip6'
|
tor_geo_ipv6_file_path = '/usr/local/share/tor/geoip6'
|
||||||
@ -121,16 +113,17 @@ def get_tor_paths():
|
|||||||
|
|
||||||
return (tor_path, tor_geo_ip_file_path, tor_geo_ipv6_file_path, obfs4proxy_file_path)
|
return (tor_path, tor_geo_ip_file_path, tor_geo_ipv6_file_path, obfs4proxy_file_path)
|
||||||
|
|
||||||
|
def build_slug(self):
|
||||||
def get_version():
|
|
||||||
"""
|
"""
|
||||||
Returns the version of OnionShare that is running.
|
Returns a random string made from two words from the wordlist, such as "deter-trig".
|
||||||
"""
|
"""
|
||||||
with open(get_resource_path('version.txt')) as f:
|
with open(self.get_resource_path('wordlist.txt')) as f:
|
||||||
version = f.read().strip()
|
wordlist = f.read().split()
|
||||||
return version
|
|
||||||
|
|
||||||
|
r = random.SystemRandom()
|
||||||
|
return '-'.join(r.choice(wordlist) for _ in range(2))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def random_string(num_bytes, output_len=None):
|
def random_string(num_bytes, output_len=None):
|
||||||
"""
|
"""
|
||||||
Returns a random string with a specified number of bytes.
|
Returns a random string with a specified number of bytes.
|
||||||
@ -142,18 +135,7 @@ def random_string(num_bytes, output_len=None):
|
|||||||
return s
|
return s
|
||||||
return s[:output_len]
|
return s[:output_len]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def build_slug():
|
|
||||||
"""
|
|
||||||
Returns a random string made from two words from the wordlist, such as "deter-trig".
|
|
||||||
"""
|
|
||||||
with open(get_resource_path('wordlist.txt')) as f:
|
|
||||||
wordlist = f.read().split()
|
|
||||||
|
|
||||||
r = random.SystemRandom()
|
|
||||||
return '-'.join(r.choice(wordlist) for _ in range(2))
|
|
||||||
|
|
||||||
|
|
||||||
def human_readable_filesize(b):
|
def human_readable_filesize(b):
|
||||||
"""
|
"""
|
||||||
Returns filesize in a human readable format.
|
Returns filesize in a human readable format.
|
||||||
@ -169,7 +151,7 @@ def human_readable_filesize(b):
|
|||||||
u += 1
|
u += 1
|
||||||
return '{:.1f} {}'.format(b, units[u])
|
return '{:.1f} {}'.format(b, units[u])
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def format_seconds(seconds):
|
def format_seconds(seconds):
|
||||||
"""Return a human-readable string of the format 1d2h3m4s"""
|
"""Return a human-readable string of the format 1d2h3m4s"""
|
||||||
days, seconds = divmod(seconds, 86400)
|
days, seconds = divmod(seconds, 86400)
|
||||||
@ -187,7 +169,7 @@ def format_seconds(seconds):
|
|||||||
human_readable.append("{:.0f}s".format(seconds))
|
human_readable.append("{:.0f}s".format(seconds))
|
||||||
return ''.join(human_readable)
|
return ''.join(human_readable)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def estimated_time_remaining(bytes_downloaded, total_bytes, started):
|
def estimated_time_remaining(bytes_downloaded, total_bytes, started):
|
||||||
now = time.time()
|
now = time.time()
|
||||||
time_elapsed = now - started # in seconds
|
time_elapsed = now - started # in seconds
|
||||||
@ -196,7 +178,7 @@ def estimated_time_remaining(bytes_downloaded, total_bytes, started):
|
|||||||
eta = remaining_bytes / download_rate
|
eta = remaining_bytes / download_rate
|
||||||
return format_seconds(eta)
|
return format_seconds(eta)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def get_available_port(min_port, max_port):
|
def get_available_port(min_port, max_port):
|
||||||
"""
|
"""
|
||||||
Find a random available port within the given range.
|
Find a random available port within the given range.
|
||||||
@ -211,7 +193,7 @@ def get_available_port(min_port, max_port):
|
|||||||
_, port = tmpsock.getsockname()
|
_, port = tmpsock.getsockname()
|
||||||
return port
|
return port
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def dir_size(start_path):
|
def dir_size(start_path):
|
||||||
"""
|
"""
|
||||||
Calculates the total size, in bytes, of all of the files in a directory.
|
Calculates the total size, in bytes, of all of the files in a directory.
|
||||||
@ -229,12 +211,15 @@ class ShutdownTimer(threading.Thread):
|
|||||||
"""
|
"""
|
||||||
Background thread sleeps t hours and returns.
|
Background thread sleeps t hours and returns.
|
||||||
"""
|
"""
|
||||||
def __init__(self, time):
|
def __init__(self, common, time):
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
|
|
||||||
|
self.common = common
|
||||||
|
|
||||||
self.setDaemon(True)
|
self.setDaemon(True)
|
||||||
self.time = time
|
self.time = time
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
log('Shutdown Timer', 'Server will shut down after {} seconds'.format(self.time))
|
self.common.log('Shutdown Timer', 'Server will shut down after {} seconds'.format(self.time))
|
||||||
time.sleep(self.time)
|
time.sleep(self.time)
|
||||||
return 1
|
return 1
|
||||||
|
@ -125,22 +125,22 @@ class Onion(object):
|
|||||||
call this function and pass in a status string while connecting to tor. This
|
call this function and pass in a status string while connecting to tor. This
|
||||||
is necessary for status updates to reach the GUI.
|
is necessary for status updates to reach the GUI.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self, common):
|
||||||
common.log('Onion', '__init__')
|
self.common = common
|
||||||
|
|
||||||
|
self.common.log('Onion', '__init__')
|
||||||
|
|
||||||
self.stealth = False
|
self.stealth = False
|
||||||
self.service_id = None
|
self.service_id = None
|
||||||
|
|
||||||
self.system = common.get_platform()
|
|
||||||
|
|
||||||
# Is bundled tor supported?
|
# Is bundled tor supported?
|
||||||
if (self.system == 'Windows' or self.system == 'Darwin') and getattr(sys, 'onionshare_dev_mode', False):
|
if (self.common.platform == 'Windows' or self.common.platform == 'Darwin') and getattr(sys, 'onionshare_dev_mode', False):
|
||||||
self.bundle_tor_supported = False
|
self.bundle_tor_supported = False
|
||||||
else:
|
else:
|
||||||
self.bundle_tor_supported = True
|
self.bundle_tor_supported = True
|
||||||
|
|
||||||
# Set the path of the tor binary, for bundled tor
|
# Set the path of the tor binary, for bundled tor
|
||||||
(self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = common.get_tor_paths()
|
(self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = self.common.get_tor_paths()
|
||||||
|
|
||||||
# The tor process
|
# The tor process
|
||||||
self.tor_proc = None
|
self.tor_proc = None
|
||||||
@ -149,13 +149,13 @@ class Onion(object):
|
|||||||
self.connected_to_tor = False
|
self.connected_to_tor = False
|
||||||
|
|
||||||
def connect(self, settings=False, config=False, tor_status_update_func=None):
|
def connect(self, settings=False, config=False, tor_status_update_func=None):
|
||||||
common.log('Onion', 'connect')
|
self.common.log('Onion', 'connect')
|
||||||
|
|
||||||
# Either use settings that are passed in, or load them from disk
|
# Either use settings that are passed in, or load them from disk
|
||||||
if settings:
|
if settings:
|
||||||
self.settings = settings
|
self.settings = settings
|
||||||
else:
|
else:
|
||||||
self.settings = Settings(config)
|
self.settings = Settings(self.common, config)
|
||||||
self.settings.load()
|
self.settings.load()
|
||||||
|
|
||||||
# The Tor controller
|
# The Tor controller
|
||||||
@ -168,29 +168,29 @@ class Onion(object):
|
|||||||
# Create a torrc for this session
|
# Create a torrc for this session
|
||||||
self.tor_data_directory = tempfile.TemporaryDirectory()
|
self.tor_data_directory = tempfile.TemporaryDirectory()
|
||||||
|
|
||||||
if self.system == 'Windows':
|
if self.common.platform == 'Windows':
|
||||||
# Windows needs to use network ports, doesn't support unix sockets
|
# Windows needs to use network ports, doesn't support unix sockets
|
||||||
torrc_template = open(common.get_resource_path('torrc_template-windows')).read()
|
torrc_template = open(self.common.get_resource_path('torrc_template-windows')).read()
|
||||||
try:
|
try:
|
||||||
self.tor_control_port = common.get_available_port(1000, 65535)
|
self.tor_control_port = self.common.get_available_port(1000, 65535)
|
||||||
except:
|
except:
|
||||||
raise OSError(strings._('no_available_port'))
|
raise OSError(strings._('no_available_port'))
|
||||||
self.tor_control_socket = None
|
self.tor_control_socket = None
|
||||||
self.tor_cookie_auth_file = os.path.join(self.tor_data_directory.name, 'cookie')
|
self.tor_cookie_auth_file = os.path.join(self.tor_data_directory.name, 'cookie')
|
||||||
try:
|
try:
|
||||||
self.tor_socks_port = common.get_available_port(1000, 65535)
|
self.tor_socks_port = self.common.get_available_port(1000, 65535)
|
||||||
except:
|
except:
|
||||||
raise OSError(strings._('no_available_port'))
|
raise OSError(strings._('no_available_port'))
|
||||||
self.tor_torrc = os.path.join(self.tor_data_directory.name, 'torrc')
|
self.tor_torrc = os.path.join(self.tor_data_directory.name, 'torrc')
|
||||||
else:
|
else:
|
||||||
# Linux, Mac and BSD can use unix sockets
|
# Linux, Mac and BSD can use unix sockets
|
||||||
with open(common.get_resource_path('torrc_template')) as f:
|
with open(self.common.get_resource_path('torrc_template')) as f:
|
||||||
torrc_template = f.read()
|
torrc_template = f.read()
|
||||||
self.tor_control_port = None
|
self.tor_control_port = None
|
||||||
self.tor_control_socket = os.path.join(self.tor_data_directory.name, 'control_socket')
|
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_cookie_auth_file = os.path.join(self.tor_data_directory.name, 'cookie')
|
||||||
try:
|
try:
|
||||||
self.tor_socks_port = common.get_available_port(1000, 65535)
|
self.tor_socks_port = self.common.get_available_port(1000, 65535)
|
||||||
except:
|
except:
|
||||||
raise OSError(strings._('no_available_port'))
|
raise OSError(strings._('no_available_port'))
|
||||||
self.tor_torrc = os.path.join(self.tor_data_directory.name, 'torrc')
|
self.tor_torrc = os.path.join(self.tor_data_directory.name, 'torrc')
|
||||||
@ -208,17 +208,17 @@ class Onion(object):
|
|||||||
# Bridge support
|
# Bridge support
|
||||||
if self.settings.get('tor_bridges_use_obfs4'):
|
if self.settings.get('tor_bridges_use_obfs4'):
|
||||||
f.write('ClientTransportPlugin obfs4 exec {}\n'.format(self.obfs4proxy_file_path))
|
f.write('ClientTransportPlugin obfs4 exec {}\n'.format(self.obfs4proxy_file_path))
|
||||||
with open(common.get_resource_path('torrc_template-obfs4')) as o:
|
with open(self.common.get_resource_path('torrc_template-obfs4')) as o:
|
||||||
for line in o:
|
for line in o:
|
||||||
f.write(line)
|
f.write(line)
|
||||||
elif self.settings.get('tor_bridges_use_meek_lite_amazon'):
|
elif self.settings.get('tor_bridges_use_meek_lite_amazon'):
|
||||||
f.write('ClientTransportPlugin meek_lite exec {}\n'.format(self.obfs4proxy_file_path))
|
f.write('ClientTransportPlugin meek_lite exec {}\n'.format(self.obfs4proxy_file_path))
|
||||||
with open(common.get_resource_path('torrc_template-meek_lite_amazon')) as o:
|
with open(self.common.get_resource_path('torrc_template-meek_lite_amazon')) as o:
|
||||||
for line in o:
|
for line in o:
|
||||||
f.write(line)
|
f.write(line)
|
||||||
elif self.settings.get('tor_bridges_use_meek_lite_azure'):
|
elif self.settings.get('tor_bridges_use_meek_lite_azure'):
|
||||||
f.write('ClientTransportPlugin meek_lite exec {}\n'.format(self.obfs4proxy_file_path))
|
f.write('ClientTransportPlugin meek_lite exec {}\n'.format(self.obfs4proxy_file_path))
|
||||||
with open(common.get_resource_path('torrc_template-meek_lite_azure')) as o:
|
with open(self.common.get_resource_path('torrc_template-meek_lite_azure')) as o:
|
||||||
for line in o:
|
for line in o:
|
||||||
f.write(line)
|
f.write(line)
|
||||||
|
|
||||||
@ -232,7 +232,7 @@ class Onion(object):
|
|||||||
|
|
||||||
# Execute a tor subprocess
|
# Execute a tor subprocess
|
||||||
start_ts = time.time()
|
start_ts = time.time()
|
||||||
if self.system == 'Windows':
|
if self.common.platform == 'Windows':
|
||||||
# In Windows, hide console window when opening tor.exe subprocess
|
# In Windows, hide console window when opening tor.exe subprocess
|
||||||
startupinfo = subprocess.STARTUPINFO()
|
startupinfo = subprocess.STARTUPINFO()
|
||||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||||
@ -245,7 +245,7 @@ class Onion(object):
|
|||||||
|
|
||||||
# Connect to the controller
|
# Connect to the controller
|
||||||
try:
|
try:
|
||||||
if self.system == 'Windows':
|
if self.common.platform == 'Windows':
|
||||||
self.c = Controller.from_port(port=self.tor_control_port)
|
self.c = Controller.from_port(port=self.tor_control_port)
|
||||||
self.c.authenticate()
|
self.c.authenticate()
|
||||||
else:
|
else:
|
||||||
@ -270,7 +270,7 @@ class Onion(object):
|
|||||||
if callable(tor_status_update_func):
|
if callable(tor_status_update_func):
|
||||||
if not tor_status_update_func(progress, summary):
|
if not tor_status_update_func(progress, summary):
|
||||||
# If the dialog was canceled, stop connecting to Tor
|
# If the dialog was canceled, stop connecting to Tor
|
||||||
common.log('Onion', 'connect', 'tor_status_update_func returned false, canceling connecting to Tor')
|
self.common.log('Onion', 'connect', 'tor_status_update_func returned false, canceling connecting to Tor')
|
||||||
print()
|
print()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -322,7 +322,7 @@ class Onion(object):
|
|||||||
socket_file_path = ''
|
socket_file_path = ''
|
||||||
if not found_tor:
|
if not found_tor:
|
||||||
try:
|
try:
|
||||||
if self.system == 'Darwin':
|
if self.common.platform == 'Darwin':
|
||||||
socket_file_path = os.path.expanduser('~/Library/Application Support/TorBrowser-Data/Tor/control.socket')
|
socket_file_path = os.path.expanduser('~/Library/Application Support/TorBrowser-Data/Tor/control.socket')
|
||||||
|
|
||||||
self.c = Controller.from_socket_file(path=socket_file_path)
|
self.c = Controller.from_socket_file(path=socket_file_path)
|
||||||
@ -334,11 +334,11 @@ class Onion(object):
|
|||||||
# guessing the socket file name next
|
# guessing the socket file name next
|
||||||
if not found_tor:
|
if not found_tor:
|
||||||
try:
|
try:
|
||||||
if self.system == 'Linux' or self.system == 'BSD':
|
if self.common.platform == 'Linux' or self.common.platform == 'BSD':
|
||||||
socket_file_path = '/run/user/{}/Tor/control.socket'.format(os.geteuid())
|
socket_file_path = '/run/user/{}/Tor/control.socket'.format(os.geteuid())
|
||||||
elif self.system == 'Darwin':
|
elif self.common.platform == 'Darwin':
|
||||||
socket_file_path = '/run/user/{}/Tor/control.socket'.format(os.geteuid())
|
socket_file_path = '/run/user/{}/Tor/control.socket'.format(os.geteuid())
|
||||||
elif self.system == 'Windows':
|
elif self.common.platform == 'Windows':
|
||||||
# Windows doesn't support unix sockets
|
# Windows doesn't support unix sockets
|
||||||
raise TorErrorAutomatic(strings._('settings_error_automatic'))
|
raise TorErrorAutomatic(strings._('settings_error_automatic'))
|
||||||
|
|
||||||
@ -424,7 +424,7 @@ class Onion(object):
|
|||||||
Start a onion service on port 80, pointing to the given port, and
|
Start a onion service on port 80, pointing to the given port, and
|
||||||
return the onion hostname.
|
return the onion hostname.
|
||||||
"""
|
"""
|
||||||
common.log('Onion', 'start_onion_service')
|
self.common.log('Onion', 'start_onion_service')
|
||||||
|
|
||||||
self.auth_string = None
|
self.auth_string = None
|
||||||
if not self.supports_ephemeral:
|
if not self.supports_ephemeral:
|
||||||
@ -447,11 +447,11 @@ class Onion(object):
|
|||||||
if self.settings.get('private_key'):
|
if self.settings.get('private_key'):
|
||||||
key_type = "RSA1024"
|
key_type = "RSA1024"
|
||||||
key_content = self.settings.get('private_key')
|
key_content = self.settings.get('private_key')
|
||||||
common.log('Onion', 'Starting a hidden service with a saved private key')
|
self.common.log('Onion', 'Starting a hidden service with a saved private key')
|
||||||
else:
|
else:
|
||||||
key_type = "NEW"
|
key_type = "NEW"
|
||||||
key_content = "RSA1024"
|
key_content = "RSA1024"
|
||||||
common.log('Onion', 'Starting a hidden service with a new private key')
|
self.common.log('Onion', 'Starting a hidden service with a new private key')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if basic_auth != None:
|
if basic_auth != None:
|
||||||
@ -498,17 +498,17 @@ class Onion(object):
|
|||||||
"""
|
"""
|
||||||
Stop onion services that were created earlier. If there's a tor subprocess running, kill it.
|
Stop onion services that were created earlier. If there's a tor subprocess running, kill it.
|
||||||
"""
|
"""
|
||||||
common.log('Onion', 'cleanup')
|
self.common.log('Onion', 'cleanup')
|
||||||
|
|
||||||
# Cleanup the ephemeral onion services, if we have any
|
# Cleanup the ephemeral onion services, if we have any
|
||||||
try:
|
try:
|
||||||
onions = self.c.list_ephemeral_hidden_services()
|
onions = self.c.list_ephemeral_hidden_services()
|
||||||
for onion in onions:
|
for onion in onions:
|
||||||
try:
|
try:
|
||||||
common.log('Onion', 'cleanup', 'trying to remove onion {}'.format(onion))
|
self.common.log('Onion', 'cleanup', 'trying to remove onion {}'.format(onion))
|
||||||
self.c.remove_ephemeral_hidden_service(onion)
|
self.c.remove_ephemeral_hidden_service(onion)
|
||||||
except:
|
except:
|
||||||
common.log('Onion', 'cleanup', 'could not remove onion {}.. moving on anyway'.format(onion))
|
self.common.log('Onion', 'cleanup', 'could not remove onion {}.. moving on anyway'.format(onion))
|
||||||
pass
|
pass
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
@ -545,7 +545,7 @@ class Onion(object):
|
|||||||
"""
|
"""
|
||||||
Returns a (address, port) tuple for the Tor SOCKS port
|
Returns a (address, port) tuple for the Tor SOCKS port
|
||||||
"""
|
"""
|
||||||
common.log('Onion', 'get_tor_socks_port')
|
self.common.log('Onion', 'get_tor_socks_port')
|
||||||
|
|
||||||
if self.settings.get('connection_type') == 'bundled':
|
if self.settings.get('connection_type') == 'bundled':
|
||||||
return ('127.0.0.1', self.tor_socks_port)
|
return ('127.0.0.1', self.tor_socks_port)
|
||||||
|
@ -28,8 +28,10 @@ class OnionShare(object):
|
|||||||
OnionShare is the main application class. Pass in options and run
|
OnionShare is the main application class. Pass in options and run
|
||||||
start_onion_service and it will do the magic.
|
start_onion_service and it will do the magic.
|
||||||
"""
|
"""
|
||||||
def __init__(self, onion, local_only=False, stay_open=False, shutdown_timeout=0):
|
def __init__(self, common, onion, local_only=False, stay_open=False, shutdown_timeout=0):
|
||||||
common.log('OnionShare', '__init__')
|
self.common = common
|
||||||
|
|
||||||
|
self.common.log('OnionShare', '__init__')
|
||||||
|
|
||||||
# The Onion object
|
# The Onion object
|
||||||
self.onion = onion
|
self.onion = onion
|
||||||
@ -53,7 +55,7 @@ class OnionShare(object):
|
|||||||
self.shutdown_timer = None
|
self.shutdown_timer = None
|
||||||
|
|
||||||
def set_stealth(self, stealth):
|
def set_stealth(self, stealth):
|
||||||
common.log('OnionShare', 'set_stealth', 'stealth={}'.format(stealth))
|
self.common.log('OnionShare', 'set_stealth', 'stealth={}'.format(stealth))
|
||||||
|
|
||||||
self.stealth = stealth
|
self.stealth = stealth
|
||||||
self.onion.stealth = stealth
|
self.onion.stealth = stealth
|
||||||
@ -62,11 +64,11 @@ class OnionShare(object):
|
|||||||
"""
|
"""
|
||||||
Start the onionshare onion service.
|
Start the onionshare onion service.
|
||||||
"""
|
"""
|
||||||
common.log('OnionShare', 'start_onion_service')
|
self.common.log('OnionShare', 'start_onion_service')
|
||||||
|
|
||||||
# Choose a random port
|
# Choose a random port
|
||||||
try:
|
try:
|
||||||
self.port = common.get_available_port(17600, 17650)
|
self.port = self.common.get_available_port(17600, 17650)
|
||||||
except:
|
except:
|
||||||
raise OSError(strings._('no_available_port'))
|
raise OSError(strings._('no_available_port'))
|
||||||
|
|
||||||
@ -75,7 +77,7 @@ class OnionShare(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if self.shutdown_timeout > 0:
|
if self.shutdown_timeout > 0:
|
||||||
self.shutdown_timer = ShutdownTimer(self.shutdown_timeout)
|
self.shutdown_timer = ShutdownTimer(self.common, self.shutdown_timeout)
|
||||||
|
|
||||||
self.onion_host = self.onion.start_onion_service(self.port)
|
self.onion_host = self.onion.start_onion_service(self.port)
|
||||||
|
|
||||||
@ -86,7 +88,7 @@ class OnionShare(object):
|
|||||||
"""
|
"""
|
||||||
Shut everything down and clean up temporary files, etc.
|
Shut everything down and clean up temporary files, etc.
|
||||||
"""
|
"""
|
||||||
common.log('OnionShare', 'cleanup')
|
self.common.log('OnionShare', 'cleanup')
|
||||||
|
|
||||||
# cleanup files
|
# cleanup files
|
||||||
for filename in self.cleanup_filenames:
|
for filename in self.cleanup_filenames:
|
||||||
|
@ -22,7 +22,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
from . import strings, common
|
from . import strings
|
||||||
|
|
||||||
|
|
||||||
class Settings(object):
|
class Settings(object):
|
||||||
@ -32,8 +32,10 @@ class Settings(object):
|
|||||||
which is to attempt to connect automatically using default Tor Browser
|
which is to attempt to connect automatically using default Tor Browser
|
||||||
settings.
|
settings.
|
||||||
"""
|
"""
|
||||||
def __init__(self, config=False):
|
def __init__(self, common, config=False):
|
||||||
common.log('Settings', '__init__')
|
self.common = common
|
||||||
|
|
||||||
|
self.common.log('Settings', '__init__')
|
||||||
|
|
||||||
# Default config
|
# Default config
|
||||||
self.filename = self.build_filename()
|
self.filename = self.build_filename()
|
||||||
@ -43,11 +45,11 @@ class Settings(object):
|
|||||||
if os.path.isfile(config):
|
if os.path.isfile(config):
|
||||||
self.filename = config
|
self.filename = config
|
||||||
else:
|
else:
|
||||||
common.log('Settings', '__init__', 'Supplied config does not exist or is unreadable. Falling back to default location')
|
self.common.log('Settings', '__init__', 'Supplied config does not exist or is unreadable. Falling back to default location')
|
||||||
|
|
||||||
# These are the default settings. They will get overwritten when loading from disk
|
# These are the default settings. They will get overwritten when loading from disk
|
||||||
self.default_settings = {
|
self.default_settings = {
|
||||||
'version': common.get_version(),
|
'version': self.common.version,
|
||||||
'connection_type': 'bundled',
|
'connection_type': 'bundled',
|
||||||
'control_port_address': '127.0.0.1',
|
'control_port_address': '127.0.0.1',
|
||||||
'control_port_port': 9051,
|
'control_port_port': 9051,
|
||||||
@ -110,12 +112,12 @@ class Settings(object):
|
|||||||
"""
|
"""
|
||||||
Load the settings from file.
|
Load the settings from file.
|
||||||
"""
|
"""
|
||||||
common.log('Settings', 'load')
|
self.common.log('Settings', 'load')
|
||||||
|
|
||||||
# If the settings file exists, load it
|
# If the settings file exists, load it
|
||||||
if os.path.exists(self.filename):
|
if os.path.exists(self.filename):
|
||||||
try:
|
try:
|
||||||
common.log('Settings', 'load', 'Trying to load {}'.format(self.filename))
|
self.common.log('Settings', 'load', 'Trying to load {}'.format(self.filename))
|
||||||
with open(self.filename, 'r') as f:
|
with open(self.filename, 'r') as f:
|
||||||
self._settings = json.load(f)
|
self._settings = json.load(f)
|
||||||
self.fill_in_defaults()
|
self.fill_in_defaults()
|
||||||
@ -126,7 +128,7 @@ class Settings(object):
|
|||||||
"""
|
"""
|
||||||
Save settings to file.
|
Save settings to file.
|
||||||
"""
|
"""
|
||||||
common.log('Settings', 'save')
|
self.common.log('Settings', 'save')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.makedirs(os.path.dirname(self.filename))
|
os.makedirs(os.path.dirname(self.filename))
|
||||||
|
@ -41,14 +41,16 @@ class Web(object):
|
|||||||
"""
|
"""
|
||||||
The Web object is the OnionShare web server, powered by flask
|
The Web object is the OnionShare web server, powered by flask
|
||||||
"""
|
"""
|
||||||
def __init__(self, debug, stay_open, gui_mode, receive_mode=False):
|
def __init__(self, common, stay_open, gui_mode, receive_mode=False):
|
||||||
|
self.common = common
|
||||||
|
|
||||||
# The flask app
|
# The flask app
|
||||||
self.app = Flask(__name__,
|
self.app = Flask(__name__,
|
||||||
static_folder=common.get_resource_path('static'),
|
static_folder=common.get_resource_path('static'),
|
||||||
template_folder=common.get_resource_path('templates'))
|
template_folder=common.get_resource_path('templates'))
|
||||||
|
|
||||||
# Debug mode?
|
# Debug mode?
|
||||||
if debug:
|
if self.common.debug:
|
||||||
self.debug_mode()
|
self.debug_mode()
|
||||||
|
|
||||||
# Stay open after the first download?
|
# Stay open after the first download?
|
||||||
@ -107,7 +109,7 @@ class Web(object):
|
|||||||
self.client_cancel = False
|
self.client_cancel = False
|
||||||
|
|
||||||
# shutting down the server only works within the context of flask, so the easiest way to do it is over http
|
# shutting down the server only works within the context of flask, so the easiest way to do it is over http
|
||||||
self.shutdown_slug = common.random_string(16)
|
self.shutdown_slug = self.common.random_string(16)
|
||||||
|
|
||||||
# Define the ewb app routes
|
# Define the ewb app routes
|
||||||
self.common_routes()
|
self.common_routes()
|
||||||
@ -143,7 +145,7 @@ class Web(object):
|
|||||||
file_info=self.file_info,
|
file_info=self.file_info,
|
||||||
filename=os.path.basename(self.zip_filename),
|
filename=os.path.basename(self.zip_filename),
|
||||||
filesize=self.zip_filesize,
|
filesize=self.zip_filesize,
|
||||||
filesize_human=common.human_readable_filesize(self.zip_filesize)))
|
filesize_human=self.common.human_readable_filesize(self.zip_filesize)))
|
||||||
return self.add_security_headers(r)
|
return self.add_security_headers(r)
|
||||||
|
|
||||||
@self.app.route("/<slug_candidate>/download")
|
@self.app.route("/<slug_candidate>/download")
|
||||||
@ -206,10 +208,9 @@ class Web(object):
|
|||||||
percent = (1.0 * downloaded_bytes / self.zip_filesize) * 100
|
percent = (1.0 * downloaded_bytes / self.zip_filesize) * 100
|
||||||
|
|
||||||
# only output to stdout if running onionshare in CLI mode, or if using Linux (#203, #304)
|
# only output to stdout if running onionshare in CLI mode, or if using Linux (#203, #304)
|
||||||
plat = common.get_platform()
|
if not self.gui_mode or self.common.platform == 'Linux' or self.common.platform == 'BSD':
|
||||||
if not self.gui_mode or plat == 'Linux' or plat == 'BSD':
|
|
||||||
sys.stdout.write(
|
sys.stdout.write(
|
||||||
"\r{0:s}, {1:.2f}% ".format(common.human_readable_filesize(downloaded_bytes), percent))
|
"\r{0:s}, {1:.2f}% ".format(self.common.human_readable_filesize(downloaded_bytes), percent))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
self.add_request(self.REQUEST_PROGRESS, path, {'id': download_id, 'bytes': downloaded_bytes})
|
self.add_request(self.REQUEST_PROGRESS, path, {'id': download_id, 'bytes': downloaded_bytes})
|
||||||
@ -224,7 +225,7 @@ class Web(object):
|
|||||||
|
|
||||||
fp.close()
|
fp.close()
|
||||||
|
|
||||||
if common.get_platform() != 'Darwin':
|
if self.common.platform != 'Darwin':
|
||||||
sys.stdout.write("\n")
|
sys.stdout.write("\n")
|
||||||
|
|
||||||
# Download is finished
|
# Download is finished
|
||||||
@ -315,17 +316,17 @@ class Web(object):
|
|||||||
}
|
}
|
||||||
if os.path.isfile(filename):
|
if os.path.isfile(filename):
|
||||||
info['size'] = os.path.getsize(filename)
|
info['size'] = os.path.getsize(filename)
|
||||||
info['size_human'] = common.human_readable_filesize(info['size'])
|
info['size_human'] = self.common.human_readable_filesize(info['size'])
|
||||||
self.file_info['files'].append(info)
|
self.file_info['files'].append(info)
|
||||||
if os.path.isdir(filename):
|
if os.path.isdir(filename):
|
||||||
info['size'] = common.dir_size(filename)
|
info['size'] = self.common.dir_size(filename)
|
||||||
info['size_human'] = common.human_readable_filesize(info['size'])
|
info['size_human'] = self.common.human_readable_filesize(info['size'])
|
||||||
self.file_info['dirs'].append(info)
|
self.file_info['dirs'].append(info)
|
||||||
self.file_info['files'] = sorted(self.file_info['files'], key=lambda k: k['basename'])
|
self.file_info['files'] = sorted(self.file_info['files'], key=lambda k: k['basename'])
|
||||||
self.file_info['dirs'] = sorted(self.file_info['dirs'], key=lambda k: k['basename'])
|
self.file_info['dirs'] = sorted(self.file_info['dirs'], key=lambda k: k['basename'])
|
||||||
|
|
||||||
# zip up the files and folders
|
# zip up the files and folders
|
||||||
z = ZipWriter(processed_size_callback=processed_size_callback)
|
z = ZipWriter(self.common, processed_size_callback=processed_size_callback)
|
||||||
for info in self.file_info['files']:
|
for info in self.file_info['files']:
|
||||||
z.add_file(info['filename'])
|
z.add_file(info['filename'])
|
||||||
for info in self.file_info['dirs']:
|
for info in self.file_info['dirs']:
|
||||||
@ -353,7 +354,7 @@ class Web(object):
|
|||||||
if persistent_slug:
|
if persistent_slug:
|
||||||
self.slug = persistent_slug
|
self.slug = persistent_slug
|
||||||
else:
|
else:
|
||||||
self.slug = common.build_slug()
|
self.slug = self.common.build_slug()
|
||||||
|
|
||||||
def debug_mode(self):
|
def debug_mode(self):
|
||||||
"""
|
"""
|
||||||
@ -424,11 +425,13 @@ class ZipWriter(object):
|
|||||||
with. If a zip_filename is not passed in, it will use the default onionshare
|
with. If a zip_filename is not passed in, it will use the default onionshare
|
||||||
filename.
|
filename.
|
||||||
"""
|
"""
|
||||||
def __init__(self, zip_filename=None, processed_size_callback=None):
|
def __init__(self, common, zip_filename=None, processed_size_callback=None):
|
||||||
|
self.common = common
|
||||||
|
|
||||||
if zip_filename:
|
if zip_filename:
|
||||||
self.zip_filename = zip_filename
|
self.zip_filename = zip_filename
|
||||||
else:
|
else:
|
||||||
self.zip_filename = '{0:s}/onionshare_{1:s}.zip'.format(tempfile.mkdtemp(), common.random_string(4, 6))
|
self.zip_filename = '{0:s}/onionshare_{1:s}.zip'.format(tempfile.mkdtemp(), self.common.random_string(4, 6))
|
||||||
|
|
||||||
self.z = zipfile.ZipFile(self.zip_filename, 'w', allowZip64=True)
|
self.z = zipfile.ZipFile(self.zip_filename, 'w', allowZip64=True)
|
||||||
self.processed_size_callback = processed_size_callback
|
self.processed_size_callback = processed_size_callback
|
||||||
|
@ -22,7 +22,8 @@ import os, sys, platform, argparse
|
|||||||
from .alert import Alert
|
from .alert import Alert
|
||||||
from PyQt5 import QtCore, QtWidgets
|
from PyQt5 import QtCore, QtWidgets
|
||||||
|
|
||||||
from onionshare import strings, common
|
from onionshare import strings
|
||||||
|
from onionshare.common import Common
|
||||||
from onionshare.web import Web
|
from onionshare.web import Web
|
||||||
from onionshare.onion import Onion
|
from onionshare.onion import Onion
|
||||||
from onionshare.onionshare import OnionShare
|
from onionshare.onionshare import OnionShare
|
||||||
@ -35,9 +36,8 @@ class Application(QtWidgets.QApplication):
|
|||||||
This is Qt's QApplication class. It has been overridden to support threads
|
This is Qt's QApplication class. It has been overridden to support threads
|
||||||
and the quick keyboard shortcut.
|
and the quick keyboard shortcut.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self, common):
|
||||||
system = common.get_platform()
|
if common.platform == 'Linux' or common.platform == 'BSD':
|
||||||
if system == 'Linux' or system == 'BSD':
|
|
||||||
self.setAttribute(QtCore.Qt.AA_X11InitThreads, True)
|
self.setAttribute(QtCore.Qt.AA_X11InitThreads, True)
|
||||||
QtWidgets.QApplication.__init__(self, sys.argv)
|
QtWidgets.QApplication.__init__(self, sys.argv)
|
||||||
self.installEventFilter(self)
|
self.installEventFilter(self)
|
||||||
@ -54,12 +54,14 @@ def main():
|
|||||||
"""
|
"""
|
||||||
The main() function implements all of the logic that the GUI version of onionshare uses.
|
The main() function implements all of the logic that the GUI version of onionshare uses.
|
||||||
"""
|
"""
|
||||||
|
common = Common()
|
||||||
|
|
||||||
strings.load_strings(common)
|
strings.load_strings(common)
|
||||||
print(strings._('version_string').format(common.get_version()))
|
print(strings._('version_string').format(common.version))
|
||||||
|
|
||||||
# Start the Qt app
|
# Start the Qt app
|
||||||
global qtapp
|
global qtapp
|
||||||
qtapp = Application()
|
qtapp = Application(common)
|
||||||
|
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
parser = argparse.ArgumentParser(formatter_class=lambda prog: argparse.HelpFormatter(prog,max_help_position=48))
|
parser = argparse.ArgumentParser(formatter_class=lambda prog: argparse.HelpFormatter(prog,max_help_position=48))
|
||||||
@ -84,34 +86,33 @@ def main():
|
|||||||
debug = bool(args.debug)
|
debug = bool(args.debug)
|
||||||
|
|
||||||
# Debug mode?
|
# Debug mode?
|
||||||
if debug:
|
common.debug = debug
|
||||||
common.set_debug(debug)
|
|
||||||
|
|
||||||
# Validation
|
# Validation
|
||||||
if filenames:
|
if filenames:
|
||||||
valid = True
|
valid = True
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
if not os.path.isfile(filename) and not os.path.isdir(filename):
|
if not os.path.isfile(filename) and not os.path.isdir(filename):
|
||||||
Alert(strings._("not_a_file", True).format(filename))
|
Alert(self.common, strings._("not_a_file", True).format(filename))
|
||||||
valid = False
|
valid = False
|
||||||
if not os.access(filename, os.R_OK):
|
if not os.access(filename, os.R_OK):
|
||||||
Alert(strings._("not_a_readable_file", True).format(filename))
|
Alert(self.common, strings._("not_a_readable_file", True).format(filename))
|
||||||
valid = False
|
valid = False
|
||||||
if not valid:
|
if not valid:
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
# Create the Web object
|
# Create the Web object
|
||||||
web = Web(debug, stay_open, True)
|
web = Web(common, stay_open, True)
|
||||||
|
|
||||||
# Start the Onion
|
# Start the Onion
|
||||||
onion = Onion()
|
onion = Onion(common)
|
||||||
|
|
||||||
# Start the OnionShare app
|
# Start the OnionShare app
|
||||||
app = OnionShare(onion, local_only, stay_open, shutdown_timeout)
|
app = OnionShare(common, onion, local_only, stay_open, shutdown_timeout)
|
||||||
|
|
||||||
# Launch the gui
|
# Launch the gui
|
||||||
web.stay_open = stay_open
|
web.stay_open = stay_open
|
||||||
gui = OnionShareGui(web, onion, qtapp, app, filenames, config)
|
gui = OnionShareGui(common, web, onion, qtapp, app, filenames, config)
|
||||||
|
|
||||||
# Clean up when app quits
|
# Clean up when app quits
|
||||||
def shutdown():
|
def shutdown():
|
||||||
|
@ -19,18 +19,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
"""
|
"""
|
||||||
from PyQt5 import QtCore, QtWidgets, QtGui
|
from PyQt5 import QtCore, QtWidgets, QtGui
|
||||||
|
|
||||||
from onionshare import common
|
|
||||||
|
|
||||||
class Alert(QtWidgets.QMessageBox):
|
class Alert(QtWidgets.QMessageBox):
|
||||||
"""
|
"""
|
||||||
An alert box dialog.
|
An alert box dialog.
|
||||||
"""
|
"""
|
||||||
def __init__(self, message, icon=QtWidgets.QMessageBox.NoIcon, buttons=QtWidgets.QMessageBox.Ok, autostart=True):
|
def __init__(self, common, message, icon=QtWidgets.QMessageBox.NoIcon, buttons=QtWidgets.QMessageBox.Ok, autostart=True):
|
||||||
super(Alert, self).__init__(None)
|
super(Alert, self).__init__(None)
|
||||||
common.log('Alert', '__init__')
|
|
||||||
|
self.common = common
|
||||||
|
|
||||||
|
self.common.log('Alert', '__init__')
|
||||||
|
|
||||||
self.setWindowTitle("OnionShare")
|
self.setWindowTitle("OnionShare")
|
||||||
self.setWindowIcon(QtGui.QIcon(common.get_resource_path('images/logo.png')))
|
self.setWindowIcon(QtGui.QIcon(self.common.get_resource_path('images/logo.png')))
|
||||||
self.setText(message)
|
self.setText(message)
|
||||||
self.setIcon(icon)
|
self.setIcon(icon)
|
||||||
self.setStandardButtons(buttons)
|
self.setStandardButtons(buttons)
|
||||||
|
@ -21,11 +21,13 @@ import time
|
|||||||
|
|
||||||
from PyQt5 import QtCore, QtWidgets
|
from PyQt5 import QtCore, QtWidgets
|
||||||
|
|
||||||
from onionshare import strings, common
|
from onionshare import strings
|
||||||
|
|
||||||
class Download(object):
|
class Download(object):
|
||||||
|
|
||||||
def __init__(self, download_id, total_bytes):
|
def __init__(self, common, download_id, total_bytes):
|
||||||
|
self.common = common
|
||||||
|
|
||||||
self.download_id = download_id
|
self.download_id = download_id
|
||||||
self.started = time.time()
|
self.started = time.time()
|
||||||
self.total_bytes = total_bytes
|
self.total_bytes = total_bytes
|
||||||
@ -64,7 +66,7 @@ class Download(object):
|
|||||||
self.progress_bar.setValue(downloaded_bytes)
|
self.progress_bar.setValue(downloaded_bytes)
|
||||||
if downloaded_bytes == self.progress_bar.total_bytes:
|
if downloaded_bytes == self.progress_bar.total_bytes:
|
||||||
pb_fmt = strings._('gui_download_progress_complete').format(
|
pb_fmt = strings._('gui_download_progress_complete').format(
|
||||||
common.format_seconds(time.time() - self.started))
|
self.common.format_seconds(time.time() - self.started))
|
||||||
else:
|
else:
|
||||||
elapsed = time.time() - self.started
|
elapsed = time.time() - self.started
|
||||||
if elapsed < 10:
|
if elapsed < 10:
|
||||||
@ -72,10 +74,10 @@ class Download(object):
|
|||||||
# This prevents a "Windows copy dialog"-esque experience at
|
# This prevents a "Windows copy dialog"-esque experience at
|
||||||
# the beginning of the download.
|
# the beginning of the download.
|
||||||
pb_fmt = strings._('gui_download_progress_starting').format(
|
pb_fmt = strings._('gui_download_progress_starting').format(
|
||||||
common.human_readable_filesize(downloaded_bytes))
|
self.common.human_readable_filesize(downloaded_bytes))
|
||||||
else:
|
else:
|
||||||
pb_fmt = strings._('gui_download_progress_eta').format(
|
pb_fmt = strings._('gui_download_progress_eta').format(
|
||||||
common.human_readable_filesize(downloaded_bytes),
|
self.common.human_readable_filesize(downloaded_bytes),
|
||||||
self.estimated_time_remaining)
|
self.estimated_time_remaining)
|
||||||
|
|
||||||
self.progress_bar.setFormat(pb_fmt)
|
self.progress_bar.setFormat(pb_fmt)
|
||||||
@ -85,7 +87,7 @@ class Download(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def estimated_time_remaining(self):
|
def estimated_time_remaining(self):
|
||||||
return common.estimated_time_remaining(self.downloaded_bytes,
|
return self.common.estimated_time_remaining(self.downloaded_bytes,
|
||||||
self.total_bytes,
|
self.total_bytes,
|
||||||
self.started)
|
self.started)
|
||||||
|
|
||||||
@ -95,8 +97,11 @@ class Downloads(QtWidgets.QWidget):
|
|||||||
The downloads chunk of the GUI. This lists all of the active download
|
The downloads chunk of the GUI. This lists all of the active download
|
||||||
progress bars.
|
progress bars.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self, common):
|
||||||
super(Downloads, self).__init__()
|
super(Downloads, self).__init__()
|
||||||
|
|
||||||
|
self.common = common
|
||||||
|
|
||||||
self.downloads = {}
|
self.downloads = {}
|
||||||
self.layout = QtWidgets.QVBoxLayout()
|
self.layout = QtWidgets.QVBoxLayout()
|
||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
@ -108,7 +113,7 @@ class Downloads(QtWidgets.QWidget):
|
|||||||
self.parent().show()
|
self.parent().show()
|
||||||
|
|
||||||
# add it to the list
|
# add it to the list
|
||||||
download = Download(download_id, total_bytes)
|
download = Download(self.common, download_id, total_bytes)
|
||||||
self.downloads[download_id] = download
|
self.downloads[download_id] = download
|
||||||
self.layout.insertWidget(-1, download.progress_bar)
|
self.layout.insertWidget(-1, download.progress_bar)
|
||||||
|
|
||||||
|
@ -21,21 +21,24 @@ import os
|
|||||||
from PyQt5 import QtCore, QtWidgets, QtGui
|
from PyQt5 import QtCore, QtWidgets, QtGui
|
||||||
from .alert import Alert
|
from .alert import Alert
|
||||||
|
|
||||||
from onionshare import strings, common
|
from onionshare import strings
|
||||||
|
|
||||||
class DropHereLabel(QtWidgets.QLabel):
|
class DropHereLabel(QtWidgets.QLabel):
|
||||||
"""
|
"""
|
||||||
When there are no files or folders in the FileList yet, display the
|
When there are no files or folders in the FileList yet, display the
|
||||||
'drop files here' message and graphic.
|
'drop files here' message and graphic.
|
||||||
"""
|
"""
|
||||||
def __init__(self, parent, image=False):
|
def __init__(self, common, parent, image=False):
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
super(DropHereLabel, self).__init__(parent=parent)
|
super(DropHereLabel, self).__init__(parent=parent)
|
||||||
|
|
||||||
|
self.common = common
|
||||||
|
|
||||||
self.setAcceptDrops(True)
|
self.setAcceptDrops(True)
|
||||||
self.setAlignment(QtCore.Qt.AlignCenter)
|
self.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
|
|
||||||
if image:
|
if image:
|
||||||
self.setPixmap(QtGui.QPixmap.fromImage(QtGui.QImage(common.get_resource_path('images/logo_transparent.png'))))
|
self.setPixmap(QtGui.QPixmap.fromImage(QtGui.QImage(self.common.get_resource_path('images/logo_transparent.png'))))
|
||||||
else:
|
else:
|
||||||
self.setText(strings._('gui_drag_and_drop', True))
|
self.setText(strings._('gui_drag_and_drop', True))
|
||||||
self.setStyleSheet('color: #999999;')
|
self.setStyleSheet('color: #999999;')
|
||||||
@ -53,9 +56,12 @@ class DropCountLabel(QtWidgets.QLabel):
|
|||||||
While dragging files over the FileList, this counter displays the
|
While dragging files over the FileList, this counter displays the
|
||||||
number of files you're dragging.
|
number of files you're dragging.
|
||||||
"""
|
"""
|
||||||
def __init__(self, parent):
|
def __init__(self, common, parent):
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
super(DropCountLabel, self).__init__(parent=parent)
|
super(DropCountLabel, self).__init__(parent=parent)
|
||||||
|
|
||||||
|
self.common = common
|
||||||
|
|
||||||
self.setAcceptDrops(True)
|
self.setAcceptDrops(True)
|
||||||
self.setAlignment(QtCore.Qt.AlignCenter)
|
self.setAlignment(QtCore.Qt.AlignCenter)
|
||||||
self.setText(strings._('gui_drag_and_drop', True))
|
self.setText(strings._('gui_drag_and_drop', True))
|
||||||
@ -74,16 +80,19 @@ class FileList(QtWidgets.QListWidget):
|
|||||||
files_dropped = QtCore.pyqtSignal()
|
files_dropped = QtCore.pyqtSignal()
|
||||||
files_updated = QtCore.pyqtSignal()
|
files_updated = QtCore.pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, common, parent=None):
|
||||||
super(FileList, self).__init__(parent)
|
super(FileList, self).__init__(parent)
|
||||||
|
|
||||||
|
self.common = common
|
||||||
|
|
||||||
self.setAcceptDrops(True)
|
self.setAcceptDrops(True)
|
||||||
self.setIconSize(QtCore.QSize(32, 32))
|
self.setIconSize(QtCore.QSize(32, 32))
|
||||||
self.setSortingEnabled(True)
|
self.setSortingEnabled(True)
|
||||||
self.setMinimumHeight(205)
|
self.setMinimumHeight(205)
|
||||||
self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||||
self.drop_here_image = DropHereLabel(self, True)
|
self.drop_here_image = DropHereLabel(self.common, self, True)
|
||||||
self.drop_here_text = DropHereLabel(self, False)
|
self.drop_here_text = DropHereLabel(self.common, self, False)
|
||||||
self.drop_count = DropCountLabel(self)
|
self.drop_count = DropCountLabel(self.common, self)
|
||||||
self.resizeEvent(None)
|
self.resizeEvent(None)
|
||||||
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
|
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
|
||||||
|
|
||||||
@ -206,7 +215,7 @@ class FileList(QtWidgets.QListWidget):
|
|||||||
|
|
||||||
if filename not in filenames:
|
if filename not in filenames:
|
||||||
if not os.access(filename, os.R_OK):
|
if not os.access(filename, os.R_OK):
|
||||||
Alert(strings._("not_a_readable_file", True).format(filename))
|
Alert(self.common, strings._("not_a_readable_file", True).format(filename))
|
||||||
return
|
return
|
||||||
|
|
||||||
fileinfo = QtCore.QFileInfo(filename)
|
fileinfo = QtCore.QFileInfo(filename)
|
||||||
@ -215,10 +224,10 @@ class FileList(QtWidgets.QListWidget):
|
|||||||
|
|
||||||
if os.path.isfile(filename):
|
if os.path.isfile(filename):
|
||||||
size_bytes = fileinfo.size()
|
size_bytes = fileinfo.size()
|
||||||
size_readable = common.human_readable_filesize(size_bytes)
|
size_readable = self.common.human_readable_filesize(size_bytes)
|
||||||
else:
|
else:
|
||||||
size_bytes = common.dir_size(filename)
|
size_bytes = self.common.dir_size(filename)
|
||||||
size_readable = common.human_readable_filesize(size_bytes)
|
size_readable = self.common.human_readable_filesize(size_bytes)
|
||||||
|
|
||||||
# Create a new item
|
# Create a new item
|
||||||
item = QtWidgets.QListWidgetItem()
|
item = QtWidgets.QListWidgetItem()
|
||||||
@ -245,7 +254,7 @@ class FileList(QtWidgets.QListWidget):
|
|||||||
item.item_button = QtWidgets.QPushButton()
|
item.item_button = QtWidgets.QPushButton()
|
||||||
item.item_button.setDefault(False)
|
item.item_button.setDefault(False)
|
||||||
item.item_button.setFlat(True)
|
item.item_button.setFlat(True)
|
||||||
item.item_button.setIcon( QtGui.QIcon(common.get_resource_path('images/file_delete.png')) )
|
item.item_button.setIcon( QtGui.QIcon(self.common.get_resource_path('images/file_delete.png')) )
|
||||||
item.item_button.clicked.connect(delete_item)
|
item.item_button.clicked.connect(delete_item)
|
||||||
item.item_button.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
item.item_button.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
|
||||||
@ -277,12 +286,15 @@ class FileSelection(QtWidgets.QVBoxLayout):
|
|||||||
The list of files and folders in the GUI, as well as buttons to add and
|
The list of files and folders in the GUI, as well as buttons to add and
|
||||||
delete the files and folders.
|
delete the files and folders.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self, common):
|
||||||
super(FileSelection, self).__init__()
|
super(FileSelection, self).__init__()
|
||||||
|
|
||||||
|
self.common = common
|
||||||
|
|
||||||
self.server_on = False
|
self.server_on = False
|
||||||
|
|
||||||
# File list
|
# File list
|
||||||
self.file_list = FileList()
|
self.file_list = FileList(self.common)
|
||||||
self.file_list.itemSelectionChanged.connect(self.update)
|
self.file_list.itemSelectionChanged.connect(self.update)
|
||||||
self.file_list.files_dropped.connect(self.update)
|
self.file_list.files_dropped.connect(self.update)
|
||||||
self.file_list.files_updated.connect(self.update)
|
self.file_list.files_updated.connect(self.update)
|
||||||
|
@ -24,7 +24,7 @@ import queue
|
|||||||
from PyQt5 import QtCore, QtWidgets, QtGui
|
from PyQt5 import QtCore, QtWidgets, QtGui
|
||||||
|
|
||||||
from onionshare import strings, common
|
from onionshare import strings, common
|
||||||
from onionshare.common import ShutdownTimer
|
from onionshare.common import Common, ShutdownTimer
|
||||||
from onionshare.settings import Settings
|
from onionshare.settings import Settings
|
||||||
from onionshare.onion import *
|
from onionshare.onion import *
|
||||||
|
|
||||||
@ -47,12 +47,13 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
starting_server_step3 = QtCore.pyqtSignal()
|
starting_server_step3 = QtCore.pyqtSignal()
|
||||||
starting_server_error = QtCore.pyqtSignal(str)
|
starting_server_error = QtCore.pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, web, onion, qtapp, app, filenames, config=False):
|
def __init__(self, common, web, onion, qtapp, app, filenames, config=False):
|
||||||
super(OnionShareGui, self).__init__()
|
super(OnionShareGui, self).__init__()
|
||||||
|
|
||||||
self._initSystemTray()
|
self.common = common
|
||||||
|
self.common.log('OnionShareGui', '__init__')
|
||||||
|
|
||||||
common.log('OnionShareGui', '__init__')
|
self._initSystemTray()
|
||||||
|
|
||||||
self.web = web
|
self.web = web
|
||||||
self.onion = onion
|
self.onion = onion
|
||||||
@ -60,22 +61,22 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
self.app = app
|
self.app = app
|
||||||
|
|
||||||
self.setWindowTitle('OnionShare')
|
self.setWindowTitle('OnionShare')
|
||||||
self.setWindowIcon(QtGui.QIcon(common.get_resource_path('images/logo.png')))
|
self.setWindowIcon(QtGui.QIcon(self.common.get_resource_path('images/logo.png')))
|
||||||
self.setMinimumWidth(430)
|
self.setMinimumWidth(430)
|
||||||
|
|
||||||
# Load settings
|
# Load settings
|
||||||
self.config = config
|
self.config = config
|
||||||
self.settings = Settings(self.config)
|
self.settings = Settings(self.common, self.config)
|
||||||
self.settings.load()
|
self.settings.load()
|
||||||
|
|
||||||
# File selection
|
# File selection
|
||||||
self.file_selection = FileSelection()
|
self.file_selection = FileSelection(self.common)
|
||||||
if filenames:
|
if filenames:
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
self.file_selection.file_list.add_file(filename)
|
self.file_selection.file_list.add_file(filename)
|
||||||
|
|
||||||
# Server status
|
# Server status
|
||||||
self.server_status = ServerStatus(self.qtapp, self.app, self.web, self.file_selection, self.settings)
|
self.server_status = ServerStatus(self.common, self.qtapp, self.app, self.web, self.file_selection, self.settings)
|
||||||
self.server_status.server_started.connect(self.file_selection.server_started)
|
self.server_status.server_started.connect(self.file_selection.server_started)
|
||||||
self.server_status.server_started.connect(self.start_server)
|
self.server_status.server_started.connect(self.start_server)
|
||||||
self.server_status.server_started.connect(self.update_server_status_indicator)
|
self.server_status.server_started.connect(self.update_server_status_indicator)
|
||||||
@ -107,7 +108,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
self.filesize_warning.hide()
|
self.filesize_warning.hide()
|
||||||
|
|
||||||
# Downloads
|
# Downloads
|
||||||
self.downloads = Downloads()
|
self.downloads = Downloads(self.common)
|
||||||
self.downloads_container = QtWidgets.QScrollArea()
|
self.downloads_container = QtWidgets.QScrollArea()
|
||||||
self.downloads_container.setWidget(self.downloads)
|
self.downloads_container.setWidget(self.downloads)
|
||||||
self.downloads_container.setWidgetResizable(True)
|
self.downloads_container.setWidgetResizable(True)
|
||||||
@ -147,13 +148,13 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
self.settings_button.setDefault(False)
|
self.settings_button.setDefault(False)
|
||||||
self.settings_button.setFlat(True)
|
self.settings_button.setFlat(True)
|
||||||
self.settings_button.setFixedWidth(40)
|
self.settings_button.setFixedWidth(40)
|
||||||
self.settings_button.setIcon( QtGui.QIcon(common.get_resource_path('images/settings.png')) )
|
self.settings_button.setIcon( QtGui.QIcon(self.common.get_resource_path('images/settings.png')) )
|
||||||
self.settings_button.clicked.connect(self.open_settings)
|
self.settings_button.clicked.connect(self.open_settings)
|
||||||
|
|
||||||
# Server status indicator on the status bar
|
# Server status indicator on the status bar
|
||||||
self.server_status_image_stopped = QtGui.QImage(common.get_resource_path('images/server_stopped.png'))
|
self.server_status_image_stopped = QtGui.QImage(self.common.get_resource_path('images/server_stopped.png'))
|
||||||
self.server_status_image_working = QtGui.QImage(common.get_resource_path('images/server_working.png'))
|
self.server_status_image_working = QtGui.QImage(self.common.get_resource_path('images/server_working.png'))
|
||||||
self.server_status_image_started = QtGui.QImage(common.get_resource_path('images/server_started.png'))
|
self.server_status_image_started = QtGui.QImage(self.common.get_resource_path('images/server_started.png'))
|
||||||
self.server_status_image_label = QtWidgets.QLabel()
|
self.server_status_image_label = QtWidgets.QLabel()
|
||||||
self.server_status_image_label.setFixedWidth(20)
|
self.server_status_image_label.setFixedWidth(20)
|
||||||
self.server_status_label = QtWidgets.QLabel()
|
self.server_status_label = QtWidgets.QLabel()
|
||||||
@ -221,7 +222,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
self.timer.timeout.connect(self.check_for_requests)
|
self.timer.timeout.connect(self.check_for_requests)
|
||||||
|
|
||||||
# Start the "Connecting to Tor" dialog, which calls onion.connect()
|
# Start the "Connecting to Tor" dialog, which calls onion.connect()
|
||||||
tor_con = TorConnectionDialog(self.qtapp, self.settings, self.onion)
|
tor_con = TorConnectionDialog(self.common, self.qtapp, self.settings, self.onion)
|
||||||
tor_con.canceled.connect(self._tor_connection_canceled)
|
tor_con.canceled.connect(self._tor_connection_canceled)
|
||||||
tor_con.open_settings.connect(self._tor_connection_open_settings)
|
tor_con.open_settings.connect(self._tor_connection_open_settings)
|
||||||
tor_con.start()
|
tor_con.start()
|
||||||
@ -244,7 +245,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
for index in range(self.file_selection.file_list.count()):
|
for index in range(self.file_selection.file_list.count()):
|
||||||
item = self.file_selection.file_list.item(index)
|
item = self.file_selection.file_list.item(index)
|
||||||
total_size_bytes += item.size_bytes
|
total_size_bytes += item.size_bytes
|
||||||
total_size_readable = common.human_readable_filesize(total_size_bytes)
|
total_size_readable = self.common.human_readable_filesize(total_size_bytes)
|
||||||
|
|
||||||
if file_count > 1:
|
if file_count > 1:
|
||||||
self.info_label.setText(strings._('gui_file_info', True).format(file_count, total_size_readable))
|
self.info_label.setText(strings._('gui_file_info', True).format(file_count, total_size_readable))
|
||||||
@ -259,7 +260,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
self.adjustSize()
|
self.adjustSize()
|
||||||
|
|
||||||
def update_server_status_indicator(self):
|
def update_server_status_indicator(self):
|
||||||
common.log('OnionShareGui', 'update_server_status_indicator')
|
self.common.log('OnionShareGui', 'update_server_status_indicator')
|
||||||
|
|
||||||
# Set the status image
|
# Set the status image
|
||||||
if self.server_status.status == self.server_status.STATUS_STOPPED:
|
if self.server_status.status == self.server_status.STATUS_STOPPED:
|
||||||
@ -273,8 +274,6 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
self.server_status_label.setText(strings._('gui_status_indicator_started', True))
|
self.server_status_label.setText(strings._('gui_status_indicator_started', True))
|
||||||
|
|
||||||
def _initSystemTray(self):
|
def _initSystemTray(self):
|
||||||
system = common.get_platform()
|
|
||||||
|
|
||||||
menu = QtWidgets.QMenu()
|
menu = QtWidgets.QMenu()
|
||||||
self.settingsAction = menu.addAction(strings._('gui_settings_window_title', True))
|
self.settingsAction = menu.addAction(strings._('gui_settings_window_title', True))
|
||||||
self.settingsAction.triggered.connect(self.open_settings)
|
self.settingsAction.triggered.connect(self.open_settings)
|
||||||
@ -285,10 +284,10 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
|
|
||||||
self.systemTray = QtWidgets.QSystemTrayIcon(self)
|
self.systemTray = QtWidgets.QSystemTrayIcon(self)
|
||||||
# The convention is Mac systray icons are always grayscale
|
# The convention is Mac systray icons are always grayscale
|
||||||
if system == 'Darwin':
|
if self.common.platform == 'Darwin':
|
||||||
self.systemTray.setIcon(QtGui.QIcon(common.get_resource_path('images/logo_grayscale.png')))
|
self.systemTray.setIcon(QtGui.QIcon(self.common.get_resource_path('images/logo_grayscale.png')))
|
||||||
else:
|
else:
|
||||||
self.systemTray.setIcon(QtGui.QIcon(common.get_resource_path('images/logo.png')))
|
self.systemTray.setIcon(QtGui.QIcon(self.common.get_resource_path('images/logo.png')))
|
||||||
self.systemTray.setContextMenu(menu)
|
self.systemTray.setContextMenu(menu)
|
||||||
self.systemTray.show()
|
self.systemTray.show()
|
||||||
|
|
||||||
@ -297,10 +296,10 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
If the user cancels before Tor finishes connecting, ask if they want to
|
If the user cancels before Tor finishes connecting, ask if they want to
|
||||||
quit, or open settings.
|
quit, or open settings.
|
||||||
"""
|
"""
|
||||||
common.log('OnionShareGui', '_tor_connection_canceled')
|
self.common.log('OnionShareGui', '_tor_connection_canceled')
|
||||||
|
|
||||||
def ask():
|
def ask():
|
||||||
a = Alert(strings._('gui_tor_connection_ask', True), QtWidgets.QMessageBox.Question, buttons=QtWidgets.QMessageBox.NoButton, autostart=False)
|
a = Alert(self.common, strings._('gui_tor_connection_ask', True), QtWidgets.QMessageBox.Question, buttons=QtWidgets.QMessageBox.NoButton, autostart=False)
|
||||||
settings_button = QtWidgets.QPushButton(strings._('gui_tor_connection_ask_open_settings', True))
|
settings_button = QtWidgets.QPushButton(strings._('gui_tor_connection_ask_open_settings', True))
|
||||||
quit_button = QtWidgets.QPushButton(strings._('gui_tor_connection_ask_quit', True))
|
quit_button = QtWidgets.QPushButton(strings._('gui_tor_connection_ask_quit', True))
|
||||||
a.addButton(settings_button, QtWidgets.QMessageBox.AcceptRole)
|
a.addButton(settings_button, QtWidgets.QMessageBox.AcceptRole)
|
||||||
@ -310,12 +309,12 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
|
|
||||||
if a.clickedButton() == settings_button:
|
if a.clickedButton() == settings_button:
|
||||||
# Open settings
|
# Open settings
|
||||||
common.log('OnionShareGui', '_tor_connection_canceled', 'Settings button clicked')
|
self.common.log('OnionShareGui', '_tor_connection_canceled', 'Settings button clicked')
|
||||||
self.open_settings()
|
self.open_settings()
|
||||||
|
|
||||||
if a.clickedButton() == quit_button:
|
if a.clickedButton() == quit_button:
|
||||||
# Quit
|
# Quit
|
||||||
common.log('OnionShareGui', '_tor_connection_canceled', 'Quit button clicked')
|
self.common.log('OnionShareGui', '_tor_connection_canceled', 'Quit button clicked')
|
||||||
|
|
||||||
# Wait 1ms for the event loop to finish, then quit
|
# Wait 1ms for the event loop to finish, then quit
|
||||||
QtCore.QTimer.singleShot(1, self.qtapp.quit)
|
QtCore.QTimer.singleShot(1, self.qtapp.quit)
|
||||||
@ -327,7 +326,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
"""
|
"""
|
||||||
The TorConnectionDialog wants to open the Settings dialog
|
The TorConnectionDialog wants to open the Settings dialog
|
||||||
"""
|
"""
|
||||||
common.log('OnionShareGui', '_tor_connection_open_settings')
|
self.common.log('OnionShareGui', '_tor_connection_open_settings')
|
||||||
|
|
||||||
# Wait 1ms for the event loop to finish closing the TorConnectionDialog
|
# Wait 1ms for the event loop to finish closing the TorConnectionDialog
|
||||||
QtCore.QTimer.singleShot(1, self.open_settings)
|
QtCore.QTimer.singleShot(1, self.open_settings)
|
||||||
@ -336,10 +335,10 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
"""
|
"""
|
||||||
Open the SettingsDialog.
|
Open the SettingsDialog.
|
||||||
"""
|
"""
|
||||||
common.log('OnionShareGui', 'open_settings')
|
self.common.log('OnionShareGui', 'open_settings')
|
||||||
|
|
||||||
def reload_settings():
|
def reload_settings():
|
||||||
common.log('OnionShareGui', 'open_settings', 'settings have changed, reloading')
|
self.common.log('OnionShareGui', 'open_settings', 'settings have changed, reloading')
|
||||||
self.settings.load()
|
self.settings.load()
|
||||||
# We might've stopped the main requests timer if a Tor connection failed.
|
# We might've stopped the main requests timer if a Tor connection failed.
|
||||||
# If we've reloaded settings, we probably succeeded in obtaining a new
|
# If we've reloaded settings, we probably succeeded in obtaining a new
|
||||||
@ -356,7 +355,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
if not self.settings.get('shutdown_timeout'):
|
if not self.settings.get('shutdown_timeout'):
|
||||||
self.server_status.shutdown_timeout_container.hide()
|
self.server_status.shutdown_timeout_container.hide()
|
||||||
|
|
||||||
d = SettingsDialog(self.onion, self.qtapp, self.config)
|
d = SettingsDialog(self.common, self.onion, self.qtapp, self.config)
|
||||||
d.settings_saved.connect(reload_settings)
|
d.settings_saved.connect(reload_settings)
|
||||||
d.exec_()
|
d.exec_()
|
||||||
|
|
||||||
@ -368,7 +367,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
Start the onionshare server. This uses multiple threads to start the Tor onion
|
Start the onionshare server. This uses multiple threads to start the Tor onion
|
||||||
server and the web app.
|
server and the web app.
|
||||||
"""
|
"""
|
||||||
common.log('OnionShareGui', 'start_server')
|
self.common.log('OnionShareGui', 'start_server')
|
||||||
|
|
||||||
self.set_server_active(True)
|
self.set_server_active(True)
|
||||||
|
|
||||||
@ -405,8 +404,8 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
# wait for modules in thread to load, preventing a thread-related cx_Freeze crash
|
# wait for modules in thread to load, preventing a thread-related cx_Freeze crash
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
|
|
||||||
common.log('OnionshareGui', 'start_server', 'Starting an onion thread')
|
self.common.log('OnionshareGui', 'start_server', 'Starting an onion thread')
|
||||||
self.t = OnionThread(function=start_onion_service, kwargs={'self': self})
|
self.t = OnionThread(self.common, function=start_onion_service, kwargs={'self': self})
|
||||||
self.t.daemon = True
|
self.t.daemon = True
|
||||||
self.t.start()
|
self.t.start()
|
||||||
|
|
||||||
@ -414,7 +413,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
"""
|
"""
|
||||||
Step 2 in starting the onionshare server. Zipping up files.
|
Step 2 in starting the onionshare server. Zipping up files.
|
||||||
"""
|
"""
|
||||||
common.log('OnionShareGui', 'start_server_step2')
|
self.common.log('OnionShareGui', 'start_server_step2')
|
||||||
|
|
||||||
# add progress bar to the status bar, indicating the crunching of files.
|
# add progress bar to the status bar, indicating the crunching of files.
|
||||||
self._zip_progress_bar = ZipProgressBar(0)
|
self._zip_progress_bar = ZipProgressBar(0)
|
||||||
@ -451,7 +450,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
Step 3 in starting the onionshare server. This displays the large filesize
|
Step 3 in starting the onionshare server. This displays the large filesize
|
||||||
warning, if applicable.
|
warning, if applicable.
|
||||||
"""
|
"""
|
||||||
common.log('OnionShareGui', 'start_server_step3')
|
self.common.log('OnionShareGui', 'start_server_step3')
|
||||||
|
|
||||||
# Remove zip progress bar
|
# Remove zip progress bar
|
||||||
if self._zip_progress_bar is not None:
|
if self._zip_progress_bar is not None:
|
||||||
@ -469,7 +468,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
self.timeout = now.secsTo(self.server_status.timeout)
|
self.timeout = now.secsTo(self.server_status.timeout)
|
||||||
# Set the shutdown timeout value
|
# Set the shutdown timeout value
|
||||||
if self.timeout > 0:
|
if self.timeout > 0:
|
||||||
self.app.shutdown_timer = ShutdownTimer(self.timeout)
|
self.app.shutdown_timer = ShutdownTimer(self.common, self.timeout)
|
||||||
self.app.shutdown_timer.start()
|
self.app.shutdown_timer.start()
|
||||||
# The timeout has actually already passed since the user clicked Start. Probably the Onion service took too long to start.
|
# The timeout has actually already passed since the user clicked Start. Probably the Onion service took too long to start.
|
||||||
else:
|
else:
|
||||||
@ -480,11 +479,11 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
"""
|
"""
|
||||||
If there's an error when trying to start the onion service
|
If there's an error when trying to start the onion service
|
||||||
"""
|
"""
|
||||||
common.log('OnionShareGui', 'start_server_error')
|
self.common.log('OnionShareGui', 'start_server_error')
|
||||||
|
|
||||||
self.set_server_active(False)
|
self.set_server_active(False)
|
||||||
|
|
||||||
Alert(error, QtWidgets.QMessageBox.Warning)
|
Alert(self.common, error, QtWidgets.QMessageBox.Warning)
|
||||||
self.server_status.stop_server()
|
self.server_status.stop_server()
|
||||||
if self._zip_progress_bar is not None:
|
if self._zip_progress_bar is not None:
|
||||||
self.status_bar.removeWidget(self._zip_progress_bar)
|
self.status_bar.removeWidget(self._zip_progress_bar)
|
||||||
@ -503,7 +502,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
"""
|
"""
|
||||||
Stop the onionshare server.
|
Stop the onionshare server.
|
||||||
"""
|
"""
|
||||||
common.log('OnionShareGui', 'stop_server')
|
self.common.log('OnionShareGui', 'stop_server')
|
||||||
|
|
||||||
if self.server_status.status != self.server_status.STATUS_STOPPED:
|
if self.server_status.status != self.server_status.STATUS_STOPPED:
|
||||||
try:
|
try:
|
||||||
@ -527,13 +526,12 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
"""
|
"""
|
||||||
Check for updates in a new thread, if enabled.
|
Check for updates in a new thread, if enabled.
|
||||||
"""
|
"""
|
||||||
system = common.get_platform()
|
if self.common.platform == 'Windows' or self.common.platform == 'Darwin':
|
||||||
if system == 'Windows' or system == 'Darwin':
|
|
||||||
if self.settings.get('use_autoupdate'):
|
if self.settings.get('use_autoupdate'):
|
||||||
def update_available(update_url, installed_version, latest_version):
|
def update_available(update_url, installed_version, latest_version):
|
||||||
Alert(strings._("update_available", True).format(update_url, installed_version, latest_version))
|
Alert(self.common, strings._("update_available", True).format(update_url, installed_version, latest_version))
|
||||||
|
|
||||||
self.update_thread = UpdateThread(self.onion, self.config)
|
self.update_thread = UpdateThread(self.common, self.onion, self.config)
|
||||||
self.update_thread.update_available.connect(update_available)
|
self.update_thread.update_available.connect(update_available)
|
||||||
self.update_thread.start()
|
self.update_thread.start()
|
||||||
|
|
||||||
@ -544,7 +542,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
if os.path.isfile(filename):
|
if os.path.isfile(filename):
|
||||||
total_size += os.path.getsize(filename)
|
total_size += os.path.getsize(filename)
|
||||||
if os.path.isdir(filename):
|
if os.path.isdir(filename):
|
||||||
total_size += common.dir_size(filename)
|
total_size += Common.dir_size(filename)
|
||||||
return total_size
|
return total_size
|
||||||
|
|
||||||
def check_for_requests(self):
|
def check_for_requests(self):
|
||||||
@ -594,7 +592,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
|
|
||||||
elif event["type"] == self.web.REQUEST_RATE_LIMIT:
|
elif event["type"] == self.web.REQUEST_RATE_LIMIT:
|
||||||
self.stop_server()
|
self.stop_server()
|
||||||
Alert(strings._('error_rate_limit'), QtWidgets.QMessageBox.Critical)
|
Alert(self.common, strings._('error_rate_limit'), QtWidgets.QMessageBox.Critical)
|
||||||
|
|
||||||
elif event["type"] == self.web.REQUEST_PROGRESS:
|
elif event["type"] == self.web.REQUEST_PROGRESS:
|
||||||
self.downloads.update_download(event["data"]["id"], event["data"]["bytes"])
|
self.downloads.update_download(event["data"]["id"], event["data"]["bytes"])
|
||||||
@ -655,7 +653,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
"""
|
"""
|
||||||
When the URL gets copied to the clipboard, display this in the status bar.
|
When the URL gets copied to the clipboard, display this in the status bar.
|
||||||
"""
|
"""
|
||||||
common.log('OnionShareGui', 'copy_url')
|
self.common.log('OnionShareGui', 'copy_url')
|
||||||
if self.systemTray.supportsMessages() and self.settings.get('systray_notifications'):
|
if self.systemTray.supportsMessages() and self.settings.get('systray_notifications'):
|
||||||
self.systemTray.showMessage(strings._('gui_copied_url_title', True), strings._('gui_copied_url', True))
|
self.systemTray.showMessage(strings._('gui_copied_url_title', True), strings._('gui_copied_url', True))
|
||||||
|
|
||||||
@ -663,7 +661,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
"""
|
"""
|
||||||
When the stealth onion service HidServAuth gets copied to the clipboard, display this in the status bar.
|
When the stealth onion service HidServAuth gets copied to the clipboard, display this in the status bar.
|
||||||
"""
|
"""
|
||||||
common.log('OnionShareGui', 'copy_hidservauth')
|
self.common.log('OnionShareGui', 'copy_hidservauth')
|
||||||
if self.systemTray.supportsMessages() and self.settings.get('systray_notifications'):
|
if self.systemTray.supportsMessages() and self.settings.get('systray_notifications'):
|
||||||
self.systemTray.showMessage(strings._('gui_copied_hidservauth_title', True), strings._('gui_copied_hidservauth', True))
|
self.systemTray.showMessage(strings._('gui_copied_hidservauth_title', True), strings._('gui_copied_hidservauth', True))
|
||||||
|
|
||||||
@ -697,9 +695,9 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
Update the 'Downloads completed' info widget.
|
Update the 'Downloads completed' info widget.
|
||||||
"""
|
"""
|
||||||
if count == 0:
|
if count == 0:
|
||||||
self.info_completed_downloads_image = common.get_resource_path('images/download_completed_none.png')
|
self.info_completed_downloads_image = self.common.get_resource_path('images/download_completed_none.png')
|
||||||
else:
|
else:
|
||||||
self.info_completed_downloads_image = common.get_resource_path('images/download_completed.png')
|
self.info_completed_downloads_image = self.common.get_resource_path('images/download_completed.png')
|
||||||
self.info_completed_downloads_count.setText('<img src="{0:s}" /> {1:d}'.format(self.info_completed_downloads_image, count))
|
self.info_completed_downloads_count.setText('<img src="{0:s}" /> {1:d}'.format(self.info_completed_downloads_image, count))
|
||||||
self.info_completed_downloads_count.setToolTip(strings._('info_completed_downloads_tooltip', True).format(count))
|
self.info_completed_downloads_count.setToolTip(strings._('info_completed_downloads_tooltip', True).format(count))
|
||||||
|
|
||||||
@ -708,17 +706,17 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
|||||||
Update the 'Downloads in progress' info widget.
|
Update the 'Downloads in progress' info widget.
|
||||||
"""
|
"""
|
||||||
if count == 0:
|
if count == 0:
|
||||||
self.info_in_progress_downloads_image = common.get_resource_path('images/download_in_progress_none.png')
|
self.info_in_progress_downloads_image = self.common.get_resource_path('images/download_in_progress_none.png')
|
||||||
else:
|
else:
|
||||||
self.info_in_progress_downloads_image = common.get_resource_path('images/download_in_progress.png')
|
self.info_in_progress_downloads_image = self.common.get_resource_path('images/download_in_progress.png')
|
||||||
self.info_in_progress_downloads_count.setText('<img src="{0:s}" /> {1:d}'.format(self.info_in_progress_downloads_image, count))
|
self.info_in_progress_downloads_count.setText('<img src="{0:s}" /> {1:d}'.format(self.info_in_progress_downloads_image, count))
|
||||||
self.info_in_progress_downloads_count.setToolTip(strings._('info_in_progress_downloads_tooltip', True).format(count))
|
self.info_in_progress_downloads_count.setToolTip(strings._('info_in_progress_downloads_tooltip', True).format(count))
|
||||||
|
|
||||||
def closeEvent(self, e):
|
def closeEvent(self, e):
|
||||||
common.log('OnionShareGui', 'closeEvent')
|
self.common.log('OnionShareGui', 'closeEvent')
|
||||||
try:
|
try:
|
||||||
if self.server_status.status != self.server_status.STATUS_STOPPED:
|
if self.server_status.status != self.server_status.STATUS_STOPPED:
|
||||||
common.log('OnionShareGui', 'closeEvent, opening warning dialog')
|
self.common.log('OnionShareGui', 'closeEvent, opening warning dialog')
|
||||||
dialog = QtWidgets.QMessageBox()
|
dialog = QtWidgets.QMessageBox()
|
||||||
dialog.setWindowTitle(strings._('gui_quit_title', True))
|
dialog.setWindowTitle(strings._('gui_quit_title', True))
|
||||||
dialog.setText(strings._('gui_quit_warning', True))
|
dialog.setText(strings._('gui_quit_warning', True))
|
||||||
@ -803,9 +801,12 @@ class OnionThread(QtCore.QThread):
|
|||||||
decided to cancel (in which case do not proceed with obtaining
|
decided to cancel (in which case do not proceed with obtaining
|
||||||
the Onion address and starting the web server).
|
the Onion address and starting the web server).
|
||||||
"""
|
"""
|
||||||
def __init__(self, function, kwargs=None):
|
def __init__(self, common, function, kwargs=None):
|
||||||
super(OnionThread, self).__init__()
|
super(OnionThread, self).__init__()
|
||||||
common.log('OnionThread', '__init__')
|
|
||||||
|
self.common = common
|
||||||
|
|
||||||
|
self.common.log('OnionThread', '__init__')
|
||||||
self.function = function
|
self.function = function
|
||||||
if not kwargs:
|
if not kwargs:
|
||||||
self.kwargs = {}
|
self.kwargs = {}
|
||||||
@ -813,6 +814,6 @@ class OnionThread(QtCore.QThread):
|
|||||||
self.kwargs = kwargs
|
self.kwargs = kwargs
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
common.log('OnionThread', 'run')
|
self.common.log('OnionThread', 'run')
|
||||||
|
|
||||||
self.function(**self.kwargs)
|
self.function(**self.kwargs)
|
||||||
|
@ -21,7 +21,7 @@ import platform
|
|||||||
from .alert import Alert
|
from .alert import Alert
|
||||||
from PyQt5 import QtCore, QtWidgets, QtGui
|
from PyQt5 import QtCore, QtWidgets, QtGui
|
||||||
|
|
||||||
from onionshare import strings, common, settings
|
from onionshare import strings
|
||||||
|
|
||||||
class ServerStatus(QtWidgets.QWidget):
|
class ServerStatus(QtWidgets.QWidget):
|
||||||
"""
|
"""
|
||||||
@ -38,8 +38,11 @@ class ServerStatus(QtWidgets.QWidget):
|
|||||||
STATUS_WORKING = 1
|
STATUS_WORKING = 1
|
||||||
STATUS_STARTED = 2
|
STATUS_STARTED = 2
|
||||||
|
|
||||||
def __init__(self, qtapp, app, web, file_selection, settings):
|
def __init__(self, common, qtapp, app, web, file_selection, settings):
|
||||||
super(ServerStatus, self).__init__()
|
super(ServerStatus, self).__init__()
|
||||||
|
|
||||||
|
self.common = common
|
||||||
|
|
||||||
self.status = self.STATUS_STOPPED
|
self.status = self.STATUS_STOPPED
|
||||||
|
|
||||||
self.qtapp = qtapp
|
self.qtapp = qtapp
|
||||||
@ -129,7 +132,7 @@ class ServerStatus(QtWidgets.QWidget):
|
|||||||
if self.status == self.STATUS_STARTED:
|
if self.status == self.STATUS_STARTED:
|
||||||
self.url_description.show()
|
self.url_description.show()
|
||||||
|
|
||||||
info_image = common.get_resource_path('images/info.png')
|
info_image = self.common.get_resource_path('images/info.png')
|
||||||
self.url_description.setText(strings._('gui_url_description', True).format(info_image))
|
self.url_description.setText(strings._('gui_url_description', True).format(info_image))
|
||||||
# Show a Tool Tip explaining the lifecycle of this URL
|
# Show a Tool Tip explaining the lifecycle of this URL
|
||||||
if self.settings.get('save_private_key'):
|
if self.settings.get('save_private_key'):
|
||||||
@ -212,7 +215,7 @@ class ServerStatus(QtWidgets.QWidget):
|
|||||||
self.timeout = self.shutdown_timeout.dateTime().toPyDateTime().replace(second=0, microsecond=0)
|
self.timeout = self.shutdown_timeout.dateTime().toPyDateTime().replace(second=0, microsecond=0)
|
||||||
# If the timeout has actually passed already before the user hit Start, refuse to start the server.
|
# If the timeout has actually passed already before the user hit Start, refuse to start the server.
|
||||||
if QtCore.QDateTime.currentDateTime().toPyDateTime() > self.timeout:
|
if QtCore.QDateTime.currentDateTime().toPyDateTime() > self.timeout:
|
||||||
Alert(strings._('gui_server_timeout_expired', QtWidgets.QMessageBox.Warning))
|
Alert(self.common, strings._('gui_server_timeout_expired', QtWidgets.QMessageBox.Warning))
|
||||||
else:
|
else:
|
||||||
self.start_server()
|
self.start_server()
|
||||||
else:
|
else:
|
||||||
@ -252,7 +255,7 @@ class ServerStatus(QtWidgets.QWidget):
|
|||||||
"""
|
"""
|
||||||
Cancel the server.
|
Cancel the server.
|
||||||
"""
|
"""
|
||||||
common.log('ServerStatus', 'cancel_server', 'Canceling the server mid-startup')
|
self.common.log('ServerStatus', 'cancel_server', 'Canceling the server mid-startup')
|
||||||
self.status = self.STATUS_WORKING
|
self.status = self.STATUS_WORKING
|
||||||
self.shutdown_timeout_reset()
|
self.shutdown_timeout_reset()
|
||||||
self.update()
|
self.update()
|
||||||
|
@ -34,9 +34,12 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
"""
|
"""
|
||||||
settings_saved = QtCore.pyqtSignal()
|
settings_saved = QtCore.pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, onion, qtapp, config=False):
|
def __init__(self, common, onion, qtapp, config=False):
|
||||||
super(SettingsDialog, self).__init__()
|
super(SettingsDialog, self).__init__()
|
||||||
common.log('SettingsDialog', '__init__')
|
|
||||||
|
self.common = common
|
||||||
|
|
||||||
|
self.common.log('SettingsDialog', '__init__')
|
||||||
|
|
||||||
self.onion = onion
|
self.onion = onion
|
||||||
self.qtapp = qtapp
|
self.qtapp = qtapp
|
||||||
@ -44,7 +47,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
|
|
||||||
self.setModal(True)
|
self.setModal(True)
|
||||||
self.setWindowTitle(strings._('gui_settings_window_title', True))
|
self.setWindowTitle(strings._('gui_settings_window_title', True))
|
||||||
self.setWindowIcon(QtGui.QIcon(common.get_resource_path('images/logo.png')))
|
self.setWindowIcon(QtGui.QIcon(self.common.get_resource_path('images/logo.png')))
|
||||||
|
|
||||||
self.system = platform.system()
|
self.system = platform.system()
|
||||||
|
|
||||||
@ -156,7 +159,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
|
|
||||||
# obfs4 option radio
|
# obfs4 option radio
|
||||||
# if the obfs4proxy binary is missing, we can't use obfs4 transports
|
# if the obfs4proxy binary is missing, we can't use obfs4 transports
|
||||||
(self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = common.get_tor_paths()
|
(self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = self.common.get_tor_paths()
|
||||||
if not os.path.isfile(self.obfs4proxy_file_path):
|
if not os.path.isfile(self.obfs4proxy_file_path):
|
||||||
self.tor_bridges_use_obfs4_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_obfs4_radio_option_no_obfs4proxy', True))
|
self.tor_bridges_use_obfs4_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_obfs4_radio_option_no_obfs4proxy', True))
|
||||||
self.tor_bridges_use_obfs4_radio.setEnabled(False)
|
self.tor_bridges_use_obfs4_radio.setEnabled(False)
|
||||||
@ -166,7 +169,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
|
|
||||||
# meek_lite-amazon option radio
|
# meek_lite-amazon option radio
|
||||||
# if the obfs4proxy binary is missing, we can't use meek_lite-amazon transports
|
# if the obfs4proxy binary is missing, we can't use meek_lite-amazon transports
|
||||||
(self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = common.get_tor_paths()
|
(self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = self.common.get_tor_paths()
|
||||||
if not os.path.isfile(self.obfs4proxy_file_path):
|
if not os.path.isfile(self.obfs4proxy_file_path):
|
||||||
self.tor_bridges_use_meek_lite_amazon_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_meek_lite_amazon_radio_option_no_obfs4proxy', True))
|
self.tor_bridges_use_meek_lite_amazon_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_meek_lite_amazon_radio_option_no_obfs4proxy', True))
|
||||||
self.tor_bridges_use_meek_lite_amazon_radio.setEnabled(False)
|
self.tor_bridges_use_meek_lite_amazon_radio.setEnabled(False)
|
||||||
@ -176,7 +179,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
|
|
||||||
# meek_lite-azure option radio
|
# meek_lite-azure option radio
|
||||||
# if the obfs4proxy binary is missing, we can't use meek_lite-azure transports
|
# if the obfs4proxy binary is missing, we can't use meek_lite-azure transports
|
||||||
(self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = common.get_tor_paths()
|
(self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = self.common.get_tor_paths()
|
||||||
if not os.path.isfile(self.obfs4proxy_file_path):
|
if not os.path.isfile(self.obfs4proxy_file_path):
|
||||||
self.tor_bridges_use_meek_lite_azure_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_meek_lite_azure_radio_option_no_obfs4proxy', True))
|
self.tor_bridges_use_meek_lite_azure_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_meek_lite_azure_radio_option_no_obfs4proxy', True))
|
||||||
self.tor_bridges_use_meek_lite_azure_radio.setEnabled(False)
|
self.tor_bridges_use_meek_lite_azure_radio.setEnabled(False)
|
||||||
@ -330,7 +333,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
self.save_button.clicked.connect(self.save_clicked)
|
self.save_button.clicked.connect(self.save_clicked)
|
||||||
self.cancel_button = QtWidgets.QPushButton(strings._('gui_settings_button_cancel', True))
|
self.cancel_button = QtWidgets.QPushButton(strings._('gui_settings_button_cancel', True))
|
||||||
self.cancel_button.clicked.connect(self.cancel_clicked)
|
self.cancel_button.clicked.connect(self.cancel_clicked)
|
||||||
version_label = QtWidgets.QLabel('OnionShare {0:s}'.format(common.get_version()))
|
version_label = QtWidgets.QLabel('OnionShare {0:s}'.format(self.common.version))
|
||||||
version_label.setStyleSheet('color: #666666')
|
version_label.setStyleSheet('color: #666666')
|
||||||
self.help_button = QtWidgets.QPushButton(strings._('gui_settings_button_help', True))
|
self.help_button = QtWidgets.QPushButton(strings._('gui_settings_button_help', True))
|
||||||
self.help_button.clicked.connect(self.help_clicked)
|
self.help_button.clicked.connect(self.help_clicked)
|
||||||
@ -372,7 +375,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
self.cancel_button.setFocus()
|
self.cancel_button.setFocus()
|
||||||
|
|
||||||
# Load settings, and fill them in
|
# Load settings, and fill them in
|
||||||
self.old_settings = Settings(self.config)
|
self.old_settings = Settings(self.common, self.config)
|
||||||
self.old_settings.load()
|
self.old_settings.load()
|
||||||
|
|
||||||
close_after_first_download = self.old_settings.get('close_after_first_download')
|
close_after_first_download = self.old_settings.get('close_after_first_download')
|
||||||
@ -470,7 +473,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
"""
|
"""
|
||||||
Connection type bundled was toggled. If checked, hide authentication fields.
|
Connection type bundled was toggled. If checked, hide authentication fields.
|
||||||
"""
|
"""
|
||||||
common.log('SettingsDialog', 'connection_type_bundled_toggled')
|
self.common.log('SettingsDialog', 'connection_type_bundled_toggled')
|
||||||
if checked:
|
if checked:
|
||||||
self.authenticate_group.hide()
|
self.authenticate_group.hide()
|
||||||
self.connection_type_socks.hide()
|
self.connection_type_socks.hide()
|
||||||
@ -515,7 +518,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
"""
|
"""
|
||||||
Connection type automatic was toggled. If checked, hide authentication fields.
|
Connection type automatic was toggled. If checked, hide authentication fields.
|
||||||
"""
|
"""
|
||||||
common.log('SettingsDialog', 'connection_type_automatic_toggled')
|
self.common.log('SettingsDialog', 'connection_type_automatic_toggled')
|
||||||
if checked:
|
if checked:
|
||||||
self.authenticate_group.hide()
|
self.authenticate_group.hide()
|
||||||
self.connection_type_socks.hide()
|
self.connection_type_socks.hide()
|
||||||
@ -526,7 +529,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
Connection type control port was toggled. If checked, show extra fields
|
Connection type control port was toggled. If checked, show extra fields
|
||||||
for Tor control address and port. If unchecked, hide those extra fields.
|
for Tor control address and port. If unchecked, hide those extra fields.
|
||||||
"""
|
"""
|
||||||
common.log('SettingsDialog', 'connection_type_control_port_toggled')
|
self.common.log('SettingsDialog', 'connection_type_control_port_toggled')
|
||||||
if checked:
|
if checked:
|
||||||
self.authenticate_group.show()
|
self.authenticate_group.show()
|
||||||
self.connection_type_control_port_extras.show()
|
self.connection_type_control_port_extras.show()
|
||||||
@ -541,7 +544,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
Connection type socket file was toggled. If checked, show extra fields
|
Connection type socket file was toggled. If checked, show extra fields
|
||||||
for socket file. If unchecked, hide those extra fields.
|
for socket file. If unchecked, hide those extra fields.
|
||||||
"""
|
"""
|
||||||
common.log('SettingsDialog', 'connection_type_socket_file_toggled')
|
self.common.log('SettingsDialog', 'connection_type_socket_file_toggled')
|
||||||
if checked:
|
if checked:
|
||||||
self.authenticate_group.show()
|
self.authenticate_group.show()
|
||||||
self.connection_type_socket_file_extras.show()
|
self.connection_type_socket_file_extras.show()
|
||||||
@ -554,14 +557,14 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
"""
|
"""
|
||||||
Authentication option no authentication was toggled.
|
Authentication option no authentication was toggled.
|
||||||
"""
|
"""
|
||||||
common.log('SettingsDialog', 'authenticate_no_auth_toggled')
|
self.common.log('SettingsDialog', 'authenticate_no_auth_toggled')
|
||||||
|
|
||||||
def authenticate_password_toggled(self, checked):
|
def authenticate_password_toggled(self, checked):
|
||||||
"""
|
"""
|
||||||
Authentication option password was toggled. If checked, show extra fields
|
Authentication option password was toggled. If checked, show extra fields
|
||||||
for password auth. If unchecked, hide those extra fields.
|
for password auth. If unchecked, hide those extra fields.
|
||||||
"""
|
"""
|
||||||
common.log('SettingsDialog', 'authenticate_password_toggled')
|
self.common.log('SettingsDialog', 'authenticate_password_toggled')
|
||||||
if checked:
|
if checked:
|
||||||
self.authenticate_password_extras.show()
|
self.authenticate_password_extras.show()
|
||||||
else:
|
else:
|
||||||
@ -572,7 +575,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
Toggle the 'Copy HidServAuth' button
|
Toggle the 'Copy HidServAuth' button
|
||||||
to copy the saved HidServAuth to clipboard.
|
to copy the saved HidServAuth to clipboard.
|
||||||
"""
|
"""
|
||||||
common.log('SettingsDialog', 'hidservauth_copy_button_clicked', 'HidServAuth was copied to clipboard')
|
self.common.log('SettingsDialog', 'hidservauth_copy_button_clicked', 'HidServAuth was copied to clipboard')
|
||||||
clipboard = self.qtapp.clipboard()
|
clipboard = self.qtapp.clipboard()
|
||||||
clipboard.setText(self.old_settings.get('hidservauth_string'))
|
clipboard.setText(self.old_settings.get('hidservauth_string'))
|
||||||
|
|
||||||
@ -581,7 +584,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
Test Tor Settings button clicked. With the given settings, see if we can
|
Test Tor Settings button clicked. With the given settings, see if we can
|
||||||
successfully connect and authenticate to Tor.
|
successfully connect and authenticate to Tor.
|
||||||
"""
|
"""
|
||||||
common.log('SettingsDialog', 'test_tor_clicked')
|
self.common.log('SettingsDialog', 'test_tor_clicked')
|
||||||
settings = self.settings_from_fields()
|
settings = self.settings_from_fields()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -600,13 +603,13 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
onion.connect(settings=settings, config=self.config, tor_status_update_func=tor_status_update_func)
|
onion.connect(settings=settings, config=self.config, tor_status_update_func=tor_status_update_func)
|
||||||
|
|
||||||
# If an exception hasn't been raised yet, the Tor settings work
|
# 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))
|
Alert(self.common, strings._('settings_test_success', True).format(onion.tor_version, onion.supports_ephemeral, onion.supports_stealth))
|
||||||
|
|
||||||
# Clean up
|
# Clean up
|
||||||
onion.cleanup()
|
onion.cleanup()
|
||||||
|
|
||||||
except (TorErrorInvalidSetting, TorErrorAutomatic, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile, TorErrorAuthError, TorErrorProtocolError, BundledTorNotSupported, BundledTorTimeout) as e:
|
except (TorErrorInvalidSetting, TorErrorAutomatic, TorErrorSocketPort, TorErrorSocketFile, TorErrorMissingPassword, TorErrorUnreadableCookieFile, TorErrorAuthError, TorErrorProtocolError, BundledTorNotSupported, BundledTorTimeout) as e:
|
||||||
Alert(e.args[0], QtWidgets.QMessageBox.Warning)
|
Alert(self.common, e.args[0], QtWidgets.QMessageBox.Warning)
|
||||||
if settings.get('connection_type') == 'bundled':
|
if settings.get('connection_type') == 'bundled':
|
||||||
self.tor_status.hide()
|
self.tor_status.hide()
|
||||||
self._enable_buttons()
|
self._enable_buttons()
|
||||||
@ -615,14 +618,14 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
"""
|
"""
|
||||||
Check for Updates button clicked. Manually force an update check.
|
Check for Updates button clicked. Manually force an update check.
|
||||||
"""
|
"""
|
||||||
common.log('SettingsDialog', 'check_for_updates')
|
self.common.log('SettingsDialog', 'check_for_updates')
|
||||||
# Disable buttons
|
# Disable buttons
|
||||||
self._disable_buttons()
|
self._disable_buttons()
|
||||||
self.qtapp.processEvents()
|
self.qtapp.processEvents()
|
||||||
|
|
||||||
def update_timestamp():
|
def update_timestamp():
|
||||||
# Update the last checked label
|
# Update the last checked label
|
||||||
settings = Settings(self.config)
|
settings = Settings(self.common, self.config)
|
||||||
settings.load()
|
settings.load()
|
||||||
autoupdate_timestamp = settings.get('autoupdate_timestamp')
|
autoupdate_timestamp = settings.get('autoupdate_timestamp')
|
||||||
self._update_autoupdate_timestamp(autoupdate_timestamp)
|
self._update_autoupdate_timestamp(autoupdate_timestamp)
|
||||||
@ -636,22 +639,22 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
|
|
||||||
# Check for updates
|
# Check for updates
|
||||||
def update_available(update_url, installed_version, latest_version):
|
def update_available(update_url, installed_version, latest_version):
|
||||||
Alert(strings._("update_available", True).format(update_url, installed_version, latest_version))
|
Alert(self.common, strings._("update_available", True).format(update_url, installed_version, latest_version))
|
||||||
close_forced_update_thread()
|
close_forced_update_thread()
|
||||||
|
|
||||||
def update_not_available():
|
def update_not_available():
|
||||||
Alert(strings._('update_not_available', True))
|
Alert(self.common, strings._('update_not_available', True))
|
||||||
close_forced_update_thread()
|
close_forced_update_thread()
|
||||||
|
|
||||||
def update_error():
|
def update_error():
|
||||||
Alert(strings._('update_error_check_error', True), QtWidgets.QMessageBox.Warning)
|
Alert(self.common, strings._('update_error_check_error', True), QtWidgets.QMessageBox.Warning)
|
||||||
close_forced_update_thread()
|
close_forced_update_thread()
|
||||||
|
|
||||||
def update_invalid_version():
|
def update_invalid_version():
|
||||||
Alert(strings._('update_error_invalid_latest_version', True).format(e.latest_version), QtWidgets.QMessageBox.Warning)
|
Alert(self.common, strings._('update_error_invalid_latest_version', True).format(e.latest_version), QtWidgets.QMessageBox.Warning)
|
||||||
close_forced_update_thread()
|
close_forced_update_thread()
|
||||||
|
|
||||||
forced_update_thread = UpdateThread(self.onion, self.config, force=True)
|
forced_update_thread = UpdateThread(self.common, self.onion, self.config, force=True)
|
||||||
forced_update_thread.update_available.connect(update_available)
|
forced_update_thread.update_available.connect(update_available)
|
||||||
forced_update_thread.update_not_available.connect(update_not_available)
|
forced_update_thread.update_not_available.connect(update_not_available)
|
||||||
forced_update_thread.update_error.connect(update_error)
|
forced_update_thread.update_error.connect(update_error)
|
||||||
@ -662,7 +665,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
"""
|
"""
|
||||||
Save button clicked. Save current settings to disk.
|
Save button clicked. Save current settings to disk.
|
||||||
"""
|
"""
|
||||||
common.log('SettingsDialog', 'save_clicked')
|
self.common.log('SettingsDialog', 'save_clicked')
|
||||||
|
|
||||||
settings = self.settings_from_fields()
|
settings = self.settings_from_fields()
|
||||||
if settings:
|
if settings:
|
||||||
@ -672,7 +675,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
# the Onion object
|
# the Onion object
|
||||||
reboot_onion = False
|
reboot_onion = False
|
||||||
if self.onion.is_authenticated():
|
if self.onion.is_authenticated():
|
||||||
common.log('SettingsDialog', 'save_clicked', 'Connected to Tor')
|
self.common.log('SettingsDialog', 'save_clicked', 'Connected to Tor')
|
||||||
def changed(s1, s2, keys):
|
def changed(s1, s2, keys):
|
||||||
"""
|
"""
|
||||||
Compare the Settings objects s1 and s2 and return true if any values
|
Compare the Settings objects s1 and s2 and return true if any values
|
||||||
@ -694,20 +697,20 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
reboot_onion = True
|
reboot_onion = True
|
||||||
|
|
||||||
else:
|
else:
|
||||||
common.log('SettingsDialog', 'save_clicked', 'Not connected to Tor')
|
self.common.log('SettingsDialog', 'save_clicked', 'Not connected to Tor')
|
||||||
# Tor isn't connected, so try connecting
|
# Tor isn't connected, so try connecting
|
||||||
reboot_onion = True
|
reboot_onion = True
|
||||||
|
|
||||||
# Do we need to reinitialize Tor?
|
# Do we need to reinitialize Tor?
|
||||||
if reboot_onion:
|
if reboot_onion:
|
||||||
# Reinitialize the Onion object
|
# Reinitialize the Onion object
|
||||||
common.log('SettingsDialog', 'save_clicked', 'rebooting the Onion')
|
self.common.log('SettingsDialog', 'save_clicked', 'rebooting the Onion')
|
||||||
self.onion.cleanup()
|
self.onion.cleanup()
|
||||||
|
|
||||||
tor_con = TorConnectionDialog(self.qtapp, settings, self.onion)
|
tor_con = TorConnectionDialog(self.common, self.qtapp, settings, self.onion)
|
||||||
tor_con.start()
|
tor_con.start()
|
||||||
|
|
||||||
common.log('SettingsDialog', 'save_clicked', 'Onion done rebooting, connected to Tor: {}'.format(self.onion.connected_to_tor))
|
self.common.log('SettingsDialog', 'save_clicked', 'Onion done rebooting, connected to Tor: {}'.format(self.onion.connected_to_tor))
|
||||||
|
|
||||||
if self.onion.is_authenticated() and not tor_con.wasCanceled():
|
if self.onion.is_authenticated() and not tor_con.wasCanceled():
|
||||||
self.settings_saved.emit()
|
self.settings_saved.emit()
|
||||||
@ -721,9 +724,9 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
"""
|
"""
|
||||||
Cancel button clicked.
|
Cancel button clicked.
|
||||||
"""
|
"""
|
||||||
common.log('SettingsDialog', 'cancel_clicked')
|
self.common.log('SettingsDialog', 'cancel_clicked')
|
||||||
if not self.onion.is_authenticated():
|
if not self.onion.is_authenticated():
|
||||||
Alert(strings._('gui_tor_connection_canceled', True), QtWidgets.QMessageBox.Warning)
|
Alert(self.common, strings._('gui_tor_connection_canceled', True), QtWidgets.QMessageBox.Warning)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
else:
|
else:
|
||||||
self.close()
|
self.close()
|
||||||
@ -732,7 +735,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
"""
|
"""
|
||||||
Help button clicked.
|
Help button clicked.
|
||||||
"""
|
"""
|
||||||
common.log('SettingsDialog', 'help_clicked')
|
self.common.log('SettingsDialog', 'help_clicked')
|
||||||
help_site = 'https://github.com/micahflee/onionshare/wiki'
|
help_site = 'https://github.com/micahflee/onionshare/wiki'
|
||||||
QtGui.QDesktopServices.openUrl(QtCore.QUrl(help_site))
|
QtGui.QDesktopServices.openUrl(QtCore.QUrl(help_site))
|
||||||
|
|
||||||
@ -740,8 +743,8 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
"""
|
"""
|
||||||
Return a Settings object that's full of values from the settings dialog.
|
Return a Settings object that's full of values from the settings dialog.
|
||||||
"""
|
"""
|
||||||
common.log('SettingsDialog', 'settings_from_fields')
|
self.common.log('SettingsDialog', 'settings_from_fields')
|
||||||
settings = Settings(self.config)
|
settings = Settings(self.common, self.config)
|
||||||
settings.load() # To get the last update timestamp
|
settings.load() # To get the last update timestamp
|
||||||
|
|
||||||
settings.set('close_after_first_download', self.close_after_first_download_checkbox.isChecked())
|
settings.set('close_after_first_download', self.close_after_first_download_checkbox.isChecked())
|
||||||
@ -846,24 +849,24 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
new_bridges = ''.join(new_bridges)
|
new_bridges = ''.join(new_bridges)
|
||||||
settings.set('tor_bridges_use_custom_bridges', new_bridges)
|
settings.set('tor_bridges_use_custom_bridges', new_bridges)
|
||||||
else:
|
else:
|
||||||
Alert(strings._('gui_settings_tor_bridges_invalid', True))
|
Alert(self.common, strings._('gui_settings_tor_bridges_invalid', True))
|
||||||
settings.set('no_bridges', True)
|
settings.set('no_bridges', True)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return settings
|
return settings
|
||||||
|
|
||||||
def closeEvent(self, e):
|
def closeEvent(self, e):
|
||||||
common.log('SettingsDialog', 'closeEvent')
|
self.common.log('SettingsDialog', 'closeEvent')
|
||||||
|
|
||||||
# On close, if Tor isn't connected, then quit OnionShare altogether
|
# On close, if Tor isn't connected, then quit OnionShare altogether
|
||||||
if not self.onion.is_authenticated():
|
if not self.onion.is_authenticated():
|
||||||
common.log('SettingsDialog', 'closeEvent', 'Closing while not connected to Tor')
|
self.common.log('SettingsDialog', 'closeEvent', 'Closing while not connected to Tor')
|
||||||
|
|
||||||
# Wait 1ms for the event loop to finish, then quit
|
# Wait 1ms for the event loop to finish, then quit
|
||||||
QtCore.QTimer.singleShot(1, self.qtapp.quit)
|
QtCore.QTimer.singleShot(1, self.qtapp.quit)
|
||||||
|
|
||||||
def _update_autoupdate_timestamp(self, autoupdate_timestamp):
|
def _update_autoupdate_timestamp(self, autoupdate_timestamp):
|
||||||
common.log('SettingsDialog', '_update_autoupdate_timestamp')
|
self.common.log('SettingsDialog', '_update_autoupdate_timestamp')
|
||||||
|
|
||||||
if autoupdate_timestamp:
|
if autoupdate_timestamp:
|
||||||
dt = datetime.datetime.fromtimestamp(autoupdate_timestamp)
|
dt = datetime.datetime.fromtimestamp(autoupdate_timestamp)
|
||||||
@ -880,7 +883,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
self._enable_buttons()
|
self._enable_buttons()
|
||||||
|
|
||||||
def _disable_buttons(self):
|
def _disable_buttons(self):
|
||||||
common.log('SettingsDialog', '_disable_buttons')
|
self.common.log('SettingsDialog', '_disable_buttons')
|
||||||
|
|
||||||
self.check_for_updates_button.setEnabled(False)
|
self.check_for_updates_button.setEnabled(False)
|
||||||
self.connection_type_test_button.setEnabled(False)
|
self.connection_type_test_button.setEnabled(False)
|
||||||
@ -888,7 +891,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
|||||||
self.cancel_button.setEnabled(False)
|
self.cancel_button.setEnabled(False)
|
||||||
|
|
||||||
def _enable_buttons(self):
|
def _enable_buttons(self):
|
||||||
common.log('SettingsDialog', '_enable_buttons')
|
self.common.log('SettingsDialog', '_enable_buttons')
|
||||||
# We can't check for updates if we're still not connected to Tor
|
# We can't check for updates if we're still not connected to Tor
|
||||||
if not self.onion.connected_to_tor:
|
if not self.onion.connected_to_tor:
|
||||||
self.check_for_updates_button.setEnabled(False)
|
self.check_for_updates_button.setEnabled(False)
|
||||||
|
@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
"""
|
"""
|
||||||
from PyQt5 import QtCore, QtWidgets, QtGui
|
from PyQt5 import QtCore, QtWidgets, QtGui
|
||||||
|
|
||||||
from onionshare import strings, common
|
from onionshare import strings
|
||||||
from onionshare.onion import *
|
from onionshare.onion import *
|
||||||
|
|
||||||
from .alert import Alert
|
from .alert import Alert
|
||||||
@ -30,16 +30,19 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
|
|||||||
"""
|
"""
|
||||||
open_settings = QtCore.pyqtSignal()
|
open_settings = QtCore.pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, qtapp, settings, onion):
|
def __init__(self, common, qtapp, settings, onion):
|
||||||
super(TorConnectionDialog, self).__init__(None)
|
super(TorConnectionDialog, self).__init__(None)
|
||||||
common.log('TorConnectionDialog', '__init__')
|
|
||||||
|
self.common = common
|
||||||
|
|
||||||
|
self.common.log('TorConnectionDialog', '__init__')
|
||||||
|
|
||||||
self.qtapp = qtapp
|
self.qtapp = qtapp
|
||||||
self.settings = settings
|
self.settings = settings
|
||||||
self.onion = onion
|
self.onion = onion
|
||||||
|
|
||||||
self.setWindowTitle("OnionShare")
|
self.setWindowTitle("OnionShare")
|
||||||
self.setWindowIcon(QtGui.QIcon(common.get_resource_path('images/logo.png')))
|
self.setWindowIcon(QtGui.QIcon(self.common.get_resource_path('images/logo.png')))
|
||||||
self.setModal(True)
|
self.setModal(True)
|
||||||
self.setFixedSize(400, 150)
|
self.setFixedSize(400, 150)
|
||||||
|
|
||||||
@ -55,9 +58,9 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
|
|||||||
self._tor_status_update(0, '')
|
self._tor_status_update(0, '')
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
common.log('TorConnectionDialog', 'start')
|
self.common.log('TorConnectionDialog', 'start')
|
||||||
|
|
||||||
t = TorConnectionThread(self, self.settings, self.onion)
|
t = TorConnectionThread(self.common, self, self.settings, self.onion)
|
||||||
t.tor_status_update.connect(self._tor_status_update)
|
t.tor_status_update.connect(self._tor_status_update)
|
||||||
t.connected_to_tor.connect(self._connected_to_tor)
|
t.connected_to_tor.connect(self._connected_to_tor)
|
||||||
t.canceled_connecting_to_tor.connect(self._canceled_connecting_to_tor)
|
t.canceled_connecting_to_tor.connect(self._canceled_connecting_to_tor)
|
||||||
@ -77,14 +80,14 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
|
|||||||
self.setLabelText("<strong>{}</strong><br>{}".format(strings._('connecting_to_tor', True), summary))
|
self.setLabelText("<strong>{}</strong><br>{}".format(strings._('connecting_to_tor', True), summary))
|
||||||
|
|
||||||
def _connected_to_tor(self):
|
def _connected_to_tor(self):
|
||||||
common.log('TorConnectionDialog', '_connected_to_tor')
|
self.common.log('TorConnectionDialog', '_connected_to_tor')
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
# Close the dialog after connecting
|
# Close the dialog after connecting
|
||||||
self.setValue(self.maximum())
|
self.setValue(self.maximum())
|
||||||
|
|
||||||
def _canceled_connecting_to_tor(self):
|
def _canceled_connecting_to_tor(self):
|
||||||
common.log('TorConnectionDialog', '_canceled_connecting_to_tor')
|
self.common.log('TorConnectionDialog', '_canceled_connecting_to_tor')
|
||||||
self.active = False
|
self.active = False
|
||||||
self.onion.cleanup()
|
self.onion.cleanup()
|
||||||
|
|
||||||
@ -92,12 +95,12 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
|
|||||||
QtCore.QTimer.singleShot(1, self.cancel)
|
QtCore.QTimer.singleShot(1, self.cancel)
|
||||||
|
|
||||||
def _error_connecting_to_tor(self, msg):
|
def _error_connecting_to_tor(self, msg):
|
||||||
common.log('TorConnectionDialog', '_error_connecting_to_tor')
|
self.common.log('TorConnectionDialog', '_error_connecting_to_tor')
|
||||||
self.active = False
|
self.active = False
|
||||||
|
|
||||||
def alert_and_open_settings():
|
def alert_and_open_settings():
|
||||||
# Display the exception in an alert box
|
# Display the exception in an alert box
|
||||||
Alert("{}\n\n{}".format(msg, strings._('gui_tor_connection_error_settings', True)), QtWidgets.QMessageBox.Warning)
|
Alert(self.common, "{}\n\n{}".format(msg, strings._('gui_tor_connection_error_settings', True)), QtWidgets.QMessageBox.Warning)
|
||||||
|
|
||||||
# Open settings
|
# Open settings
|
||||||
self.open_settings.emit()
|
self.open_settings.emit()
|
||||||
@ -113,16 +116,19 @@ class TorConnectionThread(QtCore.QThread):
|
|||||||
canceled_connecting_to_tor = QtCore.pyqtSignal()
|
canceled_connecting_to_tor = QtCore.pyqtSignal()
|
||||||
error_connecting_to_tor = QtCore.pyqtSignal(str)
|
error_connecting_to_tor = QtCore.pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, dialog, settings, onion):
|
def __init__(self, common, dialog, settings, onion):
|
||||||
super(TorConnectionThread, self).__init__()
|
super(TorConnectionThread, self).__init__()
|
||||||
common.log('TorConnectionThread', '__init__')
|
|
||||||
|
self.common = common
|
||||||
|
|
||||||
|
self.common.log('TorConnectionThread', '__init__')
|
||||||
|
|
||||||
self.dialog = dialog
|
self.dialog = dialog
|
||||||
self.settings = settings
|
self.settings = settings
|
||||||
self.onion = onion
|
self.onion = onion
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
common.log('TorConnectionThread', 'run')
|
self.common.log('TorConnectionThread', 'run')
|
||||||
|
|
||||||
# Connect to the Onion
|
# Connect to the Onion
|
||||||
try:
|
try:
|
||||||
@ -133,11 +139,11 @@ class TorConnectionThread(QtCore.QThread):
|
|||||||
self.canceled_connecting_to_tor.emit()
|
self.canceled_connecting_to_tor.emit()
|
||||||
|
|
||||||
except BundledTorCanceled as e:
|
except BundledTorCanceled as e:
|
||||||
common.log('TorConnectionThread', 'run', 'caught exception: BundledTorCanceled')
|
self.common.log('TorConnectionThread', 'run', 'caught exception: BundledTorCanceled')
|
||||||
self.canceled_connecting_to_tor.emit()
|
self.canceled_connecting_to_tor.emit()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
common.log('TorConnectionThread', 'run', 'caught exception: {}'.format(e.args[0]))
|
self.common.log('TorConnectionThread', 'run', 'caught exception: {}'.format(e.args[0]))
|
||||||
self.error_connecting_to_tor.emit(str(e.args[0]))
|
self.error_connecting_to_tor.emit(str(e.args[0]))
|
||||||
|
|
||||||
def _tor_status_update(self, progress, summary):
|
def _tor_status_update(self, progress, summary):
|
||||||
|
@ -25,7 +25,7 @@ from onionshare import socks
|
|||||||
from onionshare.settings import Settings
|
from onionshare.settings import Settings
|
||||||
from onionshare.onion import Onion
|
from onionshare.onion import Onion
|
||||||
|
|
||||||
from . import strings, common
|
from . import strings
|
||||||
|
|
||||||
class UpdateCheckerCheckError(Exception):
|
class UpdateCheckerCheckError(Exception):
|
||||||
"""
|
"""
|
||||||
@ -55,16 +55,19 @@ class UpdateChecker(QtCore.QObject):
|
|||||||
update_error = QtCore.pyqtSignal()
|
update_error = QtCore.pyqtSignal()
|
||||||
update_invalid_version = QtCore.pyqtSignal()
|
update_invalid_version = QtCore.pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, onion, config=False):
|
def __init__(self, common, onion, config=False):
|
||||||
super(UpdateChecker, self).__init__()
|
super(UpdateChecker, self).__init__()
|
||||||
common.log('UpdateChecker', '__init__')
|
|
||||||
|
self.common = common
|
||||||
|
|
||||||
|
self.common.log('UpdateChecker', '__init__')
|
||||||
self.onion = onion
|
self.onion = onion
|
||||||
self.config = config
|
self.config = config
|
||||||
|
|
||||||
def check(self, force=False, config=False):
|
def check(self, force=False, config=False):
|
||||||
common.log('UpdateChecker', 'check', 'force={}'.format(force))
|
self.common.log('UpdateChecker', 'check', 'force={}'.format(force))
|
||||||
# Load the settings
|
# Load the settings
|
||||||
settings = Settings(config)
|
settings = Settings(self.common, config)
|
||||||
settings.load()
|
settings.load()
|
||||||
|
|
||||||
# If force=True, then definitely check
|
# If force=True, then definitely check
|
||||||
@ -87,11 +90,11 @@ class UpdateChecker(QtCore.QObject):
|
|||||||
|
|
||||||
# Check for updates
|
# Check for updates
|
||||||
if check_for_updates:
|
if check_for_updates:
|
||||||
common.log('UpdateChecker', 'check', 'checking for updates')
|
self.common.log('UpdateChecker', 'check', 'checking for updates')
|
||||||
# Download the latest-version file over Tor
|
# Download the latest-version file over Tor
|
||||||
try:
|
try:
|
||||||
# User agent string includes OnionShare version and platform
|
# User agent string includes OnionShare version and platform
|
||||||
user_agent = 'OnionShare {}, {}'.format(common.get_version(), platform.system())
|
user_agent = 'OnionShare {}, {}'.format(self.common.version, self.common.platform)
|
||||||
|
|
||||||
# If the update is forced, add '?force=1' to the URL, to more
|
# If the update is forced, add '?force=1' to the URL, to more
|
||||||
# accurately measure daily users
|
# accurately measure daily users
|
||||||
@ -104,7 +107,7 @@ class UpdateChecker(QtCore.QObject):
|
|||||||
else:
|
else:
|
||||||
onion_domain = 'elx57ue5uyfplgva.onion'
|
onion_domain = 'elx57ue5uyfplgva.onion'
|
||||||
|
|
||||||
common.log('UpdateChecker', 'check', 'loading http://{}{}'.format(onion_domain, path))
|
self.common.log('UpdateChecker', 'check', 'loading http://{}{}'.format(onion_domain, path))
|
||||||
|
|
||||||
(socks_address, socks_port) = self.onion.get_tor_socks_port()
|
(socks_address, socks_port) = self.onion.get_tor_socks_port()
|
||||||
socks.set_default_proxy(socks.SOCKS5, socks_address, socks_port)
|
socks.set_default_proxy(socks.SOCKS5, socks_address, socks_port)
|
||||||
@ -122,10 +125,10 @@ class UpdateChecker(QtCore.QObject):
|
|||||||
http_response = s.recv(1024)
|
http_response = s.recv(1024)
|
||||||
latest_version = http_response[http_response.find(b'\r\n\r\n'):].strip().decode('utf-8')
|
latest_version = http_response[http_response.find(b'\r\n\r\n'):].strip().decode('utf-8')
|
||||||
|
|
||||||
common.log('UpdateChecker', 'check', 'latest OnionShare version: {}'.format(latest_version))
|
self.common.log('UpdateChecker', 'check', 'latest OnionShare version: {}'.format(latest_version))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
common.log('UpdateChecker', 'check', '{}'.format(e))
|
self.common.log('UpdateChecker', 'check', '{}'.format(e))
|
||||||
self.update_error.emit()
|
self.update_error.emit()
|
||||||
raise UpdateCheckerCheckError
|
raise UpdateCheckerCheckError
|
||||||
|
|
||||||
@ -145,7 +148,7 @@ class UpdateChecker(QtCore.QObject):
|
|||||||
|
|
||||||
# Do we need to update?
|
# Do we need to update?
|
||||||
update_url = 'https://github.com/micahflee/onionshare/releases/tag/v{}'.format(latest_version)
|
update_url = 'https://github.com/micahflee/onionshare/releases/tag/v{}'.format(latest_version)
|
||||||
installed_version = common.get_version()
|
installed_version = self.common.version
|
||||||
if installed_version < latest_version:
|
if installed_version < latest_version:
|
||||||
self.update_available.emit(update_url, installed_version, latest_version)
|
self.update_available.emit(update_url, installed_version, latest_version)
|
||||||
return
|
return
|
||||||
@ -159,17 +162,20 @@ class UpdateThread(QtCore.QThread):
|
|||||||
update_error = QtCore.pyqtSignal()
|
update_error = QtCore.pyqtSignal()
|
||||||
update_invalid_version = QtCore.pyqtSignal()
|
update_invalid_version = QtCore.pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, onion, config=False, force=False):
|
def __init__(self, common, onion, config=False, force=False):
|
||||||
super(UpdateThread, self).__init__()
|
super(UpdateThread, self).__init__()
|
||||||
common.log('UpdateThread', '__init__')
|
|
||||||
|
self.common = common
|
||||||
|
|
||||||
|
self.common.log('UpdateThread', '__init__')
|
||||||
self.onion = onion
|
self.onion = onion
|
||||||
self.config = config
|
self.config = config
|
||||||
self.force = force
|
self.force = force
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
common.log('UpdateThread', 'run')
|
self.common.log('UpdateThread', 'run')
|
||||||
|
|
||||||
u = UpdateChecker(self.onion, self.config)
|
u = UpdateChecker(self.common, self.onion, self.config)
|
||||||
u.update_available.connect(self._update_available)
|
u.update_available.connect(self._update_available)
|
||||||
u.update_not_available.connect(self._update_not_available)
|
u.update_not_available.connect(self._update_not_available)
|
||||||
u.update_error.connect(self._update_error)
|
u.update_error.connect(self._update_error)
|
||||||
@ -179,25 +185,25 @@ class UpdateThread(QtCore.QThread):
|
|||||||
u.check(config=self.config,force=self.force)
|
u.check(config=self.config,force=self.force)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# If update check fails, silently ignore
|
# If update check fails, silently ignore
|
||||||
common.log('UpdateThread', 'run', '{}'.format(e))
|
self.common.log('UpdateThread', 'run', '{}'.format(e))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _update_available(self, update_url, installed_version, latest_version):
|
def _update_available(self, update_url, installed_version, latest_version):
|
||||||
common.log('UpdateThread', '_update_available')
|
self.common.log('UpdateThread', '_update_available')
|
||||||
self.active = False
|
self.active = False
|
||||||
self.update_available.emit(update_url, installed_version, latest_version)
|
self.update_available.emit(update_url, installed_version, latest_version)
|
||||||
|
|
||||||
def _update_not_available(self):
|
def _update_not_available(self):
|
||||||
common.log('UpdateThread', '_update_not_available')
|
self.common.log('UpdateThread', '_update_not_available')
|
||||||
self.active = False
|
self.active = False
|
||||||
self.update_not_available.emit()
|
self.update_not_available.emit()
|
||||||
|
|
||||||
def _update_error(self):
|
def _update_error(self):
|
||||||
common.log('UpdateThread', '_update_error')
|
self.common.log('UpdateThread', '_update_error')
|
||||||
self.active = False
|
self.active = False
|
||||||
self.update_error.emit()
|
self.update_error.emit()
|
||||||
|
|
||||||
def _update_invalid_version(self):
|
def _update_invalid_version(self):
|
||||||
common.log('UpdateThread', '_update_invalid_version')
|
self.common.log('UpdateThread', '_update_invalid_version')
|
||||||
self.active = False
|
self.active = False
|
||||||
self.update_invalid_version.emit()
|
self.update_invalid_version.emit()
|
||||||
|
@ -157,13 +157,13 @@ class TestGetAvailablePort:
|
|||||||
|
|
||||||
class TestGetPlatform:
|
class TestGetPlatform:
|
||||||
def test_darwin(self, platform_darwin):
|
def test_darwin(self, platform_darwin):
|
||||||
assert common.get_platform() == 'Darwin'
|
assert common.platform == 'Darwin'
|
||||||
|
|
||||||
def test_linux(self, platform_linux):
|
def test_linux(self, platform_linux):
|
||||||
assert common.get_platform() == 'Linux'
|
assert common.platform == 'Linux'
|
||||||
|
|
||||||
def test_windows(self, platform_windows):
|
def test_windows(self, platform_windows):
|
||||||
assert common.get_platform() == 'Windows'
|
assert common.platform == 'Windows'
|
||||||
|
|
||||||
|
|
||||||
# TODO: double-check these tests
|
# TODO: double-check these tests
|
||||||
@ -235,14 +235,6 @@ class TestGetTorPaths:
|
|||||||
(tor_path, tor_geo_ip_file_path, tor_geo_ipv6_file_path, obfs4proxy_file_path))
|
(tor_path, tor_geo_ip_file_path, tor_geo_ipv6_file_path, obfs4proxy_file_path))
|
||||||
|
|
||||||
|
|
||||||
class TestGetVersion:
|
|
||||||
def test_get_version(self, sys_onionshare_dev_mode):
|
|
||||||
with open(common.get_resource_path('version.txt')) as f:
|
|
||||||
version = f.read().strip()
|
|
||||||
|
|
||||||
assert version == common.get_version()
|
|
||||||
|
|
||||||
|
|
||||||
class TestHumanReadableFilesize:
|
class TestHumanReadableFilesize:
|
||||||
@pytest.mark.parametrize('test_input,expected', (
|
@pytest.mark.parametrize('test_input,expected', (
|
||||||
(1024 ** 0, '1.0 B'),
|
(1024 ** 0, '1.0 B'),
|
||||||
@ -284,13 +276,3 @@ class TestLog:
|
|||||||
line_one, line_two, _ = output.split('\n')
|
line_one, line_two, _ = output.split('\n')
|
||||||
assert LOG_MSG_REGEX.match(line_one)
|
assert LOG_MSG_REGEX.match(line_one)
|
||||||
assert LOG_MSG_REGEX.match(line_two)
|
assert LOG_MSG_REGEX.match(line_two)
|
||||||
|
|
||||||
|
|
||||||
class TestSetDebug:
|
|
||||||
def test_debug_true(self, set_debug_false):
|
|
||||||
common.set_debug(True)
|
|
||||||
assert common.debug is True
|
|
||||||
|
|
||||||
def test_debug_false(self, set_debug_true):
|
|
||||||
common.set_debug(False)
|
|
||||||
assert common.debug is False
|
|
||||||
|
@ -28,7 +28,7 @@ from onionshare import common, settings, strings
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def custom_version(monkeypatch):
|
def custom_version(monkeypatch):
|
||||||
monkeypatch.setattr(common, 'get_version', lambda: 'DUMMY_VERSION_1.2.3')
|
monkeypatch.setattr(common, 'version', 'DUMMY_VERSION_1.2.3')
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
Loading…
Reference in New Issue
Block a user