Merge pull request #1239 from micahflee/1214_onion_error_translations

Translate Tor-related error messages
This commit is contained in:
Micah Lee 2020-12-01 22:21:25 -08:00 committed by GitHub
commit 5f612a94a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 189 additions and 73 deletions

View File

@ -340,7 +340,7 @@ def main(cwd=None):
print("")
sys.exit()
except Exception as e:
sys.exit(e.args[0])
sys.exit()
# Start the onionshare app
try:

View File

@ -34,8 +34,6 @@ import psutil
from distutils.version import LooseVersion as Version
from .settings import Settings
# TODO: Figure out how to localize this for the GUI
class TorErrorAutomatic(Exception):
"""
@ -89,11 +87,15 @@ class TorErrorProtocolError(Exception):
"""
class TorTooOld(Exception):
class TorTooOldEphemeral(Exception):
"""
This exception is raised if onionshare needs to use a feature of Tor or stem
(like stealth ephemeral onion services) but the version you have installed
is too old.
This exception is raised if the version of tor doesn't support ephemeral onion services
"""
class TorTooOldStealth(Exception):
"""
This exception is raised if the version of tor doesn't support stealth onion services
"""
@ -118,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):
"""
Onion is an abstraction layer for connecting to the Tor control port and
@ -214,7 +222,8 @@ class Onion(object):
try:
self.tor_socks_port = self.common.get_available_port(1000, 65535)
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")
# If there is an existing OnionShare tor process, kill it
@ -246,7 +255,8 @@ class Onion(object):
try:
self.tor_control_port = self.common.get_available_port(1000, 65535)
except:
raise OSError("OnionShare port not available")
print("OnionShare port not available")
raise PortNotAvailable()
self.tor_control_socket = None
else:
# Linux and BSD can use unix sockets
@ -315,10 +325,6 @@ class Onion(object):
f.write(self.settings.get("tor_bridges_use_custom_bridges"))
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
start_ts = time.time()
if self.common.platform == "Windows":
@ -353,10 +359,8 @@ class Onion(object):
self.c = Controller.from_socket_file(path=self.tor_control_socket)
self.c.authenticate()
except Exception as e:
raise BundledTorBroken(
# strings._("settings_error_bundled_tor_broken").format(e.args[0])
"OnionShare could not connect to Tor:\n{}".format(e.args[0])
)
print("OnionShare could not connect to Tor:\n{}".format(e.args[0]))
raise BundledTorBroken(e.args[0])
while True:
try:
@ -403,15 +407,16 @@ class Onion(object):
print("")
try:
self.tor_proc.terminate()
raise BundledTorTimeout(
# strings._("settings_error_bundled_tor_timeout")
print(
"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:
pass
elif self.settings.get("connection_type") == "automatic":
# 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
found_tor = False
@ -463,30 +468,25 @@ class Onion(object):
)
elif self.common.platform == "Windows":
# Windows doesn't support unix sockets
raise TorErrorAutomatic(
# strings._("settings_error_automatic")
"Could not connect to the Tor controller. Is Tor Browser (available from torproject.org) running in the background?"
)
print(automatic_error)
raise TorErrorAutomatic()
self.c = Controller.from_socket_file(path=socket_file_path)
except:
raise TorErrorAutomatic(
# strings._("settings_error_automatic")
"Could not connect to the Tor controller. Is Tor Browser (available from torproject.org) running in the background?"
)
print(automatic_error)
raise TorErrorAutomatic()
# Try authenticating
try:
self.c.authenticate()
except:
raise TorErrorAutomatic(
# strings._("settings_error_automatic")
"Could not connect to the Tor controller. Is Tor Browser (available from torproject.org) running in the background?"
)
print(automatic_error)
raise TorErrorAutomatic()
else:
# 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:
@ -500,27 +500,28 @@ class Onion(object):
path=self.settings.get("socket_file_path")
)
else:
raise TorErrorInvalidSetting(
# strings._("settings_error_unknown")
"Can't connect to Tor controller because your settings don't make sense."
)
print(invalid_settings_error)
raise TorErrorInvalidSetting()
except:
if self.settings.get("connection_type") == "control_port":
raise TorErrorSocketPort(
# strings._("settings_error_socket_port")
print(
"Can't connect to the Tor controller at {}:{}.".format(
self.settings.get("control_port_address"),
self.settings.get("control_port_port"),
)
)
raise TorErrorSocketPort(
self.settings.get("control_port_address"),
self.settings.get("control_port_port"),
)
else:
raise TorErrorSocketFile(
# strings._("settings_error_socket_file")
print(
"Can't connect to the Tor controller using socket file {}.".format(
self.settings.get("socket_file_path")
)
)
raise TorErrorSocketFile(self.settings.get("socket_file_path"))
# Try authenticating
try:
@ -529,29 +530,30 @@ class Onion(object):
elif self.settings.get("auth_type") == "password":
self.c.authenticate(self.settings.get("auth_password"))
else:
raise TorErrorInvalidSetting(
# strings._("settings_error_unknown")
"Can't connect to Tor controller because your settings don't make sense."
)
print(invalid_settings_error)
raise TorErrorInvalidSetting()
except MissingPassword:
raise TorErrorMissingPassword(
# strings._("settings_error_missing_password")
print(
"Connected to Tor controller, but it requires a password to authenticate."
)
raise TorErrorMissingPassword()
except UnreadableCookieFile:
raise TorErrorUnreadableCookieFile(
# strings._("settings_error_unreadable_cookie_file")
print(
"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:
raise TorErrorAuthError(
# strings._("settings_error_auth")
print(
"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_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
self.connected_to_tor = True
@ -606,15 +608,15 @@ class Onion(object):
self.common.log("Onion", "start_onion_service", f"port={port}")
if not self.supports_ephemeral:
raise TorTooOld(
# strings._("error_ephemeral_not_supported")
print(
"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:
raise TorTooOld(
# strings._("error_stealth_not_supported")
print(
"Your version of Tor is too old, stealth onion services are not supported"
)
raise TorTooOldStealth()
auth_cookie = None
if mode_settings.get("general", "client_auth"):
@ -671,10 +673,8 @@ class Onion(object):
)
except ProtocolError as e:
raise TorErrorProtocolError(
# strings._("error_tor_protocol_error")
"Tor error: {}".format(e.args[0])
)
print("Tor error: {}".format(e.args[0]))
raise TorErrorProtocolError(e.args[0])
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
from . import common
from .onion import TorTooOld, TorErrorProtocolError
from .common import AutoStopTimer

View File

@ -24,7 +24,22 @@ import shutil
from pkg_resources import resource_filename
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:
@ -377,3 +392,37 @@ class GuiCommon:
Returns the absolute path of a resource
"""
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

@ -187,5 +187,6 @@
"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.",
"settings_error_bundled_tor_not_supported": "Using the Tor version that comes with OnionShare does not work in developer mode on Windows or macOS.",
"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{}",
"error_port_not_available": "OnionShare port not available"
}

View File

@ -27,11 +27,31 @@ import os
from onionshare_cli import common
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 .widgets import Alert
from .update_checker import *
from .update_checker import (
UpdateCheckerCheckError,
UpdateCheckerInvalidLatestVersion,
UpdateChecker,
UpdateThread,
)
from .tor_connection_dialog import TorConnectionDialog
from .gui_common import GuiCommon
@ -698,10 +718,18 @@ class SettingsDialog(QtWidgets.QDialog):
TorErrorUnreadableCookieFile,
TorErrorAuthError,
TorErrorProtocolError,
BundledTorNotSupported,
BundledTorTimeout,
BundledTorBroken,
TorTooOldEphemeral,
TorTooOldStealth,
PortNotAvailable,
) 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":
self.tor_status.hide()
self._enable_buttons()

View File

@ -24,7 +24,6 @@ import os
from PySide2 import QtCore
from onionshare_cli.onion import (
TorTooOld,
TorErrorInvalidSetting,
TorErrorAutomatic,
TorErrorSocketPort,
@ -34,6 +33,10 @@ from onionshare_cli.onion import (
TorErrorAuthError,
TorErrorProtocolError,
BundledTorTimeout,
BundledTorBroken,
TorTooOldEphemeral,
TorTooOldStealth,
PortNotAvailable,
)
from . import strings
@ -93,7 +96,6 @@ class OnionThread(QtCore.QThread):
self.success.emit()
except (
TorTooOld,
TorErrorInvalidSetting,
TorErrorAutomatic,
TorErrorSocketPort,
@ -103,9 +105,13 @@ class OnionThread(QtCore.QThread):
TorErrorAuthError,
TorErrorProtocolError,
BundledTorTimeout,
OSError,
BundledTorBroken,
TorTooOldEphemeral,
TorTooOldStealth,
PortNotAvailable,
) as e:
self.error.emit(e.args[0])
message = self.mode.common.gui.get_translated_tor_error(e)
self.error.emit(message)
return
@ -174,7 +180,7 @@ class AutoStartTimer(QtCore.QThread):
class EventHandlerThread(QtCore.QThread):
"""
To trigger an event, write a JSON line to the events file. When that file changes,
To trigger an event, write a JSON line to the events file. When that file changes,
each line will be handled as an event. Valid events are:
{"type": "new_tab"}
{"type": "new_share_tab", "filenames": ["file1", "file2"]}

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/>.
"""
import time
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 .gui_common import GuiCommon
@ -156,9 +172,26 @@ class TorConnectionThread(QtCore.QThread):
)
self.canceled_connecting_to_tor.emit()
except Exception as e:
self.common.log("TorConnectionThread", "run", f"caught exception: {e}")
self.error_connecting_to_tor.emit(str(e))
except (
TorErrorInvalidSetting,
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):
self.tor_status_update.emit(progress, summary)