diff options
| -rw-r--r-- | src/leap/config/baseconfig.py | 3 | ||||
| -rw-r--r-- | src/leap/config/pluggableconfig.py | 4 | ||||
| -rw-r--r-- | src/leap/config/prefixers.py | 6 | ||||
| -rw-r--r-- | src/leap/config/providerconfig.py | 5 | ||||
| -rw-r--r-- | src/leap/crypto/srpauth.py | 108 | ||||
| -rw-r--r-- | src/leap/crypto/srpregister.py | 17 | ||||
| -rw-r--r-- | src/leap/gui/mainwindow.py | 91 | ||||
| -rw-r--r-- | src/leap/gui/ui/wizard.ui | 5 | ||||
| -rw-r--r-- | src/leap/gui/wizard.py | 91 | ||||
| -rw-r--r-- | src/leap/services/eip/eipbootstrapper.py | 101 | ||||
| -rw-r--r-- | src/leap/services/eip/eipconfig.py | 13 | ||||
| -rw-r--r-- | src/leap/services/eip/providerbootstrapper.py | 137 | ||||
| -rw-r--r-- | src/leap/services/eip/vpn.py | 15 | ||||
| -rw-r--r-- | src/leap/services/eip/vpnlaunchers.py | 24 | ||||
| -rw-r--r-- | src/leap/util/check.py | 61 | ||||
| -rw-r--r-- | src/leap/util/checkerthread.py | 110 | 
16 files changed, 465 insertions, 326 deletions
| diff --git a/src/leap/config/baseconfig.py b/src/leap/config/baseconfig.py index d553255e..b80fd419 100644 --- a/src/leap/config/baseconfig.py +++ b/src/leap/config/baseconfig.py @@ -29,6 +29,7 @@ from abc import ABCMeta, abstractmethod  from leap.config.prefixers import get_platform_prefixer  from leap.config.pluggableconfig import PluggableConfig +from leap.util.check import leap_assert  logger = logging.getLogger(__name__) @@ -58,7 +59,7 @@ class BaseConfig:          @rtype: depends on the config structure, dict, str, array, int          @return: returns the value for the specified key in the config          """ -        assert self._config_checker, "Load the config first" +        leap_assert(self._config_checker, "Load the config first")          return self._config_checker.config[key]      def get_path_prefix(self, standalone=False): diff --git a/src/leap/config/pluggableconfig.py b/src/leap/config/pluggableconfig.py index 64aa05cc..5ed83b3f 100644 --- a/src/leap/config/pluggableconfig.py +++ b/src/leap/config/pluggableconfig.py @@ -28,6 +28,8 @@ import urlparse  import jsonschema  #from leap.base.util.translations import LEAPTranslatable +from leap.util.check import leap_assert +  logger = logging.getLogger(__name__) @@ -378,7 +380,7 @@ class PluggableConfig(object):          # XXX cleanup this!          if fromfile: -            assert os.path.exists(fromfile) +            leap_assert(os.path.exists(fromfile))              if not format:                  format = self.filename2format(fromfile) diff --git a/src/leap/config/prefixers.py b/src/leap/config/prefixers.py index a33e68aa..20d59b2d 100644 --- a/src/leap/config/prefixers.py +++ b/src/leap/config/prefixers.py @@ -24,6 +24,8 @@ import platform  from abc import ABCMeta, abstractmethod  from xdg import BaseDirectory +from leap.util.check import leap_assert +  class Prefixer:      """ @@ -47,8 +49,8 @@ class Prefixer:  def get_platform_prefixer():      prefixer = globals()[platform.system() + "Prefixer"] -    assert prefixer, "Unimplemented platform prefixer: %s" % \ -        (platform.system(),) +    leap_assert(prefixer, "Unimplemented platform prefixer: %s" % +                (platform.system(),))      return prefixer() diff --git a/src/leap/config/providerconfig.py b/src/leap/config/providerconfig.py index c3c2c298..55b33b98 100644 --- a/src/leap/config/providerconfig.py +++ b/src/leap/config/providerconfig.py @@ -23,6 +23,7 @@ import os  from leap.config.baseconfig import BaseConfig, LocalizedKey  from leap.config.provider_spec import leap_provider_spec +from leap.util.check import leap_assert  logger = logging.getLogger(__name__) @@ -95,8 +96,8 @@ class ProviderConfig(BaseConfig):                                   "cacert.pem")          if not about_to_download: -            assert os.path.exists(cert_path), \ -                "You need to download the certificate first" +            leap_assert(os.path.exists(cert_path), +                        "You need to download the certificate first")              logger.debug("Going to verify SSL against %s" % (cert_path,))          return cert_path diff --git a/src/leap/crypto/srpauth.py b/src/leap/crypto/srpauth.py index dbcc95cb..28e4f037 100644 --- a/src/leap/crypto/srpauth.py +++ b/src/leap/crypto/srpauth.py @@ -20,9 +20,11 @@ import srp  import binascii  import logging -from PySide import QtCore +from PySide import QtCore, QtGui  from leap.config.providerconfig import ProviderConfig +from leap.util.check import leap_assert +from leap.util.checkerthread import CheckerThread  logger = logging.getLogger(__name__) @@ -34,7 +36,7 @@ class SRPAuthenticationError(Exception):      pass -class SRPAuth(QtCore.QThread): +class SRPAuth(QtCore.QObject):      """      SRPAuth singleton      """ @@ -55,7 +57,8 @@ class SRPAuth(QtCore.QThread):              @param server: Server to which we will authenticate              @type server: str              """ -            assert provider_config, "We need a provider config to authenticate" +            leap_assert(provider_config, +                        "We need a provider config to authenticate")              self._provider_config = provider_config @@ -277,15 +280,15 @@ class SRPAuth(QtCore.QThread):              @param password: password for this user              @type password: str              """ -            assert self.get_session_id() is None, "Already logged in" +            leap_assert(self.get_session_id() is None, "Already logged in")              self._authentication_preprocessing(username, password)              salt, B = self._start_authentication(username, password)              M2 = self._process_challenge(salt, B, username)              self._verify_session(M2) -            assert self.get_session_id(), "Something went wrong because" + \ -                " we don't have the auth cookie afterwards" +            leap_assert(self.get_session_id(), "Something went wrong because" +                        " we don't have the auth cookie afterwards")          def logout(self):              """ @@ -294,7 +297,8 @@ class SRPAuth(QtCore.QThread):              """              logger.debug("Starting logout...") -            assert self.get_session_id(), "Cannot logout an unexisting session" +            leap_assert(self.get_session_id(), +                        "Cannot logout an unexisting session")              logout_url = "%s/%s/%s/" % (self._provider_config.get_api_uri(),                                          self._provider_config. @@ -344,7 +348,7 @@ class SRPAuth(QtCore.QThread):          """          Creates a singleton instance if needed          """ -        QtCore.QThread.__init__(self) +        QtCore.QObject.__init__(self)          # Check whether we already have an instance          if SRPAuth.__instance is None: @@ -371,47 +375,47 @@ class SRPAuth(QtCore.QThread):          @type password: str          """ -        with QtCore.QMutexLocker(self._should_login_lock): -            self._should_login = self.DO_LOGIN -            self._username = username -            self._password = password -        # Detach the start call to Qt's event loop -        QtCore.QTimer.singleShot(0, self.start) - -    def logout(self): -        """ -        Logs out the current session. -        Expects a session_id to exists, might raise AssertionError -        """ -        QtCore.QMutexLocker(self._should_login_lock) -        self._should_login = self.DO_LOGOUT -        # Detach the start call to Qt's event loop -        QtCore.QTimer.singleShot(0, self.start) - -    def _runLogin(self, username, password):          try:              self.__instance.authenticate(username, password) + +            logger.debug("Successful login!")              self.authentication_finished.emit(True, "Succeeded") +            return True          except Exception as e: +            logger.error("Error logging in %s" % (e,))              self.authentication_finished.emit(False, "%s" % (e,)) +        return False -    def _runLogout(self): +    def logout(self): +        """ +        Logs out the current session. +        Expects a session_id to exists, might raise AssertionError +        """          try:              self.__instance.logout()              self.logout_finished.emit(True, "Succeeded") +            return True          except Exception as e:              self.logout_finished.emit(False, "%s" % (e,)) - -    def run(self): -        QtCore.QMutexLocker(self._should_login_lock) -        if self._should_login == self.DO_LOGIN: -            self._runLogin(self._username, self._password) -        elif self._should_login == self.DO_LOGOUT: -            self._runLogout() -        self._should_login = self.DO_NOTHING +        return False  if __name__ == "__main__": +    import sys +    from functools import partial +    app = QtGui.QApplication(sys.argv) + +    import signal + +    def sigint_handler(*args, **kwargs): +        logger.debug('SIGINT catched. shutting down...') +        checker = args[0] +        checker.set_should_quit() +        QtGui.QApplication.quit() + +    def signal_tester(d): +        print d +      logger = logging.getLogger(name='leap')      logger.setLevel(logging.DEBUG)      console = logging.StreamHandler() @@ -422,8 +426,23 @@ if __name__ == "__main__":      console.setFormatter(formatter)      logger.addHandler(console) -    provider = ProviderConfig() +    checker = CheckerThread() + +    sigint = partial(sigint_handler, checker) +    signal.signal(signal.SIGINT, sigint) +    timer = QtCore.QTimer() +    timer.start(500) +    timer.timeout.connect(lambda: None) +    app.connect(app, QtCore.SIGNAL("aboutToQuit()"), +                checker.set_should_quit) +    w = QtGui.QWidget() +    w.resize(100, 100) +    w.show() + +    checker.start() + +    provider = ProviderConfig()      if provider.load("leap/providers/bitmask.net/provider.json"):          # url = "%s/tickets" % (provider.get_api_uri(),)          # print url @@ -431,9 +450,14 @@ if __name__ == "__main__":          # print res.content          # res.raise_for_status()          auth = SRPAuth(provider) -        auth.start() -        auth.authenticate("test2", "sarasaaaa") -        res = requests.session().get("%s/cert" % (provider.get_api_uri(),), -                                     verify=provider.get_ca_cert_path()) -        print res.content -        auth.logout() +        auth_instantiated = partial(auth.authenticate, "test2", "sarasaaaa") + +        checker.add_checks([auth_instantiated, auth.logout]) + +        #auth.authenticate("test2", "sarasaaaa") +        #res = requests.session().get("%s/cert" % (provider.get_api_uri(),), +                                     #verify=provider.get_ca_cert_path()) +        #print res.content +        #auth.logout() + +    sys.exit(app.exec_()) diff --git a/src/leap/crypto/srpregister.py b/src/leap/crypto/srpregister.py index d9b2b22b..cf673e35 100644 --- a/src/leap/crypto/srpregister.py +++ b/src/leap/crypto/srpregister.py @@ -20,15 +20,17 @@ import binascii  import srp  import logging +from PySide import QtCore  from urlparse import urlparse  from leap.config.providerconfig import ProviderConfig  from leap.crypto.constants import SIGNUP_TIMEOUT +from leap.util.check import leap_assert, leap_assert_type  logger = logging.getLogger(__name__) -class SRPRegister(object): +class SRPRegister(QtCore.QObject):      """      Registers a user to a specific provider using SRP      """ @@ -37,6 +39,8 @@ class SRPRegister(object):      USER_VERIFIER_KEY = 'user[password_verifier]'      USER_SALT_KEY = 'user[password_salt]' +    registration_finished = QtCore.Signal(bool, object) +      def __init__(self,                   provider_config=None,                   register_path="users"): @@ -49,10 +53,9 @@ class SRPRegister(object):          @param register_path: webapp path for registering users          @type register_path; str          """ - -        assert provider_config, "Please provider a provider" -        assert isinstance(provider_config, ProviderConfig), \ -            "We need a ProviderConfig instead of %r" % (provider_config,) +        QtCore.QObject.__init__(self) +        leap_assert(provider_config, "Please provider a provider") +        leap_assert_type(provider_config, ProviderConfig)          self._provider_config = provider_config @@ -131,7 +134,9 @@ class SRPRegister(object):                                   verify=self._provider_config.                                   get_ca_cert_path()) -        return (req.ok, req) +        self.registration_finished.emit(req.ok, req) + +        return req.ok  if __name__ == "__main__": diff --git a/src/leap/gui/mainwindow.py b/src/leap/gui/mainwindow.py index 1821e4a6..50a03fb9 100644 --- a/src/leap/gui/mainwindow.py +++ b/src/leap/gui/mainwindow.py @@ -31,6 +31,8 @@ from leap.services.eip.providerbootstrapper import ProviderBootstrapper  from leap.services.eip.eipbootstrapper import EIPBootstrapper  from leap.services.eip.eipconfig import EIPConfig  from leap.gui.wizard import Wizard +from leap.util.check import leap_assert +from leap.util.checkerthread import CheckerThread  logger = logging.getLogger(__name__) @@ -44,6 +46,9 @@ class MainWindow(QtGui.QMainWindow):      LOGIN_INDEX = 0      EIP_STATUS_INDEX = 1 +    GEOMETRY_KEY = "Geometry" +    WINDOWSTATE_KEY = "WindowState" +      def __init__(self):          QtGui.QMainWindow.__init__(self) @@ -69,6 +74,9 @@ class MainWindow(QtGui.QMainWindow):          # This is created once we have a valid provider config          self._srp_auth = None +        self._checker_thread = CheckerThread() +        self._checker_thread.start() +          # This thread is always running, although it's quite          # lightweight when it's done setting up provider          # configuration and certificate. @@ -110,11 +118,7 @@ class MainWindow(QtGui.QMainWindow):          QtCore.QCoreApplication.instance().connect(              QtCore.QCoreApplication.instance(),              QtCore.SIGNAL("aboutToQuit()"), -            self._provider_bootstrapper.set_should_quit) -        QtCore.QCoreApplication.instance().connect( -            QtCore.QCoreApplication.instance(), -            QtCore.SIGNAL("aboutToQuit()"), -            self._eip_bootstrapper.set_should_quit) +            self._checker_thread.set_should_quit)          self.ui.action_sign_out.setEnabled(False)          self.ui.action_sign_out.triggered.connect(self._logout) @@ -131,17 +135,26 @@ class MainWindow(QtGui.QMainWindow):          self._center_window()          self._wizard = None +        self._wizard_firstrun = False          if self._first_run(): -            self._wizard = Wizard() +            self._wizard_firstrun = True +            self._wizard = Wizard(self._checker_thread)              # Give this window time to finish init and then show the wizard              QtCore.QTimer.singleShot(1, self._launch_wizard) -            self._wizard.finished.connect(self._finish_init) +            self._wizard.accepted.connect(self._finish_init) +            self._wizard.rejected.connect(self._rejected_wizard) +        else: +            self._finish_init() + +    def _rejected_wizard(self): +        if self._wizard_firstrun: +            self.quit()          else:              self._finish_init()      def _launch_wizard(self):          if self._wizard is None: -            self._wizard = Wizard() +            self._wizard = Wizard(self._checker_thread)          self._wizard.exec_()      def _finish_init(self): @@ -187,14 +200,23 @@ class MainWindow(QtGui.QMainWindow):          """          Centers the mainwindow based on the desktop geometry          """ -        app = QtGui.QApplication.instance() -        width = app.desktop().width() -        height = app.desktop().height() -        window_width = self.size().width() -        window_height = self.size().height() -        x = (width / 2.0) - (window_width / 2.0) -        y = (height / 2.0) - (window_height / 2.0) -        self.move(x, y) +        settings = QtCore.QSettings() +        geometry = settings.value(self.GEOMETRY_KEY, None) +        state = settings.value(self.WINDOWSTATE_KEY, None) +        if geometry is None: +            app = QtGui.QApplication.instance() +            width = app.desktop().width() +            height = app.desktop().height() +            window_width = self.size().width() +            window_height = self.size().height() +            x = (width / 2.0) - (window_width / 2.0) +            y = (height / 2.0) - (window_height / 2.0) +            self.move(x, y) +        else: +            self.restoreGeometry(geometry) + +        if state is not None: +            self.restoreState(state)      def _about(self):          """ @@ -236,6 +258,9 @@ class MainWindow(QtGui.QMainWindow):              self._toggle_visible()              e.ignore()              return +        settings = QtCore.QSettings() +        settings.setValue(self.GEOMETRY_KEY, self.saveGeometry()) +        settings.setValue(self.WINDOWSTATE_KEY, self.saveState())          QtGui.QMainWindow.closeEvent(self, e)      def _configured_providers(self): @@ -244,10 +269,16 @@ class MainWindow(QtGui.QMainWindow):          @rtype: list          """ -        providers = os.listdir( -            os.path.join(self._provider_config.get_path_prefix(), -                         "leap", -                         "providers")) +        providers = [] +        try: +            providers = os.listdir( +                os.path.join(self._provider_config.get_path_prefix(), +                             "leap", +                             "providers")) +        except Exception as e: +            logger.debug("Error listing providers, assume there are none. %r" +                         % (e,)) +          return providers      def _first_run(self): @@ -303,8 +334,8 @@ class MainWindow(QtGui.QMainWindow):          """          provider = self.ui.cmbProviders.currentText() -        self._provider_bootstrapper.start()          self._provider_bootstrapper.run_provider_select_checks( +            self._checker_thread,              provider,              download_if_needed=True) @@ -329,6 +360,7 @@ class MainWindow(QtGui.QMainWindow):                                                              provider,                                                              "provider.json")):                  self._provider_bootstrapper.run_provider_setup_checks( +                    self._checker_thread,                      self._provider_config,                      download_if_needed=True)              else: @@ -350,7 +382,7 @@ class MainWindow(QtGui.QMainWindow):          start the SRP authentication, and as the last step          bootstrapping the EIP service          """ -        assert self._provider_config, "We need a provider config" +        leap_assert(self._provider_config, "We need a provider config")          username = self.ui.lnUser.text()          password = self.ui.lnPassword.text() @@ -381,9 +413,7 @@ class MainWindow(QtGui.QMainWindow):          Once the provider configuration is loaded, this starts the SRP          authentication          """ -        assert self._provider_config, "We need a provider config!" - -        self._provider_bootstrapper.set_should_quit() +        leap_assert(self._provider_config, "We need a provider config!")          if data[self._provider_bootstrapper.PASSED_KEY]:              username = self.ui.lnUser.text() @@ -431,14 +461,14 @@ class MainWindow(QtGui.QMainWindow):          """          Starts the EIP bootstrapping sequence          """ -        assert self._eip_bootstrapper, "We need an eip bootstrapper!" -        assert self._provider_config, "We need a provider config" +        leap_assert(self._eip_bootstrapper, "We need an eip bootstrapper!") +        leap_assert(self._provider_config, "We need a provider config")          self._set_eip_status("Checking configuration, please wait...")          if self._provider_config.provides_eip(): -            self._eip_bootstrapper.start()              self._eip_bootstrapper.run_eip_setup_checks( +                self._checker_thread,                  self._provider_config,                  download_if_needed=True)          else: @@ -503,10 +533,9 @@ class MainWindow(QtGui.QMainWindow):          Starts the VPN thread if the eip configuration is properly          loaded          """ -        assert self._eip_config, "We need an eip config!" -        assert self._provider_config, "We need a provider config!" +        leap_assert(self._eip_config, "We need an eip config!") +        leap_assert(self._provider_config, "We need a provider config!") -        self._eip_bootstrapper.set_should_quit()          if self._eip_config.loaded() or \                  self._eip_config.load(os.path.join("leap",                                                     "providers", diff --git a/src/leap/gui/ui/wizard.ui b/src/leap/gui/ui/wizard.ui index 86f8d458..2d9cb441 100644 --- a/src/leap/gui/ui/wizard.ui +++ b/src/leap/gui/ui/wizard.ui @@ -47,7 +47,7 @@      <item row="0" column="0">       <widget class="QLabel" name="label_3">        <property name="text"> -       <string><html><head/><body><p>New we will guide you through some configuration that is needed before you can connect for the first time.</p><p>If you ever need to modify these options again, you can find the wizard in the <span style=" font-style:italic;">'Settings'</span> menu from the main window.</p><p>Do you want to <span style=" font-weight:600;">sign up</span> for a new account, or <span style=" font-weight:600;">log in</span> with an already existing username?</p></body></html></string> +       <string><html><head/><body><p>Now we will guide you through some configuration that is needed before you can connect for the first time.</p><p>If you ever need to modify these options again, you can find the wizard in the <span style=" font-style:italic;">'Settings'</span> menu from the main window.</p><p>Do you want to <span style=" font-weight:600;">sign up</span> for a new account, or <span style=" font-weight:600;">log in</span> with an already existing username?</p></body></html></string>        </property>        <property name="textFormat">         <enum>Qt::RichText</enum> @@ -497,6 +497,9 @@        <property name="text">         <string/>        </property> +      <property name="textFormat"> +       <enum>Qt::AutoText</enum> +      </property>        <property name="alignment">         <set>Qt::AlignCenter</set>        </property> diff --git a/src/leap/gui/wizard.py b/src/leap/gui/wizard.py index 7dcc8dd6..bac74d1d 100644 --- a/src/leap/gui/wizard.py +++ b/src/leap/gui/wizard.py @@ -21,7 +21,8 @@ First run wizard  import os  import logging -from PySide import QtCore, QtGui +from PySide import QtGui +from functools import partial  from ui_wizard import Ui_Wizard  from leap.config.providerconfig import ProviderConfig @@ -45,15 +46,18 @@ class Wizard(QtGui.QWizard):      SETUP_EIP_PAGE = 5      FINISH_PATH = 6 -    WEAK_PASSWORDS = ("1234", "12345", "123456", +    WEAK_PASSWORDS = ("123456", "qweasd", "qwerty",                        "password") -    def __init__(self): +    def __init__(self, checker):          QtGui.QWizard.__init__(self)          self.ui = Ui_Wizard()          self.ui.setupUi(self) +        self.setPixmap(QtGui.QWizard.LogoPixmap, +                       QtGui.QPixmap(":/images/leap-color-small.png")) +          self.QUESTION_ICON = QtGui.QPixmap(":/images/Emblem-question.png")          self.ERROR_ICON = QtGui.QPixmap(":/images/Dialog-error.png")          self.OK_ICON = QtGui.QPixmap(":/images/Dialog-accept.png") @@ -94,6 +98,9 @@ class Wizard(QtGui.QWizard):          self.ui.lblPassword.setEchoMode(QtGui.QLineEdit.Password)          self.ui.lblPassword2.setEchoMode(QtGui.QLineEdit.Password) +        self.ui.lnProvider.textChanged.connect( +            self._enable_check) +          self.ui.lblUser.returnPressed.connect(              self._focus_password)          self.ui.lblPassword.returnPressed.connect( @@ -105,15 +112,14 @@ class Wizard(QtGui.QWizard):          self._username = None -    def __del__(self): -        self._provider_bootstrapper.set_should_quit() -        self._eip_bootstrapper.set_should_quit() -        self._provider_bootstrapper.wait() -        self._eip_bootstrapper.wait() +        self._checker_thread = checker      def get_username(self):          return self._username +    def _enable_check(self, text): +        self.ui.btnCheck.setEnabled(len(self.ui.lnProvider.text()) != 0) +      def _focus_password(self):          """          Focuses at the password lineedit for the registration page @@ -151,13 +157,13 @@ class Wizard(QtGui.QWizard):          if message is not None and password != password2:              message = "Passwords don't match" -        if message is not None and len(password) < 4: +        if message is None and len(password) < 6:              message = "Password too short" -        if message is not None and password in self.WEAK_PASSWORDS: +        if message is None and password in self.WEAK_PASSWORDS:              message = "Password too easy" -        if message is not None and username == password: +        if message is None and username == password:              message = "Password equal to username"          if message is not None: @@ -172,10 +178,6 @@ class Wizard(QtGui.QWizard):          Performs the registration based on the values provided in the form          """          self.ui.btnRegister.setEnabled(False) -        # See the disabled button -        while QtGui.QApplication.instance().hasPendingEvents(): -            QtGui.QApplication.instance().processEvents() -        self.button(QtGui.QWizard.NextButton).setFocus()          username = self.ui.lblUser.text()          password = self.ui.lblPassword.text() @@ -183,27 +185,32 @@ class Wizard(QtGui.QWizard):          if self._basic_password_checks(username, password, password2):              register = SRPRegister(provider_config=self._provider_config) -            ok, req = register.register_user(username, password) -            if ok: -                self._set_register_status("<b>User registration OK</b>") -                self._username = username -                self.ui.lblPassword2.clearFocus() -                # Detach this call to allow UI updates briefly -                QtCore.QTimer.singleShot(1, -                                         self.page(self.REGISTER_USER_PAGE) -                                         .set_completed) -            else: -                print req.content -                error_msg = "Unknown error" -                try: -                    error_msg = req.json().get("errors").get("login")[0] -                except: -                    logger.error("Unknown error: %r" % (req.content,)) -                self._set_register_status(error_msg) -                self.ui.btnRegister.setEnabled(True) +            register.registration_finished.connect( +                self._registration_finished) +            self._checker_thread.add_checks( +                [partial(register.register_user, username, password)]) +            self._username = username +            self._set_register_status("Starting registration...")          else:              self.ui.btnRegister.setEnabled(True) +    def _registration_finished(self, ok, req): +        if ok: +            self._set_register_status("<font color='green'>" +                                      "<b>User registration OK</b></font>") +            self.ui.lblPassword2.clearFocus() +            self.page(self.REGISTER_USER_PAGE).set_completed() +            self.button(QtGui.QWizard.BackButton).setEnabled(False) +        else: +            self._username = None +            error_msg = "Unknown error" +            try: +                error_msg = req.json().get("errors").get("login")[0] +            except: +                logger.error("Unknown error: %r" % (req.content,)) +            self._set_register_status(error_msg) +            self.ui.btnRegister.setEnabled(True) +      def _set_register_status(self, status):          """          Sets the status label in the registration page to status @@ -222,12 +229,16 @@ class Wizard(QtGui.QWizard):          Starts the checks for a given provider          """ +        if len(self.ui.lnProvider.text()) == 0: +            return +          self.ui.grpCheckProvider.setVisible(True)          self.ui.btnCheck.setEnabled(False)          self._domain = self.ui.lnProvider.text() -        self._provider_bootstrapper.start() -        self._provider_bootstrapper.run_provider_select_checks(self._domain) +        self._provider_bootstrapper.run_provider_select_checks( +            self._checker_thread, +            self._domain)      def _complete_task(self, data, label, complete=False, complete_page=-1):          """ @@ -328,7 +339,6 @@ class Wizard(QtGui.QWizard):          """          self._complete_task(data, self.ui.lblCheckApiCert,                              True, self.SETUP_PROVIDER_PAGE) -        self._provider_bootstrapper.set_should_quit()      def _download_eip_config(self, data):          """ @@ -351,7 +361,6 @@ class Wizard(QtGui.QWizard):          """          self._complete_task(data, self.ui.lblDownloadClientCert,                              True, self.SETUP_EIP_PAGE) -        self._eip_bootstrapper.set_should_quit()      def _current_id_changed(self, pageId):          """ @@ -365,14 +374,16 @@ class Wizard(QtGui.QWizard):              self.ui.lblNameResolution.setPixmap(self.QUESTION_ICON)              self.ui.lblHTTPS.setPixmap(self.QUESTION_ICON)              self.ui.lblProviderInfo.setPixmap(self.QUESTION_ICON) +            self._enable_check("")          if pageId == self.SETUP_PROVIDER_PAGE:              self._provider_bootstrapper.\ -                run_provider_setup_checks(self._provider_config) +                run_provider_setup_checks(self._checker_thread, +                                          self._provider_config)          if pageId == self.SETUP_EIP_PAGE: -            self._eip_bootstrapper.start() -            self._eip_bootstrapper.run_eip_setup_checks(self._provider_config) +            self._eip_bootstrapper.run_eip_setup_checks(self._checker_thread, +                                                        self._provider_config)          if pageId == self.PRESENT_PROVIDER_PAGE:              # TODO: get the right lang for these diff --git a/src/leap/services/eip/eipbootstrapper.py b/src/leap/services/eip/eipbootstrapper.py index 77d7020a..bd6ab715 100644 --- a/src/leap/services/eip/eipbootstrapper.py +++ b/src/leap/services/eip/eipbootstrapper.py @@ -28,11 +28,13 @@ from PySide import QtGui, QtCore  from leap.config.providerconfig import ProviderConfig  from leap.services.eip.eipconfig import EIPConfig +from leap.util.check import leap_assert, leap_assert_type +from leap.util.checkerthread import CheckerThread  logger = logging.getLogger(__name__) -class EIPBootstrapper(QtCore.QThread): +class EIPBootstrapper(QtCore.QObject):      """      Sets up EIP for a provider a series of checks and emits signals      after they are passed. @@ -50,13 +52,7 @@ class EIPBootstrapper(QtCore.QThread):      download_client_certificate = QtCore.Signal(dict)      def __init__(self): -        QtCore.QThread.__init__(self) - -        self._checks = [] -        self._checks_lock = QtCore.QMutex() - -        self._should_quit = False -        self._should_quit_lock = QtCore.QMutex() +        QtCore.QObject.__init__(self)          # **************************************************** #          # Dependency injection helpers, override this for more @@ -69,35 +65,6 @@ class EIPBootstrapper(QtCore.QThread):          self._eip_config = None          self._download_if_needed = False -    def get_should_quit(self): -        """ -        Returns wether this thread should quit - -        @rtype: bool -        @return: True if the thread should terminate itself, Flase otherwise -        """ - -        QtCore.QMutexLocker(self._should_quit_lock) -        return self._should_quit - -    def set_should_quit(self): -        """ -        Sets the should_quit flag to True so that this thread -        terminates the first chance it gets -        """ -        QtCore.QMutexLocker(self._should_quit_lock) -        self._should_quit = True -        self.wait() - -    def start(self): -        """ -        Starts the thread and resets the should_quit flag -        """ -        with QtCore.QMutexLocker(self._should_quit_lock): -            self._should_quit = False - -        QtCore.QThread.start(self) -      def _download_config(self):          """          Downloads the EIP config for the given provider @@ -106,7 +73,8 @@ class EIPBootstrapper(QtCore.QThread):          @rtype: bool          """ -        assert self._provider_config, "We need a provider configuration!" +        leap_assert(self._provider_config, +                    "We need a provider configuration!")          logger.debug("Downloading EIP config for %s" %                       (self._provider_config.get_domain(),)) @@ -162,8 +130,8 @@ class EIPBootstrapper(QtCore.QThread):          @return: True if the checks passed, False otherwise          @rtype: bool          """ -        assert self._provider_config, "We need a provider configuration!" -        assert self._eip_config, "We need an eip configuration!" +        leap_assert(self._provider_config, "We need a provider configuration!") +        leap_assert(self._eip_config, "We need an eip configuration!")          logger.debug("Downloading EIP client certificate for %s" %                       (self._provider_config.get_domain(),)) @@ -218,49 +186,25 @@ class EIPBootstrapper(QtCore.QThread):          return download_cert[self.PASSED_KEY] -    def run_eip_setup_checks(self, provider_config, download_if_needed=False): +    def run_eip_setup_checks(self, checker, +                             provider_config, +                             download_if_needed=False):          """          Starts the checks needed for a new eip setup          @param provider_config: Provider configuration          @type provider_config: ProviderConfig          """ -        assert provider_config, "We need a provider config!" -        assert isinstance(provider_config, ProviderConfig), "Expected " + \ -            "ProviderConfig type, not %r" % (type(provider_config),) +        leap_assert(provider_config, "We need a provider config!") +        leap_assert_type(provider_config, ProviderConfig)          self._provider_config = provider_config          self._download_if_needed = download_if_needed -        QtCore.QMutexLocker(self._checks_lock) -        self._checks = [ +        checker.add_checks([              self._download_config,              self._download_client_certificates -        ] - -    def run(self): -        """ -        Main run loop for this thread. Executes the checks. -        """ -        shouldContinue = False -        while True: -            if self.get_should_quit(): -                logger.debug("Quitting provider bootstrap thread") -                return -            checkSomething = False -            with QtCore.QMutexLocker(self._checks_lock): -                if len(self._checks) > 0: -                    check = self._checks.pop(0) -                    shouldContinue = check() -                    checkSomething = True -                    if not shouldContinue: -                        logger.debug("Something went wrong with the checks, " - -                                     "clearing...") -                        self._checks = [] -                        checkSomething = False -            if not checkSomething: -                self.usleep(self.IDLE_SLEEP_INTERVAL) +        ])  if __name__ == "__main__": @@ -272,8 +216,8 @@ if __name__ == "__main__":      def sigint_handler(*args, **kwargs):          logger.debug('SIGINT catched. shutting down...') -        bootstrapper_thread = args[0] -        bootstrapper_thread.set_should_quit() +        checker = args[0] +        checker.set_should_quit()          QtGui.QApplication.quit()      def signal_tester(d): @@ -289,27 +233,28 @@ if __name__ == "__main__":      console.setFormatter(formatter)      logger.addHandler(console) -    eip_thread = EIPBootstrapper() +    eip_checks = EIPBootstrapper() +    checker = CheckerThread() -    sigint = partial(sigint_handler, eip_thread) +    sigint = partial(sigint_handler, checker)      signal.signal(signal.SIGINT, sigint)      timer = QtCore.QTimer()      timer.start(500)      timer.timeout.connect(lambda: None)      app.connect(app, QtCore.SIGNAL("aboutToQuit()"), -                eip_thread.set_should_quit) +                checker.set_should_quit)      w = QtGui.QWidget()      w.resize(100, 100)      w.show() -    eip_thread.start() +    checker.start()      provider_config = ProviderConfig()      if provider_config.load(os.path.join("leap",                                           "providers",                                           "bitmask.net",                                           "provider.json")): -        eip_thread.run_eip_setup_checks(provider_config) +        eip_checks.run_eip_setup_checks(checker, provider_config)      sys.exit(app.exec_()) diff --git a/src/leap/services/eip/eipconfig.py b/src/leap/services/eip/eipconfig.py index ac06fef1..eab5bfd4 100644 --- a/src/leap/services/eip/eipconfig.py +++ b/src/leap/services/eip/eipconfig.py @@ -24,6 +24,7 @@ import logging  from leap.config.baseconfig import BaseConfig  from leap.config.providerconfig import ProviderConfig  from leap.services.eip.eipspec import eipservice_config_spec +from leap.util.check import leap_assert, leap_assert_type  logger = logging.getLogger(__name__) @@ -61,7 +62,7 @@ class EIPConfig(BaseConfig):      def get_gateway_ip(self, index=0):          gateways = self.get_gateways() -        assert len(gateways) > 0, "We don't have any gateway!" +        leap_assert(len(gateways) > 0, "We don't have any gateway!")          if index > len(gateways):              index = 0              logger.warning("Provided an unknown gateway index %s, " + @@ -75,10 +76,8 @@ class EIPConfig(BaseConfig):          Returns the path to the certificate used by openvpn          """ -        assert providerconfig, "We need a provider" -        assert isinstance(providerconfig, ProviderConfig), "The provider " + \ -            "needs to be of type ProviderConfig instead of %s" % \ -            (type(providerconfig),) +        leap_assert(providerconfig, "We need a provider") +        leap_assert_type(providerconfig, ProviderConfig)          cert_path = os.path.join(self.get_path_prefix(),                                   "leap", @@ -89,8 +88,8 @@ class EIPConfig(BaseConfig):                                   "openvpn.pem")          if not about_to_download: -            assert os.path.exists(cert_path), \ -                "You need to download the certificate first" +            leap_assert(os.path.exists(cert_path), +                        "You need to download the certificate first")              logger.debug("Using OpenVPN cert %s" % (cert_path,))          return cert_path diff --git a/src/leap/services/eip/providerbootstrapper.py b/src/leap/services/eip/providerbootstrapper.py index babcd47b..ecdc4e07 100644 --- a/src/leap/services/eip/providerbootstrapper.py +++ b/src/leap/services/eip/providerbootstrapper.py @@ -29,11 +29,13 @@ from OpenSSL import crypto  from PySide import QtGui, QtCore  from leap.config.providerconfig import ProviderConfig +from leap.util.check import leap_assert, leap_assert_type +from leap.util.checkerthread import CheckerThread  logger = logging.getLogger(__name__) -class ProviderBootstrapper(QtCore.QThread): +class ProviderBootstrapper(QtCore.QObject):      """      Given a provider URL performs a series of checks and emits signals      after they are passed. @@ -56,13 +58,7 @@ class ProviderBootstrapper(QtCore.QThread):      check_api_certificate = QtCore.Signal(dict)      def __init__(self): -        QtCore.QThread.__init__(self) - -        self._checks = [] -        self._checks_lock = QtCore.QMutex() - -        self._should_quit = False -        self._should_quit_lock = QtCore.QMutex() +        QtCore.QObject.__init__(self)          # **************************************************** #          # Dependency injection helpers, override this for more @@ -75,35 +71,6 @@ class ProviderBootstrapper(QtCore.QThread):          self._provider_config = None          self._download_if_needed = False -    def get_should_quit(self): -        """ -        Returns wether this thread should quit - -        @rtype: bool -        @return: True if the thread should terminate itself, Flase otherwise -        """ - -        QtCore.QMutexLocker(self._should_quit_lock) -        return self._should_quit - -    def set_should_quit(self): -        """ -        Sets the should_quit flag to True so that this thread -        terminates the first chance it gets -        """ -        QtCore.QMutexLocker(self._should_quit_lock) -        self._should_quit = True -        self.wait() - -    def start(self): -        """ -        Starts the thread and resets the should_quit flag -        """ -        with QtCore.QMutexLocker(self._should_quit_lock): -            self._should_quit = False - -        QtCore.QThread.start(self) -      def _should_proceed_provider(self):          """          Returns False if provider.json already exists for the given @@ -131,7 +98,7 @@ class ProviderBootstrapper(QtCore.QThread):          @rtype: bool          """ -        assert self._domain, "Cannot check DNS without a domain" +        leap_assert(self._domain, "Cannot check DNS without a domain")          logger.debug("Checking name resolution for %s" % (self._domain)) @@ -162,7 +129,7 @@ class ProviderBootstrapper(QtCore.QThread):          @rtype: bool          """ -        assert self._domain, "Cannot check HTTPS without a domain" +        leap_assert(self._domain, "Cannot check HTTPS without a domain")          logger.debug("Checking https for %s" % (self._domain)) @@ -193,7 +160,8 @@ class ProviderBootstrapper(QtCore.QThread):          @return: True if the checks passed, False otherwise          @rtype: bool          """ -        assert self._domain, "Cannot download provider info without a domain" +        leap_assert(self._domain, +                    "Cannot download provider info without a domain")          logger.debug("Downloading provider info for %s" % (self._domain)) @@ -230,7 +198,8 @@ class ProviderBootstrapper(QtCore.QThread):          return download_data[self.PASSED_KEY] -    def run_provider_select_checks(self, domain, download_if_needed=False): +    def run_provider_select_checks(self, checker, +                                   domain, download_if_needed=False):          """          Populates the check queue @@ -243,17 +212,16 @@ class ProviderBootstrapper(QtCore.QThread):          @return: True if the checks passed, False otherwise          @rtype: bool          """ -        assert domain and len(domain) > 0, "We need a domain!" +        leap_assert(domain and len(domain) > 0, "We need a domain!")          self._domain = domain          self._download_if_needed = download_if_needed -        QtCore.QMutexLocker(self._checks_lock) -        self._checks = [ +        checker.add_checks([              self._check_name_resolution,              self._check_https,              self._download_provider_info -        ] +        ])      def _should_proceed_cert(self):          """ @@ -262,7 +230,7 @@ class ProviderBootstrapper(QtCore.QThread):          @rtype: bool          """ -        assert self._provider_config, "We need a provider config!" +        leap_assert(self._provider_config, "We need a provider config!")          if not self._download_if_needed:              return True @@ -278,8 +246,8 @@ class ProviderBootstrapper(QtCore.QThread):          @rtype: bool          """ -        assert self._provider_config, "Cannot download the ca cert " + \ -            "without a provider config!" +        leap_assert(self._provider_config, "Cannot download the ca cert " +                    "without a provider config!")          logger.debug("Downloading ca cert for %s at %s" %                       (self._domain, self._provider_config.get_ca_cert_uri())) @@ -331,8 +299,8 @@ class ProviderBootstrapper(QtCore.QThread):          @return: True if the checks passed, False otherwise          @rtype: bool          """ -        assert self._provider_config, "Cannot check the ca cert " + \ -            "without a provider config!" +        leap_assert(self._provider_config, "Cannot check the ca cert " +                    "without a provider config!")          logger.debug("Checking ca fingerprint for %s and cert %s" %                       (self._domain, @@ -350,7 +318,7 @@ class ProviderBootstrapper(QtCore.QThread):          try:              parts = self._provider_config.get_ca_cert_fingerprint().split(":") -            assert len(parts) == 2, "Wrong fingerprint format" +            leap_assert(len(parts) == 2, "Wrong fingerprint format")              method = parts[0].strip()              fingerprint = parts[1].strip() @@ -358,13 +326,13 @@ class ProviderBootstrapper(QtCore.QThread):              with open(self._provider_config.get_ca_cert_path()) as f:                  cert_data = f.read() -            assert len(cert_data) > 0, "Could not read certificate data" +            leap_assert(len(cert_data) > 0, "Could not read certificate data")              x509 = crypto.load_certificate(crypto.FILETYPE_PEM, cert_data)              digest = x509.digest(method).replace(":", "").lower() -            assert digest == fingerprint, \ -                "Downloaded certificate has a different fingerprint!" +            leap_assert(digest == fingerprint, +                        "Downloaded certificate has a different fingerprint!")              check_ca_fingerprint_data[self.PASSED_KEY] = True          except Exception as e: @@ -384,8 +352,8 @@ class ProviderBootstrapper(QtCore.QThread):          @return: True if the checks passed, False otherwise          @rtype: bool          """ -        assert self._provider_config, "Cannot check the ca cert " + \ -            "without a provider config!" +        leap_assert(self._provider_config, "Cannot check the ca cert " +                    "without a provider config!")          logger.debug("Checking api certificate for %s and cert %s" %                       (self._provider_config.get_api_uri(), @@ -418,7 +386,8 @@ class ProviderBootstrapper(QtCore.QThread):          return check_api_certificate_data[self.PASSED_KEY] -    def run_provider_setup_checks(self, provider_config, +    def run_provider_setup_checks(self, checker, +                                  provider_config,                                    download_if_needed=False):          """          Starts the checks needed for a new provider setup @@ -429,43 +398,17 @@ class ProviderBootstrapper(QtCore.QThread):          overwrite already downloaded data          @type download_if_needed: bool          """ -        assert provider_config, "We need a provider config!" -        assert isinstance(provider_config, ProviderConfig), "Expected " + \ -            "ProviderConfig type, not %r" % (type(provider_config),) +        leap_assert(provider_config, "We need a provider config!") +        leap_assert_type(provider_config, ProviderConfig)          self._provider_config = provider_config          self._download_if_needed = download_if_needed -        QtCore.QMutexLocker(self._checks_lock) -        self._checks = [ +        checker.add_checks([              self._download_ca_cert,              self._check_ca_fingerprint,              self._check_api_certificate -        ] - -    def run(self): -        """ -        Main run loop for this thread. Executes the checks. -        """ -        shouldContinue = False -        while True: -            if self.get_should_quit(): -                logger.debug("Quitting provider bootstrap thread") -                return -            checkSomething = False -            with QtCore.QMutexLocker(self._checks_lock): -                if len(self._checks) > 0: -                    check = self._checks.pop(0) -                    shouldContinue = check() -                    checkSomething = True -                    if not shouldContinue: -                        logger.debug("Something went wrong with the checks, " -                                     "clearing...") -                        self._checks = [] -                        checkSomething = False -            if not checkSomething: -                self.usleep(self.IDLE_SLEEP_INTERVAL) - +        ])  if __name__ == "__main__":      import sys @@ -476,8 +419,8 @@ if __name__ == "__main__":      def sigint_handler(*args, **kwargs):          logger.debug('SIGINT catched. shutting down...') -        bootstrapper_thread = args[0] -        bootstrapper_thread.set_should_quit() +        bootstrapper_checks = args[0] +        bootstrapper_checks.set_should_quit()          QtGui.QApplication.quit()      def signal_tester(d): @@ -493,28 +436,32 @@ if __name__ == "__main__":      console.setFormatter(formatter)      logger.addHandler(console) -    bootstrapper_thread = ProviderBootstrapper() +    bootstrapper_checks = ProviderBootstrapper() + +    checker = CheckerThread() +    checker.start() -    sigint = partial(sigint_handler, bootstrapper_thread) +    sigint = partial(sigint_handler, checker)      signal.signal(signal.SIGINT, sigint)      timer = QtCore.QTimer()      timer.start(500)      timer.timeout.connect(lambda: None)      app.connect(app, QtCore.SIGNAL("aboutToQuit()"), -                bootstrapper_thread.set_should_quit) +                checker.set_should_quit)      w = QtGui.QWidget()      w.resize(100, 100)      w.show() -    bootstrapper_thread.start() -    bootstrapper_thread.run_provider_select_checks("bitmask.net") +    bootstrapper_checks.run_provider_select_checks(checker, +                                                   "bitmask.net")      provider_config = ProviderConfig()      if provider_config.load(os.path.join("leap",                                           "providers",                                           "bitmask.net",                                           "provider.json")): -        bootstrapper_thread.run_provider_setup_checks(provider_config) +        bootstrapper_checks.run_provider_setup_checks(checker, +                                                      provider_config)      sys.exit(app.exec_()) diff --git a/src/leap/services/eip/vpn.py b/src/leap/services/eip/vpn.py index f117cdbc..88692442 100644 --- a/src/leap/services/eip/vpn.py +++ b/src/leap/services/eip/vpn.py @@ -29,6 +29,7 @@ from leap.config.providerconfig import ProviderConfig  from leap.services.eip.vpnlaunchers import get_platform_launcher  from leap.services.eip.eipconfig import EIPConfig  from leap.services.eip.udstelnet import UDSTelnet +from leap.util.check import leap_assert, leap_assert_type  logger = logging.getLogger(__name__)  ON_POSIX = 'posix' in sys.builtin_module_names @@ -123,13 +124,11 @@ class VPN(QtCore.QThread):          socket, or port otherwise          @type socket_port: str          """ -        assert eipconfig, "We need an eip config" -        assert isinstance(eipconfig, EIPConfig), "Expected EIPConfig " + \ -            "object instead of %s" % (type(eipconfig),) -        assert providerconfig, "We need a provider config" -        assert isinstance(providerconfig, ProviderConfig), "Expected " + \ -            "ProviderConfig object instead of %s" % (type(providerconfig),) -        assert not self._started, "Starting process more than once!" +        leap_assert(eipconfig, "We need an eip config") +        leap_assert_type(eipconfig, EIPConfig) +        leap_assert(providerconfig, "We need a provider config") +        leap_assert_type(providerconfig, ProviderConfig) +        leap_assert(not self._started, "Starting process more than once!")          logger.debug("Starting VPN...") @@ -202,7 +201,7 @@ class VPN(QtCore.QThread):          @return: response read          @rtype: list          """ -        assert self._tn, "We need a tn connection!" +        leap_assert(self._tn, "We need a tn connection!")          try:              self._tn.write("%s\n" % (command,))              buf = self._tn.read_until(until, 2) diff --git a/src/leap/services/eip/vpnlaunchers.py b/src/leap/services/eip/vpnlaunchers.py index 68978248..00e9c966 100644 --- a/src/leap/services/eip/vpnlaunchers.py +++ b/src/leap/services/eip/vpnlaunchers.py @@ -29,6 +29,7 @@ from abc import ABCMeta, abstractmethod  from leap.config.providerconfig import ProviderConfig  from leap.services.eip.eipconfig import EIPConfig +from leap.util.check import leap_assert, leap_assert_type  logger = logging.getLogger(__name__) @@ -65,8 +66,8 @@ class VPNLauncher:  def get_platform_launcher():      launcher = globals()[platform.system() + "VPNLauncher"] -    assert launcher, "Unimplemented platform launcher: %s" % \ -        (platform.system(),) +    leap_assert(launcher, "Unimplemented platform launcher: %s" % +                (platform.system(),))      return launcher() @@ -165,17 +166,15 @@ class LinuxVPNLauncher(VPNLauncher):          @return: A VPN command ready to be launched          @rtype: list          """ -        assert eipconfig, "We need an eip config" -        assert isinstance(eipconfig, EIPConfig), "Expected EIPConfig " + \ -            "object instead of %s" % (type(eipconfig),) -        assert providerconfig, "We need a provider config" -        assert isinstance(providerconfig, ProviderConfig), "Expected " + \ -            "ProviderConfig object instead of %s" % (type(providerconfig),) -        assert socket_host, "We need a socket host!" -        assert socket_port, "We need a socket port!" +        leap_assert(eipconfig, "We need an eip config") +        leap_assert_type(eipconfig, EIPConfig) +        leap_assert(providerconfig, "We need a provider config") +        leap_assert_type(providerconfig, ProviderConfig) +        leap_assert(socket_host, "We need a socket host!") +        leap_assert(socket_port, "We need a socket port!")          openvpn_possibilities = which(self.OPENVPN_BIN) -        assert len(openvpn_possibilities) > 0, "We couldn't find openvpn" +        leap_assert(len(openvpn_possibilities) > 0, "We couldn't find openvpn")          openvpn = openvpn_possibilities[0]          args = [] @@ -183,7 +182,8 @@ class LinuxVPNLauncher(VPNLauncher):          if _is_pkexec_in_system():              if _is_auth_agent_running():                  pkexec_possibilities = which(self.PKEXEC_BIN) -                assert len(pkexec_possibilities) > 0, "We couldn't find pkexec" +                leap_assert(len(pkexec_possibilities) > 0, +                            "We couldn't find pkexec")                  args.append(openvpn)                  openvpn = pkexec_possibilities[0]              else: diff --git a/src/leap/util/check.py b/src/leap/util/check.py new file mode 100644 index 00000000..9787341a --- /dev/null +++ b/src/leap/util/check.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# check.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. + +""" +Set of functions to help checking situations +""" +import logging +import inspect +import traceback + + +logger = logging.getLogger(__name__) + + +def leap_assert(condition, message=""): +    """ +    Asserts the condition and displays the message if that's not +    met. It also logs the error and its backtrace. + +    @param condition: condition to check +    @type condition: bool +    @param message: message to display if the condition isn't met +    @type message: str +    """ +    if not condition: +        logger.error("Bug: %s" % (message,)) +        try: +            frame = inspect.currentframe() +            stack_trace = traceback.format_stack(frame) +            logger.error(''.join(stack_trace)) +        except Exception as e: +            logger.error("Bug in leap_assert: %r" % (e,)) +    assert condition, message + + +def leap_assert_type(var, expectedType): +    """ +    Helper assert check for a variable's expected type + +    @param var: variable to check +    @type var: any +    @param expectedType: type to check agains +    @type expectedType: type +    """ +    leap_assert(isinstance(var, expectedType), +                "Expected type %r instead of %r" % +                (expectedType, type(var))) diff --git a/src/leap/util/checkerthread.py b/src/leap/util/checkerthread.py new file mode 100644 index 00000000..681c33e1 --- /dev/null +++ b/src/leap/util/checkerthread.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- +# providerbootstrapper.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. + +""" +Checker thread +""" + +import logging + +from PySide import QtCore + +from leap.util.check import leap_assert_type + +logger = logging.getLogger(__name__) + + +class CheckerThread(QtCore.QThread): +    """ +    Generic checker thread that can perform any type of operation as +    long as it returns a boolean value that identifies how the +    execution went. +    """ + +    IDLE_SLEEP_INTERVAL = 1 + +    def __init__(self): +        QtCore.QThread.__init__(self) + +        self._checks = [] +        self._checks_lock = QtCore.QMutex() + +        self._should_quit = False +        self._should_quit_lock = QtCore.QMutex() + +    def get_should_quit(self): +        """ +        Returns wether this thread should quit + +        @rtype: bool +        @return: True if the thread should terminate itself, Flase otherwise +        """ + +        QtCore.QMutexLocker(self._should_quit_lock) +        return self._should_quit + +    def set_should_quit(self): +        """ +        Sets the should_quit flag to True so that this thread +        terminates the first chance it gets +        """ +        QtCore.QMutexLocker(self._should_quit_lock) +        self._should_quit = True +        self.wait() + +    def start(self): +        """ +        Starts the thread and resets the should_quit flag +        """ +        with QtCore.QMutexLocker(self._should_quit_lock): +            self._should_quit = False + +        QtCore.QThread.start(self) + +    def add_checks(self, checks): +        """ +        Adds a list of checks to the ones being executed + +        @param checks: check functions to perform +        @type checkes: list +        """ +        with QtCore.QMutexLocker(self._checks_lock): +            self._checks += checks + +    def run(self): +        """ +        Main run loop for this thread. Executes the checks. +        """ +        shouldContinue = False +        while True: +            if self.get_should_quit(): +                logger.debug("Quitting checker thread") +                return +            checkSomething = False +            with QtCore.QMutexLocker(self._checks_lock): +                if len(self._checks) > 0: +                    check = self._checks.pop(0) +                    shouldContinue = check() +                    leap_assert_type(shouldContinue, bool) +                    checkSomething = True +                    if not shouldContinue: +                        logger.debug("Something went wrong with the checks, " +                                     "clearing...") +                        self._checks = [] +                        checkSomething = False +            if not checkSomething: +                self.sleep(self.IDLE_SLEEP_INTERVAL) | 
