From bc424a8d5c9bdd64d837e27636b4b02d8be7d582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Tue, 13 May 2014 16:15:57 -0300 Subject: Enable EIP whenever possible --- src/leap/bitmask/backend.py | 89 +++++++++++++++++++++++++++++++++++--- src/leap/bitmask/gui/mainwindow.py | 87 ++++++++++++++++++++++++++++++++----- 2 files changed, 159 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 2bfcbfa0..8dd9f799 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -41,6 +41,8 @@ from leap.bitmask.services.eip.eipbootstrapper import EIPBootstrapper from leap.bitmask.services.eip import vpnlauncher, vpnprocess from leap.bitmask.services.eip import linuxvpnlauncher, darwinvpnlauncher +from leap.common import certs as leap_certs + # Frontend side from PySide import QtCore @@ -275,18 +277,23 @@ class EIP(object): self._vpn = vpnprocess.VPN(signaler=signaler) - def setup_eip(self, domain): + def setup_eip(self, domain, skip_network=False): """ Initiate the setup for a provider :param domain: URL for the provider :type domain: unicode + :param skip_network: Whether checks that involve network should be done + or not + :type skip_network: bool :returns: the defer for the operation running in a thread. :rtype: twisted.internet.defer.Deferred """ config = self._provider_config if get_provider_config(config, domain): + if skip_network: + return defer.Deferred() eb = self._eip_bootstrapper d = eb.run_eip_setup_checks(self._provider_config, download_if_needed=True) @@ -334,7 +341,8 @@ class EIP(object): if not self._provider_config.loaded(): # This means that the user didn't call setup_eip first. - self._signaler.signal(signaler.BACKEND_BAD_CALL) + self._signaler.signal(signaler.BACKEND_BAD_CALL, "EIP.start(), " + "no provider loaded") return try: @@ -457,6 +465,47 @@ class EIP(object): self._signaler.signal( self._signaler.EIP_GET_GATEWAYS_LIST, gateways) + def can_start(self, domain): + """ + Signal whether it has everything that is needed to run EIP or not + + :param domain: the domain for the provider to check + :type domain: str + + Signals: + eip_can_start + eip_cannot_start + """ + try: + eip_config = eipconfig.EIPConfig() + provider_config = ProviderConfig.get_provider_config(domain) + + api_version = provider_config.get_api_version() + eip_config.set_api_version(api_version) + eip_loaded = eip_config.load(eipconfig.get_eipconfig_path(domain)) + + # check for other problems + if not eip_loaded or provider_config is None: + raise Exception("Cannot load provider and eip config, cannot " + "autostart") + + client_cert_path = eip_config.\ + get_client_cert_path(provider_config, about_to_download=False) + + if leap_certs.should_redownload(client_cert_path): + raise Exception("The client should redownload the certificate," + " cannot autostart") + + if not os.path.isfile(client_cert_path): + raise Exception("Can't find the certificate, cannot autostart") + + if self._signaler is not None: + self._signaler.signal(self._signaler.EIP_CAN_START) + except Exception as e: + logger.exception(e) + if self._signaler is not None: + self._signaler.signal(self._signaler.EIP_CANNOT_START) + class Authenticate(object): """ @@ -647,6 +696,10 @@ class Signaler(QtCore.QObject): eip_status_changed = QtCore.Signal(dict) eip_process_finished = QtCore.Signal(int) + # signals whether the needed files to start EIP exist or not + eip_can_start = QtCore.Signal(object) + eip_cannot_start = QtCore.Signal(object) + # This signal is used to warn the backend user that is doing something # wrong backend_bad_call = QtCore.Signal(object) @@ -713,6 +766,9 @@ class Signaler(QtCore.QObject): EIP_STATUS_CHANGED = "eip_status_changed" EIP_PROCESS_FINISHED = "eip_process_finished" + EIP_CAN_START = "eip_can_start" + EIP_CANNOT_START = "eip_cannot_start" + BACKEND_BAD_CALL = "backend_bad_call" def __init__(self): @@ -767,6 +823,9 @@ class Signaler(QtCore.QObject): self.EIP_STATUS_CHANGED, self.EIP_PROCESS_FINISHED, + self.EIP_CAN_START, + self.EIP_CANNOT_START, + self.SRP_AUTH_OK, self.SRP_AUTH_ERROR, self.SRP_AUTH_SERVER_ERROR, @@ -1001,19 +1060,23 @@ class Backend(object): self._call_queue.put(("register", "register_user", None, provider, username, password)) - def setup_eip(self, provider): + def setup_eip(self, provider, skip_network=False): """ Initiate the setup for a provider - :param domain: URL for the provider - :type domain: unicode + :param provider: URL for the provider + :type provider: unicode + :param skip_network: Whether checks that involve network should be done + or not + :type skip_network: bool Signals: eip_config_ready -> {PASSED_KEY: bool, ERROR_KEY: str} eip_client_certificate_ready -> {PASSED_KEY: bool, ERROR_KEY: str} eip_cancelled_setup """ - self._call_queue.put(("eip", "setup_eip", None, provider)) + self._call_queue.put(("eip", "setup_eip", None, provider, + skip_network)) def cancel_setup_eip(self): """ @@ -1089,6 +1152,20 @@ class Backend(object): self._call_queue.put(("eip", "get_initialized_providers", None, domains)) + def eip_can_start(self, domain): + """ + Signal whether it has everything that is needed to run EIP or not + + :param domain: the domain for the provider to check + :type domain: str + + Signals: + eip_can_start + eip_cannot_start + """ + self._call_queue.put(("eip", "can_start", + None, domain)) + def login(self, provider, username, password): """ Execute the whole authentication process for a user diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 1a88fcce..6e270de1 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -182,6 +182,8 @@ class MainWindow(QtGui.QMainWindow): self.eip_needs_login.connect(self._eip_status.disable_eip_start) self.eip_needs_login.connect(self._disable_eip_start_action) + self._trying_to_start_eip = False + # This is loaded only once, there's a bug when doing that more # than once # XXX HACK!! But we need it as long as we are using @@ -357,11 +359,24 @@ class MainWindow(QtGui.QMainWindow): self._backend_connected_signals[signal] = method signal.connect(method) + def _backend_bad_call(self, data): + """ + Callback for debugging bad backend calls + + :param data: data from the backend about the problem + :type data: str + """ + logger.error("Bad call to the backend:") + logger.error(data) + def _backend_connect(self): """ Helper to connect to backend signals """ sig = self._backend.signaler + + sig.backend_bad_call.connect(self._backend_bad_call) + self._connect_and_track(sig.prov_name_resolution, self._intermediate_stage) self._connect_and_track(sig.prov_https_connection, @@ -442,6 +457,9 @@ class MainWindow(QtGui.QMainWindow): sig.eip_process_restart_tls.connect(self._do_eip_restart) sig.eip_process_restart_ping.connect(self._do_eip_restart) + sig.eip_can_start.connect(self._backend_can_start_eip) + sig.eip_cannot_start.connect(self._backend_cannot_start_eip) + def _disconnect_and_untrack(self): """ Helper to disconnect the tracked signals. @@ -609,17 +627,43 @@ class MainWindow(QtGui.QMainWindow): """ settings = self._settings default_provider = settings.get_defaultprovider() + + if default_provider is None: + logger.warning("Trying toupdate eip enabled status but there's no" + " default provider. Disabling EIP for the time" + " being...") + self._backend_cannot_start_eip() + return + + self._trying_to_start_eip = settings.get_autostart_eip() + self._backend.eip_can_start(default_provider) + + # If we don't want to start eip, we leave everything + # initialized to quickly start it + if not self._trying_to_start_eip: + self._backend.setup_eip(default_provider, skip_network=True) + + def _backend_can_start_eip(self): + """ + TRIGGER: + self._backend.signaler.eip_can_start + + If EIP can be started right away, and the client is configured + to do so, start it. Otherwise it leaves everything in place + for the user to click Turn ON. + """ + settings = self._settings + default_provider = settings.get_defaultprovider() enabled_services = [] if default_provider is not None: enabled_services = settings.get_enabled_services(default_provider) eip_enabled = False if EIP_SERVICE in enabled_services: - should_autostart = settings.get_autostart_eip() - if should_autostart and default_provider is not None: + eip_enabled = True + if default_provider is not None: self._eip_status.enable_eip_start() self._eip_status.set_eip_status("") - eip_enabled = True else: # we don't have an usable provider # so the user needs to log in first @@ -629,7 +673,32 @@ class MainWindow(QtGui.QMainWindow): self._eip_status.disable_eip_start() self._eip_status.set_eip_status(self.tr("Disabled")) - return eip_enabled + if eip_enabled and self._trying_to_start_eip: + self._trying_to_start_eip = False + self._try_autostart_eip() + + def _backend_cannot_start_eip(self): + """ + TRIGGER: + self._backend.signaler.eip_cannot_start + + If EIP can't be started right away, get the UI to what it + needs to look like and waits for a proper login/eip bootstrap. + """ + settings = self._settings + default_provider = settings.get_defaultprovider() + enabled_services = [] + if default_provider is not None: + enabled_services = settings.get_enabled_services(default_provider) + + if EIP_SERVICE in enabled_services: + # we don't have a usable provider + # so the user needs to log in first + self._eip_status.disable_eip_start() + else: + self._stop_eip() + self._eip_status.disable_eip_start() + self._eip_status.set_eip_status(self.tr("Disabled")) @QtCore.Slot() def _show_eip_preferences(self): @@ -749,7 +818,7 @@ class MainWindow(QtGui.QMainWindow): self._wizard = None self._backend_connect() else: - self._try_autostart_eip() + self._update_eip_enabled_status() domain = self._settings.get_provider() if domain is not None: @@ -1589,23 +1658,19 @@ class MainWindow(QtGui.QMainWindow): Tries to autostart EIP """ settings = self._settings - - if not self._update_eip_enabled_status(): - return - default_provider = settings.get_defaultprovider() self._enabled_services = settings.get_enabled_services( default_provider) loaded = self._provisional_provider_config.load( provider.get_provider_path(default_provider)) - if loaded: + if loaded and settings.get_autostart_eip(): # XXX I think we should not try to re-download config every time, # it adds some delay. # Maybe if it's the first run in a session, # or we can try only if it fails. self._maybe_start_eip() - else: + elif settings.get_autostart_eip(): # XXX: Display a proper message to the user self.eip_needs_login.emit() logger.error("Unable to load %s config, cannot autostart." % -- cgit v1.2.3