Merge branch 'develop' into 929_download_errors

This commit is contained in:
Micah Lee 2020-12-13 11:40:25 -08:00
commit b96b83905b
No known key found for this signature in database
GPG key ID: 403C2657CD994F73
15 changed files with 294 additions and 116 deletions

View file

@ -22,7 +22,7 @@ import os, sys, time, argparse, threading
from datetime import datetime from datetime import datetime
from datetime import timedelta from datetime import timedelta
from .common import Common from .common import Common, CannotFindTor
from .web import Web from .web import Web
from .onion import * from .onion import *
from .onionshare import OnionShare from .onionshare import OnionShare
@ -320,7 +320,15 @@ def main(cwd=None):
web = Web(common, False, mode_settings, mode) web = Web(common, False, mode_settings, mode)
# Start the Onion object # Start the Onion object
onion = Onion(common, use_tmp_dir=True) try:
onion = Onion(common, use_tmp_dir=True)
except CannotFindTor:
print("You must install tor to use OnionShare from the command line")
if common.platform == "Darwin":
print("In macOS, you can do this with Homebrew (https://brew.sh):")
print(" brew install tor")
sys.exit()
try: try:
onion.connect( onion.connect(
custom_settings=False, custom_settings=False,
@ -332,7 +340,7 @@ def main(cwd=None):
print("") print("")
sys.exit() sys.exit()
except Exception as e: except Exception as e:
sys.exit(e.args[0]) sys.exit()
# Start the onionshare app # Start the onionshare app
try: try:

View file

@ -34,6 +34,12 @@ from pkg_resources import resource_filename
from .settings import Settings from .settings import Settings
class CannotFindTor(Exception):
"""
OnionShare can't find a tor binary
"""
class Common: class Common:
""" """
The Common object is shared amongst all parts of OnionShare. The Common object is shared amongst all parts of OnionShare.
@ -82,6 +88,8 @@ class Common:
def get_tor_paths(self): def get_tor_paths(self):
if self.platform == "Linux": if self.platform == "Linux":
tor_path = shutil.which("tor") tor_path = shutil.which("tor")
if not tor_path:
raise CannotFindTor()
obfs4proxy_file_path = shutil.which("obfs4proxy") obfs4proxy_file_path = shutil.which("obfs4proxy")
prefix = os.path.dirname(os.path.dirname(tor_path)) prefix = os.path.dirname(os.path.dirname(tor_path))
tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip") tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip")
@ -94,6 +102,8 @@ class Common:
tor_geo_ipv6_file_path = os.path.join(base_path, "Data", "Tor", "geoip6") tor_geo_ipv6_file_path = os.path.join(base_path, "Data", "Tor", "geoip6")
elif self.platform == "Darwin": elif self.platform == "Darwin":
tor_path = shutil.which("tor") tor_path = shutil.which("tor")
if not tor_path:
raise CannotFindTor()
obfs4proxy_file_path = shutil.which("obfs4proxy") obfs4proxy_file_path = shutil.which("obfs4proxy")
prefix = os.path.dirname(os.path.dirname(tor_path)) prefix = os.path.dirname(os.path.dirname(tor_path))
tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip") tor_geo_ip_file_path = os.path.join(prefix, "share/tor/geoip")

View file

@ -32,11 +32,8 @@ import getpass
import psutil import psutil
from distutils.version import LooseVersion as Version from distutils.version import LooseVersion as Version
from . import common
from .settings import Settings from .settings import Settings
# TODO: Figure out how to localize this for the GUI
class TorErrorAutomatic(Exception): class TorErrorAutomatic(Exception):
""" """
@ -44,40 +41,30 @@ class TorErrorAutomatic(Exception):
using automatic settings that should work with Tor Browser. using automatic settings that should work with Tor Browser.
""" """
pass
class TorErrorInvalidSetting(Exception): class TorErrorInvalidSetting(Exception):
""" """
This exception is raised if the settings just don't make sense. This exception is raised if the settings just don't make sense.
""" """
pass
class TorErrorSocketPort(Exception): class TorErrorSocketPort(Exception):
""" """
OnionShare can't connect to the Tor controller using the supplied address and port. OnionShare can't connect to the Tor controller using the supplied address and port.
""" """
pass
class TorErrorSocketFile(Exception): class TorErrorSocketFile(Exception):
""" """
OnionShare can't connect to the Tor controller using the supplied socket file. OnionShare can't connect to the Tor controller using the supplied socket file.
""" """
pass
class TorErrorMissingPassword(Exception): class TorErrorMissingPassword(Exception):
""" """
OnionShare connected to the Tor controller, but it requires a password. OnionShare connected to the Tor controller, but it requires a password.
""" """
pass
class TorErrorUnreadableCookieFile(Exception): class TorErrorUnreadableCookieFile(Exception):
""" """
@ -85,8 +72,6 @@ class TorErrorUnreadableCookieFile(Exception):
to access the cookie file. to access the cookie file.
""" """
pass
class TorErrorAuthError(Exception): class TorErrorAuthError(Exception):
""" """
@ -94,8 +79,6 @@ class TorErrorAuthError(Exception):
that a Tor controller isn't listening on this port. that a Tor controller isn't listening on this port.
""" """
pass
class TorErrorProtocolError(Exception): class TorErrorProtocolError(Exception):
""" """
@ -103,17 +86,17 @@ class TorErrorProtocolError(Exception):
isn't acting like a Tor controller (such as in Whonix). isn't acting like a Tor controller (such as in Whonix).
""" """
pass
class TorTooOldEphemeral(Exception):
class TorTooOld(Exception):
""" """
This exception is raised if onionshare needs to use a feature of Tor or stem This exception is raised if the version of tor doesn't support ephemeral onion services
(like stealth ephemeral onion services) but the version you have installed
is too old.
""" """
pass
class TorTooOldStealth(Exception):
"""
This exception is raised if the version of tor doesn't support stealth onion services
"""
class BundledTorTimeout(Exception): class BundledTorTimeout(Exception):
@ -137,6 +120,12 @@ class BundledTorBroken(Exception):
""" """
class PortNotAvailable(Exception):
"""
There are no available ports for OnionShare to use, which really shouldn't ever happen
"""
class Onion(object): class Onion(object):
""" """
Onion is an abstraction layer for connecting to the Tor control port and Onion is an abstraction layer for connecting to the Tor control port and
@ -236,7 +225,8 @@ class Onion(object):
try: try:
self.tor_socks_port = self.common.get_available_port(1000, 65535) self.tor_socks_port = self.common.get_available_port(1000, 65535)
except: except:
raise OSError("OnionShare port not available") print("OnionShare port not available")
raise PortNotAvailable()
self.tor_torrc = os.path.join(self.tor_data_directory_name, "torrc") self.tor_torrc = os.path.join(self.tor_data_directory_name, "torrc")
# If there is an existing OnionShare tor process, kill it # If there is an existing OnionShare tor process, kill it
@ -268,7 +258,8 @@ class Onion(object):
try: try:
self.tor_control_port = self.common.get_available_port(1000, 65535) self.tor_control_port = self.common.get_available_port(1000, 65535)
except: except:
raise OSError("OnionShare port not available") print("OnionShare port not available")
raise PortNotAvailable()
self.tor_control_socket = None self.tor_control_socket = None
else: else:
# Linux and BSD can use unix sockets # Linux and BSD can use unix sockets
@ -337,10 +328,6 @@ class Onion(object):
f.write(self.settings.get("tor_bridges_use_custom_bridges")) f.write(self.settings.get("tor_bridges_use_custom_bridges"))
f.write("\nUseBridges 1") f.write("\nUseBridges 1")
# Make sure the tor path is accurate
if not os.path.exists(self.tor_path):
raise BundledTorNotSupported(f"Cannot find tor binary: {self.tor_path}")
# Execute a tor subprocess # Execute a tor subprocess
start_ts = time.time() start_ts = time.time()
if self.common.platform == "Windows": if self.common.platform == "Windows":
@ -375,10 +362,8 @@ class Onion(object):
self.c = Controller.from_socket_file(path=self.tor_control_socket) self.c = Controller.from_socket_file(path=self.tor_control_socket)
self.c.authenticate() self.c.authenticate()
except Exception as e: except Exception as e:
raise BundledTorBroken( print("OnionShare could not connect to Tor:\n{}".format(e.args[0]))
# strings._("settings_error_bundled_tor_broken").format(e.args[0]) raise BundledTorBroken(e.args[0])
"OnionShare could not connect to Tor:\n{}".format(e.args[0])
)
while True: while True:
try: try:
@ -425,15 +410,16 @@ class Onion(object):
print("") print("")
try: try:
self.tor_proc.terminate() self.tor_proc.terminate()
raise BundledTorTimeout( print(
# strings._("settings_error_bundled_tor_timeout")
"Taking too long to connect to Tor. Maybe you aren't connected to the Internet, or have an inaccurate system clock?" "Taking too long to connect to Tor. Maybe you aren't connected to the Internet, or have an inaccurate system clock?"
) )
raise BundledTorTimeout()
except FileNotFoundError: except FileNotFoundError:
pass pass
elif self.settings.get("connection_type") == "automatic": elif self.settings.get("connection_type") == "automatic":
# Automatically try to guess the right way to connect to Tor Browser # Automatically try to guess the right way to connect to Tor Browser
automatic_error = "Could not connect to the Tor controller. Is Tor Browser (available from torproject.org) running in the background?"
# Try connecting to control port # Try connecting to control port
found_tor = False found_tor = False
@ -485,30 +471,25 @@ class Onion(object):
) )
elif self.common.platform == "Windows": elif self.common.platform == "Windows":
# Windows doesn't support unix sockets # Windows doesn't support unix sockets
raise TorErrorAutomatic( print(automatic_error)
# strings._("settings_error_automatic") raise TorErrorAutomatic()
"Could not connect to the Tor controller. Is Tor Browser (available from torproject.org) running in the background?"
)
self.c = Controller.from_socket_file(path=socket_file_path) self.c = Controller.from_socket_file(path=socket_file_path)
except: except:
raise TorErrorAutomatic( print(automatic_error)
# strings._("settings_error_automatic") raise TorErrorAutomatic()
"Could not connect to the Tor controller. Is Tor Browser (available from torproject.org) running in the background?"
)
# Try authenticating # Try authenticating
try: try:
self.c.authenticate() self.c.authenticate()
except: except:
raise TorErrorAutomatic( print(automatic_error)
# strings._("settings_error_automatic") raise TorErrorAutomatic()
"Could not connect to the Tor controller. Is Tor Browser (available from torproject.org) running in the background?"
)
else: else:
# Use specific settings to connect to tor # Use specific settings to connect to tor
invalid_settings_error = "Can't connect to Tor controller because your settings don't make sense."
# Try connecting # Try connecting
try: try:
@ -522,27 +503,28 @@ class Onion(object):
path=self.settings.get("socket_file_path") path=self.settings.get("socket_file_path")
) )
else: else:
raise TorErrorInvalidSetting( print(invalid_settings_error)
# strings._("settings_error_unknown") raise TorErrorInvalidSetting()
"Can't connect to Tor controller because your settings don't make sense."
)
except: except:
if self.settings.get("connection_type") == "control_port": if self.settings.get("connection_type") == "control_port":
raise TorErrorSocketPort( print(
# strings._("settings_error_socket_port")
"Can't connect to the Tor controller at {}:{}.".format( "Can't connect to the Tor controller at {}:{}.".format(
self.settings.get("control_port_address"), self.settings.get("control_port_address"),
self.settings.get("control_port_port"), self.settings.get("control_port_port"),
) )
) )
raise TorErrorSocketPort(
self.settings.get("control_port_address"),
self.settings.get("control_port_port"),
)
else: else:
raise TorErrorSocketFile( print(
# strings._("settings_error_socket_file")
"Can't connect to the Tor controller using socket file {}.".format( "Can't connect to the Tor controller using socket file {}.".format(
self.settings.get("socket_file_path") self.settings.get("socket_file_path")
) )
) )
raise TorErrorSocketFile(self.settings.get("socket_file_path"))
# Try authenticating # Try authenticating
try: try:
@ -551,29 +533,30 @@ class Onion(object):
elif self.settings.get("auth_type") == "password": elif self.settings.get("auth_type") == "password":
self.c.authenticate(self.settings.get("auth_password")) self.c.authenticate(self.settings.get("auth_password"))
else: else:
raise TorErrorInvalidSetting( print(invalid_settings_error)
# strings._("settings_error_unknown") raise TorErrorInvalidSetting()
"Can't connect to Tor controller because your settings don't make sense."
)
except MissingPassword: except MissingPassword:
raise TorErrorMissingPassword( print(
# strings._("settings_error_missing_password")
"Connected to Tor controller, but it requires a password to authenticate." "Connected to Tor controller, but it requires a password to authenticate."
) )
raise TorErrorMissingPassword()
except UnreadableCookieFile: except UnreadableCookieFile:
raise TorErrorUnreadableCookieFile( print(
# strings._("settings_error_unreadable_cookie_file")
"Connected to the Tor controller, but password may be wrong, or your user is not permitted to read the cookie file." "Connected to the Tor controller, but password may be wrong, or your user is not permitted to read the cookie file."
) )
raise TorErrorUnreadableCookieFile()
except AuthenticationFailure: except AuthenticationFailure:
raise TorErrorAuthError( print(
# strings._("settings_error_auth")
"Connected to {}:{}, but can't authenticate. Maybe this isn't a Tor controller?".format( "Connected to {}:{}, but can't authenticate. Maybe this isn't a Tor controller?".format(
self.settings.get("control_port_address"), self.settings.get("control_port_address"),
self.settings.get("control_port_port"), self.settings.get("control_port_port"),
) )
) )
raise TorErrorAuthError(
self.settings.get("control_port_address"),
self.settings.get("control_port_port"),
)
# If we made it this far, we should be connected to Tor # If we made it this far, we should be connected to Tor
self.connected_to_tor = True self.connected_to_tor = True
@ -628,15 +611,15 @@ class Onion(object):
self.common.log("Onion", "start_onion_service", f"port={port}") self.common.log("Onion", "start_onion_service", f"port={port}")
if not self.supports_ephemeral: if not self.supports_ephemeral:
raise TorTooOld( print(
# strings._("error_ephemeral_not_supported")
"Your version of Tor is too old, ephemeral onion services are not supported" "Your version of Tor is too old, ephemeral onion services are not supported"
) )
raise TorTooOldEphemeral()
if mode_settings.get("general", "client_auth") and not self.supports_stealth: if mode_settings.get("general", "client_auth") and not self.supports_stealth:
raise TorTooOld( print(
# strings._("error_stealth_not_supported")
"Your version of Tor is too old, stealth onion services are not supported" "Your version of Tor is too old, stealth onion services are not supported"
) )
raise TorTooOldStealth()
auth_cookie = None auth_cookie = None
if mode_settings.get("general", "client_auth"): if mode_settings.get("general", "client_auth"):
@ -693,10 +676,8 @@ class Onion(object):
) )
except ProtocolError as e: except ProtocolError as e:
raise TorErrorProtocolError( print("Tor error: {}".format(e.args[0]))
# strings._("error_tor_protocol_error") raise TorErrorProtocolError(e.args[0])
"Tor error: {}".format(e.args[0])
)
onion_host = res.service_id + ".onion" onion_host = res.service_id + ".onion"

View file

@ -21,7 +21,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import os, shutil import os, shutil
from . import common from . import common
from .onion import TorTooOld, TorErrorProtocolError
from .common import AutoStopTimer from .common import AutoStopTimer

View file

@ -51,17 +51,7 @@ Download Tor Browser and extract the binaries:
python scripts\get-tor-windows.py python scripts\get-tor-windows.py
``` ```
### Prepare the code ### Prepare the virtual environment
In order to work with the desktop app, you'll need to build a wheel of the CLI package first, and copy it into the `desktop` folder:
```sh
cd ../cli
poetry install
poetry build
cp dist/onionshare_cli-*.whl ../desktop
cd ../desktop
```
OnionShare uses [Briefcase](https://briefcase.readthedocs.io/en/latest/). OnionShare uses [Briefcase](https://briefcase.readthedocs.io/en/latest/).
@ -86,19 +76,30 @@ While your virtual environment is active, install briefcase from pip.
pip install briefcase pip install briefcase
``` ```
Run OnionShare from the source tree like this (`-d` re-installs dependencies, which you'll have to do each time you update the `onionshare-cli` wheel): In order to work with the desktop app, you'll need to build a wheel of the CLI package first, and copy it into the `desktop` folder. You'll need to re-run this script each time you change the CLI code.
```sh
python scripts/rebuild-cli.py
```
### Running OnionShare from the source code tree
Inside the virtual environment, run OnionShare like this to install all of the dependencies:
``` ```
briefcase dev -d briefcase dev -d
``` ```
If you want to pass arguments into `onionshare`, such as to use verbose mode: Once you have the dependencies installed, you can run it using the `dev.sh` script, which lets you use command line arguments, such as to `--verbose` or `--local-only`:
``` ```
cd src ./scripts/dev.sh --help
python -c "import onionshare; onionshare.main()" --help ./scripts/dev.sh -v
./scripts/dev.sh -v --local-only
``` ```
Windows uses `scripts\dev.bat` instead.
## Running tests ## Running tests
Install these packages inside your virtual environment: Install these packages inside your virtual environment:

3
desktop/scripts/dev.bat Normal file
View file

@ -0,0 +1,3 @@
cd src
python -c "import onionshare; onionshare.main()" %*
cd ..

9
desktop/scripts/dev.sh Executable file
View file

@ -0,0 +1,9 @@
#!/bin/bash
# Run OnionShare desktop, allowing you to use command-line arguments
SCRIPTS_DIR="$( cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd )"
cd $SCRIPTS_DIR
cd ../src
python -c "import onionshare; onionshare.main()" $@

45
desktop/scripts/rebuild-cli.py Executable file
View file

@ -0,0 +1,45 @@
#!/usr/bin/env python3
"""
This script builds the CLI python wheel, copies it to the desktop folder,
and installs it in the virtual environment.
"""
import inspect
import os
import sys
import glob
import subprocess
import shutil
def main():
# Build paths
root_path = os.path.dirname(
os.path.dirname(
os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
)
)
cli_path = os.path.join(root_path, "cli")
desktop_path = os.path.join(root_path, "desktop")
# Delete old wheels
for filename in glob.glob(os.path.join(cli_path, "dist", "*.whl")):
os.remove(filename)
# Build new wheel
subprocess.call(["poetry", "install"], cwd=cli_path)
subprocess.call(["poetry", "build"], cwd=cli_path)
wheel_filename = glob.glob(os.path.join(cli_path, "dist", "*.whl"))[0]
wheel_basename = os.path.basename(wheel_filename)
shutil.copyfile(
wheel_filename,
os.path.join(desktop_path, wheel_basename),
)
# Reinstall the new wheel
subprocess.call(["pip", "uninstall", "onionshare-cli", "-y"])
subprocess.call(["pip", "install", os.path.join(desktop_path, wheel_basename)])
if __name__ == "__main__":
main()

View file

@ -24,7 +24,22 @@ import shutil
from pkg_resources import resource_filename from pkg_resources import resource_filename
from . import strings from . import strings
from onionshare_cli.onion import Onion from onionshare_cli.onion import (
Onion,
TorErrorInvalidSetting,
TorErrorAutomatic,
TorErrorSocketPort,
TorErrorSocketFile,
TorErrorMissingPassword,
TorErrorUnreadableCookieFile,
TorErrorAuthError,
TorErrorProtocolError,
BundledTorTimeout,
BundledTorBroken,
TorTooOldEphemeral,
TorTooOldStealth,
PortNotAvailable,
)
class GuiCommon: class GuiCommon:
@ -245,7 +260,7 @@ class GuiCommon:
QLabel { QLabel {
text-align: center; text-align: center;
color: #333333; color: #333333;
font-size: 28px; font-size: 25px;
} }
""", """,
# Share mode and child widget styles # Share mode and child widget styles
@ -377,3 +392,37 @@ class GuiCommon:
Returns the absolute path of a resource Returns the absolute path of a resource
""" """
return resource_filename("onionshare", os.path.join("resources", filename)) return resource_filename("onionshare", os.path.join("resources", filename))
@staticmethod
def get_translated_tor_error(e):
"""
Takes an exception defined in onion.py and returns a translated error message
"""
if type(e) is TorErrorInvalidSetting:
return strings._("settings_error_unknown")
elif type(e) is TorErrorAutomatic:
return strings._("settings_error_automatic")
elif type(e) is TorErrorSocketPort:
return strings._("settings_error_socket_port").format(e.args[0], e.args[1])
elif type(e) is TorErrorSocketFile:
return strings._("settings_error_socket_file").format(e.args[0])
elif type(e) is TorErrorMissingPassword:
return strings._("settings_error_missing_password")
elif type(e) is TorErrorUnreadableCookieFile:
return strings._("settings_error_unreadable_cookie_file")
elif type(e) is TorErrorAuthError:
return strings._("settings_error_auth").format(e.args[0], e.args[1])
elif type(e) is TorErrorProtocolError:
return strings._("error_tor_protocol_error").format(e.args[0])
elif type(e) is BundledTorTimeout:
return strings._("settings_error_bundled_tor_timeout")
elif type(e) is BundledTorBroken:
return strings._("settings_error_bundled_tor_broken").format(e.args[0])
elif type(e) is TorTooOldEphemeral:
return strings._("error_ephemeral_not_supported")
elif type(e) is TorTooOldStealth:
return strings._("error_stealth_not_supported")
elif type(e) is PortNotAvailable:
return strings._("error_port_not_available")
return None

View file

@ -189,5 +189,6 @@
"settings_error_bundled_tor_timeout": "Taking too long to connect to Tor. Maybe you aren't connected to the Internet, or have an inaccurate system clock?", "settings_error_bundled_tor_timeout": "Taking too long to connect to Tor. Maybe you aren't connected to the Internet, or have an inaccurate system clock?",
"settings_error_bundled_tor_broken": "OnionShare could not connect to Tor:\n{}", "settings_error_bundled_tor_broken": "OnionShare could not connect to Tor:\n{}",
"gui_rendezvous_cleanup": "Waiting for Tor circuits to close to be sure your files have successfully transferred.\n\nThis might take a few minutes.", "gui_rendezvous_cleanup": "Waiting for Tor circuits to close to be sure your files have successfully transferred.\n\nThis might take a few minutes.",
"gui_rendezvous_cleanup_quit_early": "Quit Early" "gui_rendezvous_cleanup_quit_early": "Quit Early",
"error_port_not_available": "OnionShare port not available"
} }

View file

@ -27,11 +27,31 @@ import os
from onionshare_cli import common from onionshare_cli import common
from onionshare_cli.settings import Settings from onionshare_cli.settings import Settings
from onionshare_cli.onion import * from onionshare_cli.onion import (
Onion,
TorErrorInvalidSetting,
TorErrorAutomatic,
TorErrorSocketPort,
TorErrorSocketFile,
TorErrorMissingPassword,
TorErrorUnreadableCookieFile,
TorErrorAuthError,
TorErrorProtocolError,
BundledTorTimeout,
BundledTorBroken,
TorTooOldEphemeral,
TorTooOldStealth,
PortNotAvailable,
)
from . import strings from . import strings
from .widgets import Alert from .widgets import Alert
from .update_checker import * from .update_checker import (
UpdateCheckerCheckError,
UpdateCheckerInvalidLatestVersion,
UpdateChecker,
UpdateThread,
)
from .tor_connection_dialog import TorConnectionDialog from .tor_connection_dialog import TorConnectionDialog
from .gui_common import GuiCommon from .gui_common import GuiCommon
@ -142,7 +162,7 @@ class SettingsDialog(QtWidgets.QDialog):
self.tor_geo_ip_file_path, self.tor_geo_ip_file_path,
self.tor_geo_ipv6_file_path, self.tor_geo_ipv6_file_path,
self.obfs4proxy_file_path, self.obfs4proxy_file_path,
) = self.common.get_tor_paths() ) = self.common.gui.get_tor_paths()
if not self.obfs4proxy_file_path or not os.path.isfile( if not self.obfs4proxy_file_path or not os.path.isfile(
self.obfs4proxy_file_path self.obfs4proxy_file_path
): ):
@ -165,7 +185,7 @@ class SettingsDialog(QtWidgets.QDialog):
self.tor_geo_ip_file_path, self.tor_geo_ip_file_path,
self.tor_geo_ipv6_file_path, self.tor_geo_ipv6_file_path,
self.obfs4proxy_file_path, self.obfs4proxy_file_path,
) = self.common.get_tor_paths() ) = self.common.gui.get_tor_paths()
if not self.obfs4proxy_file_path or not os.path.isfile( if not self.obfs4proxy_file_path or not os.path.isfile(
self.obfs4proxy_file_path self.obfs4proxy_file_path
): ):
@ -698,10 +718,18 @@ class SettingsDialog(QtWidgets.QDialog):
TorErrorUnreadableCookieFile, TorErrorUnreadableCookieFile,
TorErrorAuthError, TorErrorAuthError,
TorErrorProtocolError, TorErrorProtocolError,
BundledTorNotSupported,
BundledTorTimeout, BundledTorTimeout,
BundledTorBroken,
TorTooOldEphemeral,
TorTooOldStealth,
PortNotAvailable,
) as e: ) as e:
Alert(self.common, e.args[0], QtWidgets.QMessageBox.Warning) message = self.common.gui.get_translated_tor_error(e)
Alert(
self.common,
message,
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()

View file

@ -183,8 +183,7 @@ class Mode(QtWidgets.QWidget):
self.status_bar.clearMessage() self.status_bar.clearMessage()
if not self.app.autostop_timer_thread.is_alive(): if not self.app.autostop_timer_thread.is_alive():
if self.autostop_timer_finished_should_stop_server(): self.autostop_timer_finished_should_stop_server()
self.server_status.stop_server()
def timer_callback_custom(self): def timer_callback_custom(self):
""" """

View file

@ -53,16 +53,22 @@ class NewTabButton(QtWidgets.QPushButton):
) )
self.image_label.setAlignment(QtCore.Qt.AlignCenter) self.image_label.setAlignment(QtCore.Qt.AlignCenter)
self.image_label.setStyleSheet(self.common.gui.css["new_tab_button_image"]) self.image_label.setStyleSheet(self.common.gui.css["new_tab_button_image"])
self.image_label.setGeometry(0, 0, self.width(), 200) self.image_label.setGeometry(0, 0, self.width(), 190)
self.image_label.show() self.image_label.show()
# Title # Title
self.title_label = QtWidgets.QLabel(title, parent=self) self.title_label = QtWidgets.QLabel(title, parent=self)
self.title_label.setWordWrap(True)
self.title_label.setAlignment(QtCore.Qt.AlignCenter) self.title_label.setAlignment(QtCore.Qt.AlignCenter)
self.title_label.setStyleSheet(self.common.gui.css["new_tab_title_text"]) self.title_label.setStyleSheet(self.common.gui.css["new_tab_title_text"])
self.title_label.setGeometry( if self.title_label.sizeHint().width() >= 250:
(self.width() - 250) / 2, self.height() - 100, 250, 30 self.title_label.setGeometry(
) (self.width() - 250) / 2, self.height() - 120, 250, 60
)
else:
self.title_label.setGeometry(
(self.width() - 250) / 2, self.height() - 100, 250, 30
)
self.title_label.show() self.title_label.show()
# Text # Text

View file

@ -24,7 +24,6 @@ import os
from PySide2 import QtCore from PySide2 import QtCore
from onionshare_cli.onion import ( from onionshare_cli.onion import (
TorTooOld,
TorErrorInvalidSetting, TorErrorInvalidSetting,
TorErrorAutomatic, TorErrorAutomatic,
TorErrorSocketPort, TorErrorSocketPort,
@ -34,6 +33,10 @@ from onionshare_cli.onion import (
TorErrorAuthError, TorErrorAuthError,
TorErrorProtocolError, TorErrorProtocolError,
BundledTorTimeout, BundledTorTimeout,
BundledTorBroken,
TorTooOldEphemeral,
TorTooOldStealth,
PortNotAvailable,
) )
from . import strings from . import strings
@ -93,7 +96,6 @@ class OnionThread(QtCore.QThread):
self.success.emit() self.success.emit()
except ( except (
TorTooOld,
TorErrorInvalidSetting, TorErrorInvalidSetting,
TorErrorAutomatic, TorErrorAutomatic,
TorErrorSocketPort, TorErrorSocketPort,
@ -103,9 +105,13 @@ class OnionThread(QtCore.QThread):
TorErrorAuthError, TorErrorAuthError,
TorErrorProtocolError, TorErrorProtocolError,
BundledTorTimeout, BundledTorTimeout,
OSError, BundledTorBroken,
TorTooOldEphemeral,
TorTooOldStealth,
PortNotAvailable,
) as e: ) as e:
self.error.emit(e.args[0]) message = self.mode.common.gui.get_translated_tor_error(e)
self.error.emit(message)
return return

View file

@ -18,9 +18,25 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
import time
from PySide2 import QtCore, QtWidgets, QtGui from PySide2 import QtCore, QtWidgets, QtGui
from onionshare_cli.onion import * from onionshare_cli.onion import (
BundledTorCanceled,
TorErrorInvalidSetting,
TorErrorAutomatic,
TorErrorSocketPort,
TorErrorSocketFile,
TorErrorMissingPassword,
TorErrorUnreadableCookieFile,
TorErrorAuthError,
TorErrorProtocolError,
BundledTorTimeout,
BundledTorBroken,
TorTooOldEphemeral,
TorTooOldStealth,
PortNotAvailable,
)
from . import strings from . import strings
from .gui_common import GuiCommon from .gui_common import GuiCommon
@ -156,9 +172,26 @@ class TorConnectionThread(QtCore.QThread):
) )
self.canceled_connecting_to_tor.emit() self.canceled_connecting_to_tor.emit()
except Exception as e: except (
self.common.log("TorConnectionThread", "run", f"caught exception: {e}") TorErrorInvalidSetting,
self.error_connecting_to_tor.emit(str(e)) TorErrorAutomatic,
TorErrorSocketPort,
TorErrorSocketFile,
TorErrorMissingPassword,
TorErrorUnreadableCookieFile,
TorErrorAuthError,
TorErrorProtocolError,
BundledTorTimeout,
BundledTorBroken,
TorTooOldEphemeral,
TorTooOldStealth,
PortNotAvailable,
) as e:
message = self.common.gui.get_translated_tor_error(e)
self.common.log(
"TorConnectionThread", "run", f"caught exception: {message}"
)
self.error_connecting_to_tor.emit(message)
def _tor_status_update(self, progress, summary): def _tor_status_update(self, progress, summary):
self.tor_status_update.emit(progress, summary) self.tor_status_update.emit(progress, summary)