From 751638b4eb8208e1eaa1beaaed284da6b412bca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Thu, 7 Mar 2013 19:05:11 -0300 Subject: Change asserts for a custom leap_assert method Also: - Make SRPAuth and the Bootstrappers be a QObject instead of a QThread so we can use them inside another more generic thread - Add a generic CheckerThread that runs checks or whatever operation as long as it returns a boolean value - Closes the whole application if the wizard is rejected at the first run - Do not fail when the config directory doesn't exist - Set the wizard pixmap logo as LEAP's logo - Improve wizard checks - Make SRPRegister play nice with the CheckerThread --- src/leap/gui/mainwindow.py | 91 ++++++++++++++++++++++++++++++---------------- src/leap/gui/ui/wizard.ui | 5 ++- src/leap/gui/wizard.py | 91 ++++++++++++++++++++++++++-------------------- 3 files changed, 115 insertions(+), 72 deletions(-) (limited to 'src/leap/gui') 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 @@ - <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> + <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> Qt::RichText @@ -497,6 +497,9 @@ + + Qt::AutoText + Qt::AlignCenter 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("User registration OK") - 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("" + "User registration OK") + 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 -- cgit v1.2.3