diff options
| -rw-r--r-- | changes/bug_enable_eip_whenever_possible | 1 | ||||
| -rw-r--r-- | src/leap/bitmask/backend.py | 89 | ||||
| -rw-r--r-- | src/leap/bitmask/gui/mainwindow.py | 87 | 
3 files changed, 160 insertions, 17 deletions
| diff --git a/changes/bug_enable_eip_whenever_possible b/changes/bug_enable_eip_whenever_possible new file mode 100644 index 00000000..1065822f --- /dev/null +++ b/changes/bug_enable_eip_whenever_possible @@ -0,0 +1 @@ +- Enable Turn ON button for EIP whenever possible (json and cert are in place). Fixes #5665, #5666.
\ No newline at end of file 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." % | 
