From ad16a72f60ecc84524c22e8912df4eb8a48a2a42 Mon Sep 17 00:00:00 2001 From: kali Date: Tue, 6 Nov 2012 16:26:10 +0900 Subject: split wizard into separate files so we don't go nuts yet. --- src/leap/gui/firstrun/__init__.py | 24 +++ src/leap/gui/firstrun/connect.py | 218 ++++++++++++++++++++++++++ src/leap/gui/firstrun/intro.py | 68 ++++++++ src/leap/gui/firstrun/last.py | 89 +++++++++++ src/leap/gui/firstrun/login.py | 132 ++++++++++++++++ src/leap/gui/firstrun/mixins.py | 18 +++ src/leap/gui/firstrun/providerinfo.py | 67 ++++++++ src/leap/gui/firstrun/providersetup.py | 122 +++++++++++++++ src/leap/gui/firstrun/register.py | 211 +++++++++++++++++++++++++ src/leap/gui/firstrun/selectprovider.py | 216 +++++++++++++++++++++++++ src/leap/gui/firstrun/wizard.py | 269 ++++++++++++++++++++++++++++++++ 11 files changed, 1434 insertions(+) create mode 100644 src/leap/gui/firstrun/__init__.py create mode 100644 src/leap/gui/firstrun/connect.py create mode 100644 src/leap/gui/firstrun/intro.py create mode 100644 src/leap/gui/firstrun/last.py create mode 100644 src/leap/gui/firstrun/login.py create mode 100644 src/leap/gui/firstrun/mixins.py create mode 100644 src/leap/gui/firstrun/providerinfo.py create mode 100644 src/leap/gui/firstrun/providersetup.py create mode 100644 src/leap/gui/firstrun/register.py create mode 100644 src/leap/gui/firstrun/selectprovider.py create mode 100755 src/leap/gui/firstrun/wizard.py (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/__init__.py b/src/leap/gui/firstrun/__init__.py new file mode 100644 index 00000000..bf8d0df9 --- /dev/null +++ b/src/leap/gui/firstrun/__init__.py @@ -0,0 +1,24 @@ +import sip +sip.setapi('QString', 2) +sip.setapi('QVariant', 2) + +import connect +import intro +import last +import login +import mixins +import providerinfo +import providersetup +import register +import selectprovider + +__all__ = [ + 'connect', + 'intro', + 'last', + 'login', + 'mixins', + 'providerinfo', + 'providersetup', + 'register', + 'selectprovider'] diff --git a/src/leap/gui/firstrun/connect.py b/src/leap/gui/firstrun/connect.py new file mode 100644 index 00000000..3172a526 --- /dev/null +++ b/src/leap/gui/firstrun/connect.py @@ -0,0 +1,218 @@ +""" +Connecting Page, used in First Run Wizard +""" +import logging + +from PyQt4 import QtGui + +logger = logging.getLogger(__name__) + +from leap.base import auth + +from leap.gui.constants import APP_LOGO +from leap.gui.styles import ErrorLabelStyleSheet + + +class ConnectingPage(QtGui.QWizardPage): + + # XXX change to a ValidationPage + + def __init__(self, parent=None): + super(ConnectingPage, self).__init__(parent) + + self.setTitle("Connecting") + self.setSubTitle('Connecting to provider.') + + self.setPixmap( + QtGui.QWizard.LogoPixmap, + QtGui.QPixmap(APP_LOGO)) + + self.status = QtGui.QLabel("") + self.status.setWordWrap(True) + self.progress = QtGui.QProgressBar() + self.progress.setMaximum(100) + self.progress.hide() + + # for pre-checks + self.status_line_1 = QtGui.QLabel() + self.status_line_2 = QtGui.QLabel() + self.status_line_3 = QtGui.QLabel() + self.status_line_4 = QtGui.QLabel() + + # for connecting signals... + self.status_line_5 = QtGui.QLabel() + + layout = QtGui.QGridLayout() + layout.addWidget(self.status, 0, 1) + layout.addWidget(self.progress, 5, 1) + layout.addWidget(self.status_line_1, 8, 1) + layout.addWidget(self.status_line_2, 9, 1) + layout.addWidget(self.status_line_3, 10, 1) + layout.addWidget(self.status_line_4, 11, 1) + + # XXX to be used? + #self.validation_status = QtGui.QLabel("") + #self.validation_status.setStyleSheet( + #ErrorLabelStyleSheet) + #self.validation_msg = QtGui.QLabel("") + + self.setLayout(layout) + + self.goto_login_again = False + + def set_status(self, status): + self.status.setText(status) + self.status.setWordWrap(True) + + def set_status_line(self, line, status): + line = getattr(self, 'status_line_%s' % line) + if line: + line.setText(status) + + def set_validation_status(self, status): + # Do not remember if we're using + # status lines > 3 now... + # if we are, move below + self.status_line_3.setStyleSheet( + ErrorLabelStyleSheet) + self.status_line_3.setText(status) + + def set_validation_message(self, message): + self.status_line_4.setText(message) + self.status_line_4.setWordWrap(True) + + def get_donemsg(self, msg): + return "%s ... done" % msg + + def run_eip_checks_for_provider_and_connect(self, domain): + wizard = self.wizard() + conductor = wizard.conductor + start_eip_signal = getattr( + wizard, + 'start_eipconnection_signal', None) + + conductor.set_provider_domain(domain) + conductor.run_checks() + self.conductor = conductor + errors = self.eip_error_check() + if not errors and start_eip_signal: + start_eip_signal.emit() + + def eip_error_check(self): + """ + a version of the main app error checker, + but integrated within the connecting page of the wizard. + consumes the conductor error queue. + pops errors, and add those to the wizard page + """ + logger.debug('eip error check from connecting page') + errq = self.conductor.error_queue + # XXX missing! + + def fetch_and_validate(self): + import time + domain = self.field('provider_domain') + wizard = self.wizard() + #pconfig = wizard.providerconfig + eipconfigchecker = wizard.eipconfigchecker() + pCertChecker = wizard.providercertchecker( + domain=domain) + + # username and password are in different fields + # if they were stored in log_in or sign_up pages. + from_login = self.wizard().from_login + unamek_base = 'userName' + passwk_base = 'userPassword' + unamek = 'login_%s' % unamek_base if from_login else unamek_base + passwk = 'login_%s' % passwk_base if from_login else passwk_base + + username = self.field(unamek) + password = self.field(passwk) + credentials = username, password + + self.progress.show() + + fetching_eip_conf_msg = 'Fetching eip service configuration' + self.set_status(fetching_eip_conf_msg) + self.progress.setValue(30) + + # Fetching eip service + eipconfigchecker.fetch_eip_service_config( + domain=domain) + + self.status_line_1.setText( + self.get_donemsg(fetching_eip_conf_msg)) + + getting_client_cert_msg = 'Getting client certificate' + self.set_status(getting_client_cert_msg) + self.progress.setValue(66) + + # Download cert + try: + pCertChecker.download_new_client_cert( + credentials=credentials) + except auth.SRPAuthenticationError: + self.set_validation_status("Authentication error") + #self.set_validation_message( + #"Click next to introduce your " + #"credentials again") + self.goto_login_again = True + # We should do something here + # but it's broken + return False + + time.sleep(2) + self.status_line_2.setText( + self.get_donemsg(getting_client_cert_msg)) + + validating_clientcert_msg = 'Validating client certificate' + self.set_status(validating_clientcert_msg) + self.progress.setValue(90) + time.sleep(2) + self.status_line_3.setText( + self.get_donemsg(validating_clientcert_msg)) + + self.progress.setValue(100) + time.sleep(3) + + # here we go! :) + self.run_eip_checks_for_provider_and_connect(domain) + + #self.validation_block = self.wait_for_validation_block() + + # XXX signal timeout! + return True + + # + # wizardpage methods + # + + def nextId(self): + wizard = self.wizard() + # XXX this does not work because + # page login has already been met + #if self.goto_login_again: + #next_ = "login" + #else: + #next_ = "lastpage" + next_ = "lastpage" + return wizard.get_page_index(next_) + + def initializePage(self): + # XXX if we're coming from signup page + # we could say something like + # 'registration successful!' + self.status.setText( + "We have " + "all we need to connect with the provider.

" + "Click next to continue. ") + self.progress.setValue(0) + self.progress.hide() + self.status_line_1.setText('') + self.status_line_2.setText('') + self.status_line_3.setText('') + + def validatePage(self): + # XXX remove + validated = self.fetch_and_validate() + return validated diff --git a/src/leap/gui/firstrun/intro.py b/src/leap/gui/firstrun/intro.py new file mode 100644 index 00000000..4bb008c7 --- /dev/null +++ b/src/leap/gui/firstrun/intro.py @@ -0,0 +1,68 @@ +""" +Intro page used in first run wizard +""" + +from PyQt4 import QtGui + +from leap.gui.constants import APP_LOGO + + +class IntroPage(QtGui.QWizardPage): + def __init__(self, parent=None): + super(IntroPage, self).__init__(parent) + + self.setTitle("First run wizard.") + + #self.setPixmap( + #QtGui.QWizard.WatermarkPixmap, + #QtGui.QPixmap(':/images/watermark1.png')) + + self.setPixmap( + QtGui.QWizard.LogoPixmap, + QtGui.QPixmap(APP_LOGO)) + + label = QtGui.QLabel( + "Now we will guide you through " + "some configuration that is needed before you " + "can connect for the first time.

" + "If you ever need to modify these options again, " + "you can find the wizard in the 'Settings' menu from the " + "main window.

" + "Do you want to sign up for a new account, or log " + "in with an already existing username?
") + label.setWordWrap(True) + + radiobuttonGroup = QtGui.QGroupBox() + + self.sign_up = QtGui.QRadioButton( + "Sign up for a new account.") + self.sign_up.setChecked(True) + self.log_in = QtGui.QRadioButton( + "Log In with my credentials.") + + radiobLayout = QtGui.QVBoxLayout() + radiobLayout.addWidget(self.sign_up) + radiobLayout.addWidget(self.log_in) + radiobuttonGroup.setLayout(radiobLayout) + + layout = QtGui.QVBoxLayout() + layout.addWidget(label) + layout.addWidget(radiobuttonGroup) + self.setLayout(layout) + + self.registerField('is_signup', self.sign_up) + + def validatePage(self): + return True + + def nextId(self): + """ + returns next id + in a non-linear wizard + """ + if self.sign_up.isChecked(): + next_ = 'providerselection' + if self.log_in.isChecked(): + next_ = 'login' + wizard = self.wizard() + return wizard.get_page_index(next_) diff --git a/src/leap/gui/firstrun/last.py b/src/leap/gui/firstrun/last.py new file mode 100644 index 00000000..6f9abbb5 --- /dev/null +++ b/src/leap/gui/firstrun/last.py @@ -0,0 +1,89 @@ +""" +Last Page, used in First Run Wizard +""" +import logging + +from PyQt4 import QtGui + +from leap.util.coroutines import coroutine +from leap.gui.constants import APP_LOGO + +logger = logging.getLogger(__name__) + + +class LastPage(QtGui.QWizardPage): + def __init__(self, parent=None): + super(LastPage, self).__init__(parent) + + self.setTitle("Connecting to Encrypted Internet Proxy service...") + + self.setPixmap( + QtGui.QWizard.LogoPixmap, + QtGui.QPixmap(APP_LOGO)) + + #self.setPixmap( + #QtGui.QWizard.WatermarkPixmap, + #QtGui.QPixmap(':/images/watermark2.png')) + + self.label = QtGui.QLabel() + self.label.setWordWrap(True) + + self.status_line_1 = QtGui.QLabel() + self.status_line_2 = QtGui.QLabel() + self.status_line_3 = QtGui.QLabel() + self.status_line_4 = QtGui.QLabel() + + layout = QtGui.QVBoxLayout() + layout.addWidget(self.label) + + # make loop + layout.addWidget(self.status_line_1) + layout.addWidget(self.status_line_2) + layout.addWidget(self.status_line_3) + layout.addWidget(self.status_line_4) + + self.setLayout(layout) + + def set_status_line(self, line, status): + statusline = getattr(self, 'status_line_%s' % line) + if statusline: + statusline.setText(status) + + def set_finished_status(self): + self.setTitle('You are now using an encrypted connection!') + finishText = self.wizard().buttonText( + QtGui.QWizard.FinishButton) + finishText = finishText.replace('&', '') + self.label.setText( + "Click '%s' to end the wizard and " + "save your settings." % finishText) + + @coroutine + def eip_status_handler(self): + # XXX this can be changed to use + # signals. See progress.py + logger.debug('logging status in last page') + self.validation_done = False + status_count = 0 + try: + while True: + status = (yield) + status_count += 1 + # XXX add to line... + logger.debug('status --> %s', status) + self.set_status_line(status_count, status) + if status == "connected": + self.set_finished_status() + break + except GeneratorExit: + pass + + def initializePage(self): + wizard = self.wizard() + if not wizard: + return + eip_status_handler = self.eip_status_handler() + eip_statuschange_signal = wizard.eip_statuschange_signal + if eip_statuschange_signal: + eip_statuschange_signal.connect( + lambda status: eip_status_handler.send(status)) diff --git a/src/leap/gui/firstrun/login.py b/src/leap/gui/firstrun/login.py new file mode 100644 index 00000000..ae4b23c6 --- /dev/null +++ b/src/leap/gui/firstrun/login.py @@ -0,0 +1,132 @@ +""" +LogIn Page, used inf First Run Wizard +""" +from PyQt4 import QtCore +from PyQt4 import QtGui + +import requests + +from leap.gui.firstrun.mixins import UserFormMixIn + +from leap.gui.constants import APP_LOGO, FULL_USERNAME_REGEX +from leap.gui.styles import ErrorLabelStyleSheet + + +class LogInPage(QtGui.QWizardPage, UserFormMixIn): + def __init__(self, parent=None): + super(LogInPage, self).__init__(parent) + + self.setTitle("Log In") + self.setSubTitle("Log in with your credentials.") + + self.setPixmap( + QtGui.QWizard.LogoPixmap, + QtGui.QPixmap(APP_LOGO)) + + userNameLabel = QtGui.QLabel("User &name:") + userNameLineEdit = QtGui.QLineEdit() + userNameLineEdit.cursorPositionChanged.connect( + self.reset_validation_status) + userNameLabel.setBuddy(userNameLineEdit) + + # let's add regex validator + usernameRe = QtCore.QRegExp(FULL_USERNAME_REGEX) + userNameLineEdit.setValidator( + QtGui.QRegExpValidator(usernameRe, self)) + self.userNameLineEdit = userNameLineEdit + + userPasswordLabel = QtGui.QLabel("&Password:") + self.userPasswordLineEdit = QtGui.QLineEdit() + self.userPasswordLineEdit.setEchoMode( + QtGui.QLineEdit.Password) + userPasswordLabel.setBuddy(self.userPasswordLineEdit) + + self.registerField('login_userName*', self.userNameLineEdit) + self.registerField('login_userPassword*', self.userPasswordLineEdit) + + layout = QtGui.QGridLayout() + layout.setColumnMinimumWidth(0, 20) + + validationMsg = QtGui.QLabel("") + validationMsg.setStyleSheet(ErrorLabelStyleSheet) + self.validationMsg = validationMsg + + layout.addWidget(validationMsg, 0, 3) + layout.addWidget(userNameLabel, 1, 0) + layout.addWidget(self.userNameLineEdit, 1, 3) + layout.addWidget(userPasswordLabel, 2, 0) + layout.addWidget(self.userPasswordLineEdit, 2, 3) + + self.setLayout(layout) + + #self.registerField('is_login_wizard') + + def onUserNameEdit(self, *args): + if self.initial_username_sample: + self.userNameLineEdit.setText('') + self.initial_username_sample = None + + # pagewizard methods + + def nextId(self): + wizard = self.wizard() + if not wizard: + return + if wizard.is_provider_setup is True: + next_ = 'connecting' + if wizard.is_provider_setup is False: + next_ = 'providersetup' + return wizard.get_page_index(next_) + + def initializePage(self): + self.userNameLineEdit.setText('username@provider.example.org') + self.userNameLineEdit.cursorPositionChanged.connect( + self.onUserNameEdit) + self.initial_username_sample = True + + def validatePage(self): + wizard = self.wizard() + eipconfigchecker = wizard.eipconfigchecker() + + full_username = self.userNameLineEdit.text() + password = self.userPasswordLineEdit.text() + if full_username.count('@') != 1: + self.set_validation_status( + "Username must be in the username@provider form.") + return False + + username, domain = full_username.split('@') + self.setField('provider_domain', domain) + self.setField('login_userName', username) + self.setField('login_userPassword', password) + + # Able to contact domain? + # can get definition? + # two-by-one + try: + eipconfigchecker.fetch_definition(domain=domain) + + # we're using requests here for all + # the possible error cases that it catches. + except requests.exceptions.ConnectionError as exc: + self.set_validation_status(exc.message[1]) + return False + except requests.exceptions.HTTPError as exc: + self.set_validation_status(exc.message) + return False + wizard.set_providerconfig( + eipconfigchecker.defaultprovider.config) + + # XXX validate user? or we leave that for later? + # I think the best thing to do for that is + # continue to provider setup page, and if + # we catch authentication error there, redirect + # again to this page (by clicking "next" to + # come here). + # Rationale is that we need to verify server certs + # and so on. + + # mark that we came from login page. + self.wizard().from_login = True + + return True diff --git a/src/leap/gui/firstrun/mixins.py b/src/leap/gui/firstrun/mixins.py new file mode 100644 index 00000000..c4731893 --- /dev/null +++ b/src/leap/gui/firstrun/mixins.py @@ -0,0 +1,18 @@ +""" +mixins used in First Run Wizard +""" + + +class UserFormMixIn(object): + + def reset_validation_status(self): + """ + empty the validation msg + """ + self.validationMsg.setText('') + + def set_validation_status(self, msg): + """ + set generic validation status + """ + self.validationMsg.setText(msg) diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py new file mode 100644 index 00000000..f5f5518a --- /dev/null +++ b/src/leap/gui/firstrun/providerinfo.py @@ -0,0 +1,67 @@ +""" +Provider Info Page, used in First run Wizard +""" + +from PyQt4 import QtGui + +from leap.gui.constants import APP_LOGO + + +class ProviderInfoPage(QtGui.QWizardPage): + def __init__(self, parent=None): + super(ProviderInfoPage, self).__init__(parent) + + self.setTitle("Provider Info") + self.setSubTitle("Available information about chosen provider.") + + self.setPixmap( + QtGui.QWizard.LogoPixmap, + QtGui.QPixmap(APP_LOGO)) + + displayName = QtGui.QLabel("") + description = QtGui.QLabel("") + enrollment_policy = QtGui.QLabel("") + # XXX set stylesheet... + # prettify a little bit. + # bigger fonts and so on... + self.displayName = displayName + self.description = description + self.enrollment_policy = enrollment_policy + + layout = QtGui.QGridLayout() + layout.addWidget(displayName, 0, 1) + layout.addWidget(description, 1, 1) + layout.addWidget(enrollment_policy, 2, 1) + + self.setLayout(layout) + + def initializePage(self): + # XXX move to show info... + + # XXX get multilingual objects + # directly from the config object + + lang = "en" + pconfig = self.wizard().providerconfig + + dn = pconfig.get('display_name') + display_name = dn[lang] if dn else '' + self.displayName.setText( + "%s" % display_name) + + desc = pconfig.get('description') + description_text = desc[lang] if desc else '' + self.description.setText( + "%s" % description_text) + + enroll = pconfig.get('enrollment_policy') + if enroll: + self.enrollment_policy.setText( + 'enrollment policy: %s' % enroll) + + def nextId(self): + wizard = self.wizard() + next_ = "providersetupvalidation" + return wizard.get_page_index(next_) + + diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py new file mode 100644 index 00000000..63f55d00 --- /dev/null +++ b/src/leap/gui/firstrun/providersetup.py @@ -0,0 +1,122 @@ +""" +Provider Setup Validation Page, +used if First Run Wizard +""" + +from PyQt4 import QtGui + +from leap.gui.progress import ValidationPage + +from leap.gui.constants import APP_LOGO + + +class ProviderSetupValidationPage(ValidationPage): + def __init__(self, parent=None): + super(ProviderSetupValidationPage, self).__init__(parent) + self.setTitle("Setting up provider") + #self.setSubTitle( + #"auto configuring provider...") + + self.setPixmap( + QtGui.QWizard.LogoPixmap, + QtGui.QPixmap(APP_LOGO)) + + def _do_checks(self, signal=None): + """ + executes actual checks in a separate thread + """ + import time + domain = self.field('provider_domain') + wizard = self.wizard() + pconfig = wizard.providerconfig + + pCertChecker = wizard.providercertchecker + certchecker = pCertChecker(domain=domain) + + signal.emit('Fetching CA certificate') + self.progress.setValue(30) + + if pconfig: + ca_cert_uri = pconfig.get('ca_cert_uri').geturl() + else: + ca_cert_uri = None + + # XXX check scheme == "https" + # XXX passing verify == False because + # we have trusted right before. + # We should check it's the same domain!!! + # (Check with the trusted fingerprints dict + # or something smart) + + #certchecker.download_ca_cert( + #uri=ca_cert_uri, + #verify=False) + + time.sleep(2) + + signal.emit('Checking CA fingerprint') + self.progress.setValue(66) + #ca_cert_fingerprint = pconfig.get('ca_cert_fingerprint', None) + + # XXX get fingerprint dict (types) + #sha256_fpr = ca_cert_fingerprint.split('=')[1] + + #validate_fpr = certchecker.check_ca_cert_fingerprint( + #fingerprint=sha256_fpr) + time.sleep(0.5) + #if not validate_fpr: + # XXX update validationMsg + # should catch exception + #return False + + signal.emit('Validating api certificate') + self.progress.setValue(90) + + #api_uri = pconfig.get('api_uri', None) + #try: + #api_cert_verified = certchecker.verify_api_https(api_uri) + #except requests.exceptions.SSLError as exc: + #logger.error('BUG #638. %s' % exc.message) + # XXX RAISE! See #638 + # bypassing until the hostname is fixed. + # We probably should raise yet-another-warning + # here saying user that the hostname "XX.XX.XX.XX' does not + # match 'foo.bar.baz' + #api_cert_verified = True + + #if not api_cert_verified: + # XXX update validationMsg + # should catch exception + #return False + time.sleep(0.5) + #ca_cert_path = checker.ca_cert_path + + self.progress.setValue(100) + signal.emit('end_sentinel') + time.sleep(1) + + def _do_validation(self): + """ + called after _do_checks has finished + (connected to checker thread finished signal) + """ + wizard = self.wizard() + if self.errors: + print 'going back with errors' + wizard.set_validation_error( + 'signup', 'that name is taken') + self.go_back() + else: + print 'going next' + self.go_next() + + def nextId(self): + wizard = self.wizard() + if not wizard: + return + is_signup = self.field('is_signup') + if is_signup is True: + next_ = 'signup' + if is_signup is False: + next_ = 'connecting' + return wizard.get_page_index(next_) diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py new file mode 100644 index 00000000..b04844bf --- /dev/null +++ b/src/leap/gui/firstrun/register.py @@ -0,0 +1,211 @@ +""" +Register User Page, used in First Run Wizard +""" +import json +import logging +import socket + +import requests + +from PyQt4 import QtCore +from PyQt4 import QtGui + +from leap.base import auth +from leap.gui.firstrun.mixins import UserFormMixIn + +logger = logging.getLogger(__name__) + +from leap.gui.constants import APP_LOGO, BARE_USERNAME_REGEX +from leap.gui.styles import ErrorLabelStyleSheet + + +class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): + setSigningUpStatus = QtCore.pyqtSignal([]) + + def __init__(self, parent=None): + super(RegisterUserPage, self).__init__(parent) + + # bind wizard page signals + self.setSigningUpStatus.connect( + lambda: self.set_validation_status( + 'validating')) + + self.setTitle("Sign Up") + + self.setPixmap( + QtGui.QWizard.LogoPixmap, + QtGui.QPixmap(APP_LOGO)) + + userNameLabel = QtGui.QLabel("User &name:") + userNameLineEdit = QtGui.QLineEdit() + userNameLineEdit.cursorPositionChanged.connect( + self.reset_validation_status) + userNameLabel.setBuddy(userNameLineEdit) + + # let's add regex validator + usernameRe = QtCore.QRegExp(BARE_USERNAME_REGEX) + userNameLineEdit.setValidator( + QtGui.QRegExpValidator(usernameRe, self)) + self.userNameLineEdit = userNameLineEdit + + userPasswordLabel = QtGui.QLabel("&Password:") + self.userPasswordLineEdit = QtGui.QLineEdit() + self.userPasswordLineEdit.setEchoMode( + QtGui.QLineEdit.Password) + userPasswordLabel.setBuddy(self.userPasswordLineEdit) + + userPassword2Label = QtGui.QLabel("Password (again):") + self.userPassword2LineEdit = QtGui.QLineEdit() + self.userPassword2LineEdit.setEchoMode( + QtGui.QLineEdit.Password) + userPassword2Label.setBuddy(self.userPassword2LineEdit) + + rememberPasswordCheckBox = QtGui.QCheckBox( + "&Remember username and password.") + rememberPasswordCheckBox.setChecked(True) + + self.registerField('userName*', self.userNameLineEdit) + self.registerField('userPassword*', self.userPasswordLineEdit) + + # XXX missing password confirmation + # XXX validator! + + self.registerField('rememberPassword', rememberPasswordCheckBox) + + layout = QtGui.QGridLayout() + layout.setColumnMinimumWidth(0, 20) + + validationMsg = QtGui.QLabel("") + validationMsg.setStyleSheet(ErrorLabelStyleSheet) + + self.validationMsg = validationMsg + + layout.addWidget(validationMsg, 0, 3) + layout.addWidget(userNameLabel, 1, 0) + layout.addWidget(self.userNameLineEdit, 1, 3) + layout.addWidget(userPasswordLabel, 2, 0) + layout.addWidget(userPassword2Label, 3, 0) + layout.addWidget(self.userPasswordLineEdit, 2, 3) + layout.addWidget(self.userPassword2LineEdit, 3, 3) + layout.addWidget(rememberPasswordCheckBox, 4, 3, 4, 4) + self.setLayout(layout) + + # overwritten methods + + def initializePage(self): + """ + inits wizard page + """ + provider = self.field('provider_domain') + self.setSubTitle( + "Register a new user with provider %s." % + provider) + self.validationMsg.setText('') + + def validatePage(self): + """ + validation + we initialize the srp protocol register + and try to register user. if error + returned we write validation error msg + above the form. + """ + # the slot for this signal is not doing + # what's expected. Investigate why, + # right now we're not giving any feedback + # to the user re. what's going on. The only + # thing I can see as a workaround is setting + # a low timeout. + wizard = self.wizard() + + self.setSigningUpStatus.emit() + + username = self.userNameLineEdit.text() + password = self.userPasswordLineEdit.text() + password2 = self.userPassword2LineEdit.text() + + # have some call to a password checker... + + if password != password2: + self.set_validation_status('Password does not match.') + return False + + if len(password) < 6: + self.set_validation_status('Password too short.') + return False + + if password == "123456": + # joking + self.set_validation_status('Password too obvious.') + return False + + domain = self.field('provider_domain') + + if wizard and wizard.debug_server: + # We're debugging + dbgsrv = wizard.debug_server + schema = dbgsrv.scheme + netloc = dbgsrv.netloc + port = None + netloc_split = netloc.split(':') + if len(netloc_split) > 1: + provider, port = netloc_split + else: + provider = netloc + + signup = auth.LeapSRPRegister( + scheme=schema, + provider=provider, + port=port) + + else: + # this is the real thing + signup = auth.LeapSRPRegister( + # XXX FIXME 0 Force HTTPS + #schema="https", + schema="http", + provider=domain) + try: + ok, req = signup.register_user(username, password) + except socket.timeout: + self.set_validation_status( + "Error connecting to provider (timeout)") + return False + + except requests.exceptions.ConnectionError as exc: + logger.error(exc) + self.set_validation_status( + "Error connecting to provider " + "(connection error)") + return False + + if ok: + return True + + # something went wrong. + # not registered, let's catch what. + # get timeout + # ... + if req.status_code == 500: + self.set_validation_status( + "Error during registration (500)") + return False + + validation_msgs = json.loads(req.content) + logger.debug('validation errors: %s' % validation_msgs) + errors = validation_msgs.get('errors', None) + if errors and errors.get('login', None): + # XXX this sometimes catch the blank username + # but we're not allowing that (soon) + self.set_validation_status( + 'Username not available.') + else: + self.set_validation_status( + "Error during sign up") + return False + + def nextId(self): + wizard = self.wizard() + if not wizard: + return + return wizard.get_page_index('connecting') diff --git a/src/leap/gui/firstrun/selectprovider.py b/src/leap/gui/firstrun/selectprovider.py new file mode 100644 index 00000000..d26fdbbb --- /dev/null +++ b/src/leap/gui/firstrun/selectprovider.py @@ -0,0 +1,216 @@ +""" +Select Provider Page, used in First Run Wizard +""" +from PyQt4 import QtCore +from PyQt4 import QtGui + +from leap.base import exceptions as baseexceptions +from leap.crypto import certs +from leap.eip import exceptions as eipexceptions + +from leap.gui.constants import APP_LOGO +from leap.gui.styles import ErrorLabelStyleSheet + + +class SelectProviderPage(QtGui.QWizardPage): + def __init__(self, parent=None, providers=None): + super(SelectProviderPage, self).__init__(parent) + + self.setTitle("Enter Provider") + self.setSubTitle( + "Please enter the domain of the provider you want " + "to use for your connection." + ) + self.setPixmap( + QtGui.QWizard.LogoPixmap, + QtGui.QPixmap(APP_LOGO)) + + self.did_cert_check = False + + providerNameLabel = QtGui.QLabel("h&ttps://") + # note that we expect the bare domain name + # we will add the scheme later + providerNameEdit = QtGui.QLineEdit() + providerNameEdit.cursorPositionChanged.connect( + self.reset_validation_status) + providerNameLabel.setBuddy(providerNameEdit) + + # add regex validator + providerDomainRe = QtCore.QRegExp(r"^[a-z\d_-.]+$") + providerNameEdit.setValidator( + QtGui.QRegExpValidator(providerDomainRe, self)) + self.providerNameEdit = providerNameEdit + + # Eventually we will seed a list of + # well known providers here. + + #providercombo = QtGui.QComboBox() + #if providers: + #for provider in providers: + #providercombo.addItem(provider) + #providerNameSelect = providercombo + + self.registerField('provider_domain*', self.providerNameEdit) + #self.registerField('provider_name_index', providerNameSelect) + + validationMsg = QtGui.QLabel("") + validationMsg.setStyleSheet(ErrorLabelStyleSheet) + self.validationMsg = validationMsg + + # cert info + + # this is used in the callback + # for the checkbox changes. + # tricky, since the first time came + # from the exception message. + # should get string from exception too! + self.bad_cert_status = "Server certificate could not be verified." + + self.certInfo = QtGui.QLabel("") + self.certInfo.setWordWrap(True) + self.certWarning = QtGui.QLabel("") + self.trustProviderCertCheckBox = QtGui.QCheckBox( + "&Trust this provider certificate.") + + self.trustProviderCertCheckBox.stateChanged.connect( + self.onTrustCheckChanged) + + layout = QtGui.QGridLayout() + layout.addWidget(validationMsg, 0, 2) + layout.addWidget(providerNameLabel, 1, 1) + layout.addWidget(providerNameEdit, 1, 2) + + # XXX get a groupbox or something.... + certinfoGroup = QtGui.QGroupBox("Certificate validation") + certinfoLayout = QtGui.QVBoxLayout() + certinfoLayout.addWidget(self.certInfo) + certinfoLayout.addWidget(self.certWarning) + certinfoLayout.addWidget(self.trustProviderCertCheckBox) + certinfoGroup.setLayout(certinfoLayout) + + layout.addWidget(certinfoGroup, 4, 1, 4, 2) + self.certinfoGroup = certinfoGroup + self.certinfoGroup.hide() + + self.setLayout(layout) + + def is_insecure_cert_trusted(self): + return self.trustProviderCertCheckBox.isChecked() + + def onTrustCheckChanged(self, state): + checked = False + if state == 2: + checked = True + + if checked: + self.reset_validation_status() + else: + self.set_validation_status(self.bad_cert_status) + + # trigger signal to redraw next button + self.completeChanged.emit() + + def reset_validation_status(self): + """ + empty the validation msg + """ + self.validationMsg.setText('') + + def set_validation_status(self, status): + self.validationMsg.setText(status) + + def add_cert_info(self, certinfo): + self.certWarning.setText( + "Do you want to trust this provider certificate?") + self.certInfo.setText( + 'SHA-256 fingerprint: %s
' % certinfo) + self.certInfo.setWordWrap(True) + self.certinfoGroup.show() + + # pagewizard methods + + def isComplete(self): + if not self.did_cert_check: + return True + if self.is_insecure_cert_trusted(): + return True + return False + + def initializePage(self): + self.certinfoGroup.hide() + + def validatePage(self): + ################################## + # XXX FIXME! + ################################## + ################################## + ################################## + ################################## + ##### validation skipped !!! ##### + ################################## + ################################## + return True + ################################## + ################################## + ################################## + + # XXX move to ProviderInfo... + + wizard = self.wizard() + netchecker = wizard.netchecker() + providercertchecker = wizard.providercertchecker() + eipconfigchecker = wizard.eipconfigchecker() + + domain = self.providerNameEdit.text() + + # try name resolution + try: + netchecker.check_name_resolution( + domain) + + except baseexceptions.LeapException as exc: + self.set_validation_status(exc.usermessage) + return False + + # try https connection + try: + providercertchecker.is_https_working( + "https://%s" % domain, + verify=True) + + except eipexceptions.HttpsBadCertError as exc: + if self.trustProviderCertCheckBox.isChecked(): + pass + else: + self.set_validation_status(exc.usermessage) + fingerprint = certs.get_cert_fingerprint( + domain=domain, sep=" ") + + # it's ok if we've trusted this fgprt before + trustedcrts = self.wizard().trusted_certs + if trustedcrts and fingerprint.replace(' ', '') in trustedcrts: + pass + else: + # let your user face panick :P + self.add_cert_info(fingerprint) + self.did_cert_check = True + self.completeChanged.emit() + return False + + except baseexceptions.LeapException as exc: + self.set_validation_status(exc.usermessage) + return False + + # try download provider info... + eipconfigchecker.fetch_definition(domain=domain) + wizard.set_providerconfig( + eipconfigchecker.defaultprovider.config) + + # all ok, go on... + return True + + def nextId(self): + wizard = self.wizard() + if not wizard: + return + return wizard.get_page_index('providerinfo') diff --git a/src/leap/gui/firstrun/wizard.py b/src/leap/gui/firstrun/wizard.py new file mode 100755 index 00000000..fb601714 --- /dev/null +++ b/src/leap/gui/firstrun/wizard.py @@ -0,0 +1,269 @@ +#!/usr/bin/env python +import logging + +import sip +sip.setapi('QString', 2) +sip.setapi('QVariant', 2) + +from PyQt4 import QtCore +from PyQt4 import QtGui + +from leap.base import checks as basechecks +from leap.crypto import leapkeyring +from leap.eip import checks as eipchecks + +from leap.gui import firstrun + +from leap.gui import mainwindow_rc + +try: + from collections import OrderedDict +except ImportError: + # We must be in 2.6 + from leap.util.dicts import OrderedDict + +logger = logging.getLogger(__name__) + +""" +~~~~~~~~~~~~~~~~~~~~~~~~~~ +Work in progress! +~~~~~~~~~~~~~~~~~~~~~~~~~~ +This wizard still needs to be refactored out. + +TODO-ish: + +[X] Break file in wizard / pages files (and its own folder). +[ ] Separate presentation from logic. +[ ] Have a "manager" class for connections, that can be + dep-injected for testing. +[ ] Document signals used / expected. +[ ] Separate style from widgets. +[ ] Fix TOFU Widget for provider cert. +[ ] Refactor widgets out. +[ ] Follow more MVC style. +[ ] Maybe separate "first run wizard" into different wizards + that share some of the pages? +""" + + +class FirstRunWizard(QtGui.QWizard): + + def __init__( + self, + conductor_instance, + parent=None, + eip_username=None, + providers=None, + success_cb=None, is_provider_setup=False, + trusted_certs=None, + netchecker=basechecks.LeapNetworkChecker, + providercertchecker=eipchecks.ProviderCertChecker, + eipconfigchecker=eipchecks.EIPConfigChecker, + start_eipconnection_signal=None, + eip_statuschange_signal=None, + debug_server=None): + super(FirstRunWizard, self).__init__( + parent, + QtCore.Qt.WindowStaysOnTopHint) + + # we keep a reference to the conductor + # to be able to launch eip checks and connection + # in the connection page, before the wizard has ended. + self.conductor = conductor_instance + + self.eip_username = eip_username + self.providers = providers + + # success callback + self.success_cb = success_cb + + # is provider setup? + self.is_provider_setup = is_provider_setup + + # a dict with trusted fingerprints + # in the form {'nospacesfingerprint': ['host1', 'host2']} + self.trusted_certs = trusted_certs + + # Checkers + self.netchecker = netchecker + self.providercertchecker = providercertchecker + self.eipconfigchecker = eipconfigchecker + + # debug server + self.debug_server = debug_server + + # Signals + # will be emitted in connecting page + self.start_eipconnection_signal = start_eipconnection_signal + self.eip_statuschange_signal = eip_statuschange_signal + + self.providerconfig = None + # previously registered + # if True, jumps to LogIn page. + # by setting 1st page?? + #self.is_previously_registered = is_previously_registered + # XXX ??? ^v + self.is_previously_registered = bool(self.eip_username) + self.from_login = False + + pages_dict = OrderedDict(( + ('intro', firstrun.intro.IntroPage), + ('providerselection', + firstrun.selectprovider.SelectProviderPage), + ('login', firstrun.login.LogInPage), + ('providerinfo', firstrun.providerinfo.ProviderInfoPage), + ('providersetupvalidation', + firstrun.providersetup.ProviderSetupValidationPage), + ('signup', firstrun.register.RegisterUserPage), + ('connecting', firstrun.connect.ConnectingPage), + ('lastpage', firstrun.last.LastPage) + )) + self.add_pages_from_dict(pages_dict) + + self.validation_errors = {} + + self.setPixmap( + QtGui.QWizard.BannerPixmap, + QtGui.QPixmap(':/images/banner.png')) + self.setPixmap( + QtGui.QWizard.BackgroundPixmap, + QtGui.QPixmap(':/images/background.png')) + + self.setWindowTitle("First Run Wizard") + + # TODO: set style for MAC / windows ... + #self.setWizardStyle() + + def add_pages_from_dict(self, pages_dict): + """ + @param pages_dict: the dictionary with pages, where + values are a tuple of InstanceofWizardPage, kwargs. + @type pages_dict: dict + """ + for name, page in pages_dict.items(): + # XXX check for is_previously registered + # and skip adding the signup branch if so + self.addPage(page()) + self.pages_dict = pages_dict + + def get_page_index(self, page_name): + """ + returns the index of the given page + @param page_name: the name of the desired page + @type page_name: str + @rparam: index of page in wizard + @rtype: int + """ + return self.pages_dict.keys().index(page_name) + + def set_validation_error(self, pagename, error): + self.validation_errors[pagename] = error + + def get_validation_error(self, pagename): + return self.validation_errors.get(pagename, None) + + def set_providerconfig(self, providerconfig): + self.providerconfig = providerconfig + + def setWindowFlags(self, flags): + logger.debug('setting window flags') + QtGui.QWizard.setWindowFlags(self, flags) + + def focusOutEvent(self, event): + # needed ? + self.setFocus(True) + self.activateWindow() + self.raise_() + self.show() + + def accept(self): + """ + final step in the wizard. + gather the info, update settings + and call the success callback if any has been passed. + """ + super(FirstRunWizard, self).accept() + + # username and password are in different fields + # if they were stored in log_in or sign_up pages. + from_login = self.from_login + unamek_base = 'userName' + passwk_base = 'userPassword' + unamek = 'login_%s' % unamek_base if from_login else unamek_base + passwk = 'login_%s' % passwk_base if from_login else passwk_base + + username = self.field(unamek) + password = self.field(passwk) + provider = self.field('provider_domain') + remember_pass = self.field('rememberPassword') + + logger.debug('chosen provider: %s', provider) + logger.debug('username: %s', username) + logger.debug('remember password: %s', remember_pass) + + # we are assuming here that we only remember one username + # in the form username@provider.domain + # We probably could extend this to support some form of + # profiles. + + settings = QtCore.QSettings() + + settings.setValue("FirstRunWizardDone", True) + settings.setValue("provider_domain", provider) + full_username = "%s@%s" % (username, provider) + + settings.setValue("remember_user_and_pass", remember_pass) + + if remember_pass: + settings.setValue("eip_username", full_username) + seed = self.get_random_str(10) + settings.setValue("%s_seed" % provider, seed) + + # XXX #744: comment out for 0.2.0 release + # if we need to have a version of python-keyring < 0.9 + leapkeyring.leap_set_password( + full_username, password, seed=seed) + + logger.debug('First Run Wizard Done.') + cb = self.success_cb + if cb and callable(cb): + self.success_cb() + + def get_provider_by_index(self): + provider = self.field('provider_index') + return self.providers[provider] + + def get_random_str(self, n): + from string import (ascii_uppercase, ascii_lowercase, digits) + from random import choice + return ''.join(choice( + ascii_uppercase + + ascii_lowercase + + digits) for x in range(n)) + + +if __name__ == '__main__': + # standalone test + # it can be (somehow) run against + # gui/tests/integration/fake_user_signup.py + + import sys + import logging + logging.basicConfig() + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + + app = QtGui.QApplication(sys.argv) + server = sys.argv[1] if len(sys.argv) > 1 else None + + trusted_certs = { + "3DF83F316BFA0186" + "0A11A5C9C7FC24B9" + "18C62B941192CC1A" + "49AE62218B2A4B7C": ['springbok']} + + wizard = FirstRunWizard( + None, trusted_certs=trusted_certs, + debug_server=server) + wizard.show() + sys.exit(app.exec_()) -- cgit v1.2.3 From 00009f8a7de957c4d53c10855cae1396108203c3 Mon Sep 17 00:00:00 2001 From: kali Date: Tue, 6 Nov 2012 16:35:48 +0900 Subject: add 404 catch to register --- src/leap/gui/firstrun/register.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index b04844bf..b169f45b 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -101,6 +101,7 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): "Register a new user with provider %s." % provider) self.validationMsg.setText('') + self.userPassword2LineEdit.setText('') def validatePage(self): """ @@ -110,12 +111,6 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): returned we write validation error msg above the form. """ - # the slot for this signal is not doing - # what's expected. Investigate why, - # right now we're not giving any feedback - # to the user re. what's going on. The only - # thing I can see as a workaround is setting - # a low timeout. wizard = self.wizard() self.setSigningUpStatus.emit() @@ -124,7 +119,9 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): password = self.userPasswordLineEdit.text() password2 = self.userPassword2LineEdit.text() - # have some call to a password checker... + # we better have here + # some call to a password checker... + # to assess strenght and avoid silly stuff. if password != password2: self.set_validation_status('Password does not match.') @@ -161,7 +158,9 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): else: # this is the real thing signup = auth.LeapSRPRegister( - # XXX FIXME 0 Force HTTPS + # XXX FIXME FIXME FIXME FIXME + # XXX FIXME 0 Force HTTPS !!! + # XXX FIXME FIXME FIXME FIXME #schema="https", schema="http", provider=domain) @@ -191,6 +190,11 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): "Error during registration (500)") return False + if req.status_code == 404: + self.set_validation_status( + "Error during registration (404)") + return False + validation_msgs = json.loads(req.content) logger.debug('validation errors: %s' % validation_msgs) errors = validation_msgs.get('errors', None) -- cgit v1.2.3 From 6032f776cabcd04aa7f4e1f55a34ecfec2775e85 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 7 Nov 2012 04:48:12 +0900 Subject: changes to update_signal + Fix update + Rename + Changed signature (we update progress bar from slot now) --- src/leap/gui/firstrun/providerinfo.py | 42 +++++++++++++++++++++++++++++----- src/leap/gui/firstrun/providersetup.py | 14 ++++-------- 2 files changed, 41 insertions(+), 15 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index f5f5518a..52b4873f 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -2,22 +2,26 @@ Provider Info Page, used in First run Wizard """ +from PyQt4 import QtCore from PyQt4 import QtGui +from leap.gui.progress import ValidationPage + from leap.gui.constants import APP_LOGO -class ProviderInfoPage(QtGui.QWizardPage): +class ProviderInfoPage(ValidationPage): def __init__(self, parent=None): super(ProviderInfoPage, self).__init__(parent) self.setTitle("Provider Info") - self.setSubTitle("Available information about chosen provider.") + #self.setSubTitle("Available information about chosen provider.") self.setPixmap( QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) + def create_info_panel(self): displayName = QtGui.QLabel("") description = QtGui.QLabel("") enrollment_policy = QtGui.QLabel("") @@ -28,15 +32,18 @@ class ProviderInfoPage(QtGui.QWizardPage): self.description = description self.enrollment_policy = enrollment_policy + # this trick allows us to reparent + QtCore.QObjectCleanupHandler().add(self.layout) layout = QtGui.QGridLayout() + layout.addWidget(displayName, 0, 1) layout.addWidget(description, 1, 1) layout.addWidget(enrollment_policy, 2, 1) self.setLayout(layout) + self.update() - def initializePage(self): - # XXX move to show info... + def show_provider_info(self): # XXX get multilingual objects # directly from the config object @@ -59,9 +66,32 @@ class ProviderInfoPage(QtGui.QWizardPage): self.enrollment_policy.setText( 'enrollment policy: %s' % enroll) + def _do_checks(self, update_signal=None): + """ + executes actual checks in a separate thread + """ + import time + update_signal.emit("head_sentinel", 0) + time.sleep(0.5) + update_signal.emit("something", 10) + time.sleep(0.5) + update_signal.emit("done", 90) + time.sleep(1) + update_signal.emit("end_sentinel", 100) + time.sleep(1) + + def _do_validation(self): + """ + called after _do_checks has finished + (connected to checker thread finished signal) + """ + print 'validation...' + self.progress.hide() + self.stepsTableWidget.hide() + self.create_info_panel() + self.show_provider_info() + def nextId(self): wizard = self.wizard() next_ = "providersetupvalidation" return wizard.get_page_index(next_) - - diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index 63f55d00..c039dfc5 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -21,7 +21,7 @@ class ProviderSetupValidationPage(ValidationPage): QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) - def _do_checks(self, signal=None): + def _do_checks(self, update_signal=None): """ executes actual checks in a separate thread """ @@ -33,8 +33,7 @@ class ProviderSetupValidationPage(ValidationPage): pCertChecker = wizard.providercertchecker certchecker = pCertChecker(domain=domain) - signal.emit('Fetching CA certificate') - self.progress.setValue(30) + update_signal.emit('Fetching CA certificate', 30) if pconfig: ca_cert_uri = pconfig.get('ca_cert_uri').geturl() @@ -54,8 +53,7 @@ class ProviderSetupValidationPage(ValidationPage): time.sleep(2) - signal.emit('Checking CA fingerprint') - self.progress.setValue(66) + update_signal.emit('Checking CA fingerprint', 66) #ca_cert_fingerprint = pconfig.get('ca_cert_fingerprint', None) # XXX get fingerprint dict (types) @@ -69,8 +67,7 @@ class ProviderSetupValidationPage(ValidationPage): # should catch exception #return False - signal.emit('Validating api certificate') - self.progress.setValue(90) + update_signal.emit('Validating api certificate', 90) #api_uri = pconfig.get('api_uri', None) #try: @@ -91,8 +88,7 @@ class ProviderSetupValidationPage(ValidationPage): time.sleep(0.5) #ca_cert_path = checker.ca_cert_path - self.progress.setValue(100) - signal.emit('end_sentinel') + update_signal.emit('end_sentinel', 100) time.sleep(1) def _do_validation(self): -- cgit v1.2.3 From 63fc5b19e39072f4bda26f2649e83832d68b5000 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 7 Nov 2012 06:06:40 +0900 Subject: fix issue with refresh timing using end_sentinel as a workaround for the lack of refresh. doing a pause so user gets some feedback about what's going on. error messages on select provider page should be all covered now. --- src/leap/gui/firstrun/providerinfo.py | 126 +++++++++++++++++++++++++++++--- src/leap/gui/firstrun/selectprovider.py | 95 +++++++----------------- 2 files changed, 142 insertions(+), 79 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index 52b4873f..5cc34927 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -1,14 +1,27 @@ """ Provider Info Page, used in First run Wizard """ +import logging +import time from PyQt4 import QtCore from PyQt4 import QtGui +import requests + +from leap.base import exceptions as baseexceptions +from leap.crypto import certs +from leap.eip import exceptions as eipexceptions + from leap.gui.progress import ValidationPage from leap.gui.constants import APP_LOGO +logger = logging.getLogger(__name__) + +GUI_PAUSE_FOR_USER_SECONDS = 1 +pause_for_user = lambda: time.sleep(GUI_PAUSE_FOR_USER_SECONDS) + class ProviderInfoPage(ValidationPage): def __init__(self, parent=None): @@ -70,15 +83,95 @@ class ProviderInfoPage(ValidationPage): """ executes actual checks in a separate thread """ - import time + def pause_and_finish(): + update_signal.emit("end_sentinel", 100) + pause_for_user() + + wizard = self.wizard() + prevpage = "providerselection" + netchecker = wizard.netchecker() + providercertchecker = wizard.providercertchecker() + eipconfigchecker = wizard.eipconfigchecker() + + domain = self.field('provider_domain') + update_signal.emit("head_sentinel", 0) - time.sleep(0.5) - update_signal.emit("something", 10) - time.sleep(0.5) - update_signal.emit("done", 90) - time.sleep(1) - update_signal.emit("end_sentinel", 100) - time.sleep(1) + pause_for_user() + + # 1) try name resolution + update_signal.emit("Checking that server is reachable", 20) + logger.debug('checking name resolution') + try: + netchecker.check_name_resolution( + domain) + + except baseexceptions.LeapException as exc: + logger.debug('exception') + wizard.set_validation_error( + prevpage, exc.usermessage) + pause_and_finish() + return False + + # 2) try https connection + update_signal.emit("Checking secure connection to provider", 40) + logger.debug('checking https connection') + try: + providercertchecker.is_https_working( + "https://%s" % domain, + verify=True) + + except eipexceptions.HttpsBadCertError as exc: + logger.debug('exception') + # XXX skipping for now... + ############################################## + # We had this validation logic + # in the provider selection page before + ############################################## + #if self.trustProviderCertCheckBox.isChecked(): + #pass + #else: + wizard.set_validation_error( + prevpage, exc.usermessage) + #fingerprint = certs.get_cert_fingerprint( + #domain=domain, sep=" ") + + # it's ok if we've trusted this fgprt before + #trustedcrts = wizard.trusted_certs + #if trustedcrts and fingerprint.replace(' ', '') in trustedcrts: + #pass + #else: + # let your user face panick :P + #self.add_cert_info(fingerprint) + #self.did_cert_check = True + #self.completeChanged.emit() + #return False + pause_and_finish() + return False + + except baseexceptions.LeapException as exc: + wizard.set_validation_error( + prevpage, exc.usermessage) + pause_and_finish() + return False + + # try download provider info... + update_signal.emit("Downloading provider info", 70) + try: + eipconfigchecker.fetch_definition(domain=domain) + wizard.set_providerconfig( + eipconfigchecker.defaultprovider.config) + # XXX catch errors... + except requests.exceptions.SSLError: + # XXX we should have catched this before. + # but cert checking is broken. + wizard.set_validation_error( + prevpage, + "Could not get info from provider.") + pause_and_finish() + return False + + # We're done + pause_and_finish() def _do_validation(self): """ @@ -86,10 +179,19 @@ class ProviderInfoPage(ValidationPage): (connected to checker thread finished signal) """ print 'validation...' - self.progress.hide() - self.stepsTableWidget.hide() - self.create_info_panel() - self.show_provider_info() + prevpage = "providerselection" + errors = self.wizard().get_validation_error(prevpage) + + if not errors: + self.progress.hide() + self.stepsTableWidget.hide() + self.create_info_panel() + self.show_provider_info() + + else: + logger.debug('going back with errors') + logger.debug('ERRORS: %s' % errors) + self.go_back() def nextId(self): wizard = self.wizard() diff --git a/src/leap/gui/firstrun/selectprovider.py b/src/leap/gui/firstrun/selectprovider.py index d26fdbbb..e95a4af2 100644 --- a/src/leap/gui/firstrun/selectprovider.py +++ b/src/leap/gui/firstrun/selectprovider.py @@ -1,6 +1,8 @@ """ Select Provider Page, used in First Run Wizard """ +import logging + from PyQt4 import QtCore from PyQt4 import QtGui @@ -11,6 +13,8 @@ from leap.eip import exceptions as eipexceptions from leap.gui.constants import APP_LOGO from leap.gui.styles import ErrorLabelStyleSheet +logger = logging.getLogger(__name__) + class SelectProviderPage(QtGui.QWizardPage): def __init__(self, parent=None, providers=None): @@ -136,77 +140,34 @@ class SelectProviderPage(QtGui.QWizardPage): return True return False + def populateErrors(self): + # XXX could move this to ValidationMixin + + #logger.debug('getting errors') + errors = self.wizard().get_validation_error('providerselection') + if errors: + #logger.debug('errors! -> %s', errors) + self.validationMsg.setText(errors) + + def paintEvent(self, event): + """ + we hook our populate errors + on paintEvent because we need it to catch + when user enters the page coming from next, + and initializePage does not cover that case. + Maybe there's a better event to hook upon. + """ + super(SelectProviderPage, self).paintEvent(event) + self.populateErrors() + def initializePage(self): + self.validationMsg.setText('') self.certinfoGroup.hide() def validatePage(self): - ################################## - # XXX FIXME! - ################################## - ################################## - ################################## - ################################## - ##### validation skipped !!! ##### - ################################## - ################################## - return True - ################################## - ################################## - ################################## - - # XXX move to ProviderInfo... - - wizard = self.wizard() - netchecker = wizard.netchecker() - providercertchecker = wizard.providercertchecker() - eipconfigchecker = wizard.eipconfigchecker() - - domain = self.providerNameEdit.text() - - # try name resolution - try: - netchecker.check_name_resolution( - domain) - - except baseexceptions.LeapException as exc: - self.set_validation_status(exc.usermessage) - return False - - # try https connection - try: - providercertchecker.is_https_working( - "https://%s" % domain, - verify=True) - - except eipexceptions.HttpsBadCertError as exc: - if self.trustProviderCertCheckBox.isChecked(): - pass - else: - self.set_validation_status(exc.usermessage) - fingerprint = certs.get_cert_fingerprint( - domain=domain, sep=" ") - - # it's ok if we've trusted this fgprt before - trustedcrts = self.wizard().trusted_certs - if trustedcrts and fingerprint.replace(' ', '') in trustedcrts: - pass - else: - # let your user face panick :P - self.add_cert_info(fingerprint) - self.did_cert_check = True - self.completeChanged.emit() - return False - - except baseexceptions.LeapException as exc: - self.set_validation_status(exc.usermessage) - return False - - # try download provider info... - eipconfigchecker.fetch_definition(domain=domain) - wizard.set_providerconfig( - eipconfigchecker.defaultprovider.config) - - # all ok, go on... + """ + we are doing validation in next page + """ return True def nextId(self): -- cgit v1.2.3 From ee5928e4e066ac9f72a7dec15972817746dbc058 Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 8 Nov 2012 05:10:22 +0900 Subject: allow user to specify host:port for provider selection --- src/leap/gui/firstrun/providerinfo.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index 5cc34927..06e00682 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -23,6 +23,21 @@ GUI_PAUSE_FOR_USER_SECONDS = 1 pause_for_user = lambda: time.sleep(GUI_PAUSE_FOR_USER_SECONDS) +def get_https_domain_and_port(full_domain): + """ + returns a tuple with domain and port + from a full_domain string that can + contain a colon + """ + domain_split = full_domain.split(':') + _len = len(domain_split) + if _len == 1: + domain, port = full_domain, 443 + if _len == 2: + domain, port = domain_split + return domain, port + + class ProviderInfoPage(ValidationPage): def __init__(self, parent=None): super(ProviderInfoPage, self).__init__(parent) @@ -93,12 +108,18 @@ class ProviderInfoPage(ValidationPage): providercertchecker = wizard.providercertchecker() eipconfigchecker = wizard.eipconfigchecker() - domain = self.field('provider_domain') + full_domain = self.field('provider_domain') + + # we check if we have a port in the domain string. + domain, port = get_https_domain_and_port(full_domain) + _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain) update_signal.emit("head_sentinel", 0) pause_for_user() + ######################## # 1) try name resolution + ######################## update_signal.emit("Checking that server is reachable", 20) logger.debug('checking name resolution') try: @@ -112,12 +133,14 @@ class ProviderInfoPage(ValidationPage): pause_and_finish() return False + ######################### # 2) try https connection + ######################### update_signal.emit("Checking secure connection to provider", 40) logger.debug('checking https connection') try: providercertchecker.is_https_working( - "https://%s" % domain, + "https://%s" % _domain, verify=True) except eipexceptions.HttpsBadCertError as exc: -- cgit v1.2.3 From 6a4d0b8298e24968106007fabef16238300742cd Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 8 Nov 2012 05:15:27 +0900 Subject: catch conn error while fetching provider info --- src/leap/gui/firstrun/providerinfo.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index 06e00682..9b959602 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -177,13 +177,15 @@ class ProviderInfoPage(ValidationPage): pause_and_finish() return False - # try download provider info... + ################################## + # 3) try download provider info... + ################################## + update_signal.emit("Downloading provider info", 70) try: - eipconfigchecker.fetch_definition(domain=domain) + eipconfigchecker.fetch_definition(domain=_domain) wizard.set_providerconfig( eipconfigchecker.defaultprovider.config) - # XXX catch errors... except requests.exceptions.SSLError: # XXX we should have catched this before. # but cert checking is broken. @@ -192,8 +194,16 @@ class ProviderInfoPage(ValidationPage): "Could not get info from provider.") pause_and_finish() return False + except requests.exceptions.ConnectionError: + wizard.set_validation_error( + prevpage, + "Could not download provider info " + "(refused conn.).") + pause_and_finish() + return False + # XXX catch more errors... - # We're done + # We're done! pause_and_finish() def _do_validation(self): -- cgit v1.2.3 From b3c0634dc6e01656422a6c70297fc46d808f303f Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 8 Nov 2012 06:02:36 +0900 Subject: selectprovider rename + fix onComplete function for provider entry --- src/leap/gui/firstrun/__init__.py | 6 +- src/leap/gui/firstrun/providerselect.py | 181 ++++++++++++++++++++++++++++++++ src/leap/gui/firstrun/register.py | 95 ++--------------- src/leap/gui/firstrun/regvalidation.py | 140 ++++++++++++++++++++++++ src/leap/gui/firstrun/selectprovider.py | 177 ------------------------------- src/leap/gui/firstrun/wizard.py | 4 +- 6 files changed, 339 insertions(+), 264 deletions(-) create mode 100644 src/leap/gui/firstrun/providerselect.py create mode 100644 src/leap/gui/firstrun/regvalidation.py delete mode 100644 src/leap/gui/firstrun/selectprovider.py (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/__init__.py b/src/leap/gui/firstrun/__init__.py index bf8d0df9..477e7269 100644 --- a/src/leap/gui/firstrun/__init__.py +++ b/src/leap/gui/firstrun/__init__.py @@ -8,9 +8,10 @@ import last import login import mixins import providerinfo +import providerselect import providersetup import register -import selectprovider +import regvalidation __all__ = [ 'connect', @@ -19,6 +20,7 @@ __all__ = [ 'login', 'mixins', 'providerinfo', + 'providerselect', 'providersetup', 'register', - 'selectprovider'] + 'regvalidation'] diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py new file mode 100644 index 00000000..c282e3ab --- /dev/null +++ b/src/leap/gui/firstrun/providerselect.py @@ -0,0 +1,181 @@ +""" +Select Provider Page, used in First Run Wizard +""" +import logging + +from PyQt4 import QtCore +from PyQt4 import QtGui + +from leap.base import exceptions as baseexceptions +from leap.crypto import certs +from leap.eip import exceptions as eipexceptions + +from leap.gui.constants import APP_LOGO +from leap.gui.styles import ErrorLabelStyleSheet + +logger = logging.getLogger(__name__) + + +class SelectProviderPage(QtGui.QWizardPage): + def __init__(self, parent=None, providers=None): + super(SelectProviderPage, self).__init__(parent) + + self.setTitle("Enter Provider") + self.setSubTitle( + "Please enter the domain of the provider you want " + "to use for your connection." + ) + self.setPixmap( + QtGui.QWizard.LogoPixmap, + QtGui.QPixmap(APP_LOGO)) + + self.did_cert_check = False + + providerNameLabel = QtGui.QLabel("h&ttps://") + # note that we expect the bare domain name + # we will add the scheme later + providerNameEdit = QtGui.QLineEdit() + providerNameEdit.cursorPositionChanged.connect( + self.reset_validation_status) + providerNameLabel.setBuddy(providerNameEdit) + + # add regex validator + providerDomainRe = QtCore.QRegExp(r"^[a-z\d_-.]+$") + providerNameEdit.setValidator( + QtGui.QRegExpValidator(providerDomainRe, self)) + self.providerNameEdit = providerNameEdit + + # Eventually we will seed a list of + # well known providers here. + + #providercombo = QtGui.QComboBox() + #if providers: + #for provider in providers: + #providercombo.addItem(provider) + #providerNameSelect = providercombo + + self.registerField("provider_domain*", self.providerNameEdit) + #self.registerField('provider_name_index', providerNameSelect) + + validationMsg = QtGui.QLabel("") + validationMsg.setStyleSheet(ErrorLabelStyleSheet) + self.validationMsg = validationMsg + + # cert info + + # this is used in the callback + # for the checkbox changes. + # tricky, since the first time came + # from the exception message. + # should get string from exception too! + self.bad_cert_status = "Server certificate could not be verified." + + self.certInfo = QtGui.QLabel("") + self.certInfo.setWordWrap(True) + self.certWarning = QtGui.QLabel("") + self.trustProviderCertCheckBox = QtGui.QCheckBox( + "&Trust this provider certificate.") + + self.trustProviderCertCheckBox.stateChanged.connect( + self.onTrustCheckChanged) + self.providerNameEdit.textChanged.connect( + self.onProviderChanged) + + layout = QtGui.QGridLayout() + layout.addWidget(validationMsg, 0, 2) + layout.addWidget(providerNameLabel, 1, 1) + layout.addWidget(providerNameEdit, 1, 2) + + # XXX get a groupbox or something.... + certinfoGroup = QtGui.QGroupBox("Certificate validation") + certinfoLayout = QtGui.QVBoxLayout() + certinfoLayout.addWidget(self.certInfo) + certinfoLayout.addWidget(self.certWarning) + certinfoLayout.addWidget(self.trustProviderCertCheckBox) + certinfoGroup.setLayout(certinfoLayout) + + layout.addWidget(certinfoGroup, 4, 1, 4, 2) + self.certinfoGroup = certinfoGroup + self.certinfoGroup.hide() + + self.setLayout(layout) + + def is_insecure_cert_trusted(self): + return self.trustProviderCertCheckBox.isChecked() + + def onTrustCheckChanged(self, state): + checked = False + if state == 2: + checked = True + + if checked: + self.reset_validation_status() + else: + self.set_validation_status(self.bad_cert_status) + + # trigger signal to redraw next button + self.completeChanged.emit() + + def onProviderChanged(self, text): + self.completeChanged.emit() + + def reset_validation_status(self): + """ + empty the validation msg + """ + self.validationMsg.setText('') + + #def set_validation_status(selF, STATUS): + #self.validationMsg.setText(status) + + def add_cert_info(self, certinfo): + self.certWarning.setText( + "Do you want to trust this provider certificate?") + self.certInfo.setText( + 'SHA-256 fingerprint: %s
' % certinfo) + self.certInfo.setWordWrap(True) + self.certinfoGroup.show() + + # pagewizard methods + + def isComplete(self): + provider = self.providerNameEdit.text() + + if not provider: + return False + else: + if self.is_insecure_cert_trusted(): + return True + if not self.did_cert_check: + return True + return False + + def populateErrors(self): + # XXX could move this to ValidationMixin + + #logger.debug('getting errors') + errors = self.wizard().get_validation_error('providerselection') + if errors: + #logger.debug('errors! -> %s', errors) + self.validationMsg.setText(errors) + + def paintEvent(self, event): + """ + we hook our populate errors + on paintEvent because we need it to catch + when user enters the page coming from next, + and initializePage does not cover that case. + Maybe there's a better event to hook upon. + """ + super(SelectProviderPage, self).paintEvent(event) + self.populateErrors() + + def initializePage(self): + self.validationMsg.setText('') + self.certinfoGroup.hide() + + def nextId(self): + wizard = self.wizard() + if not wizard: + return + return wizard.get_page_index('providerinfo') diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index b169f45b..d7e8db0e 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -1,16 +1,12 @@ """ Register User Page, used in First Run Wizard """ -import json import logging -import socket -import requests from PyQt4 import QtCore from PyQt4 import QtGui -from leap.base import auth from leap.gui.firstrun.mixins import UserFormMixIn logger = logging.getLogger(__name__) @@ -20,9 +16,11 @@ from leap.gui.styles import ErrorLabelStyleSheet class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): + setSigningUpStatus = QtCore.pyqtSignal([]) def __init__(self, parent=None): + super(RegisterUserPage, self).__init__(parent) # bind wizard page signals @@ -105,17 +103,16 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): def validatePage(self): """ - validation - we initialize the srp protocol register - and try to register user. if error - returned we write validation error msg - above the form. + we only pre-validate here password weakness + stuff, or any other client side validation + that we think of. + real server validation is made on next page, + and if any errors are thrown there we come back + and re-display the validation label. """ - wizard = self.wizard() - self.setSigningUpStatus.emit() - username = self.userNameLineEdit.text() + #username = self.userNameLineEdit.text() password = self.userPasswordLineEdit.text() password2 = self.userPassword2LineEdit.text() @@ -136,80 +133,10 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): self.set_validation_status('Password too obvious.') return False - domain = self.field('provider_domain') - - if wizard and wizard.debug_server: - # We're debugging - dbgsrv = wizard.debug_server - schema = dbgsrv.scheme - netloc = dbgsrv.netloc - port = None - netloc_split = netloc.split(':') - if len(netloc_split) > 1: - provider, port = netloc_split - else: - provider = netloc - - signup = auth.LeapSRPRegister( - scheme=schema, - provider=provider, - port=port) - - else: - # this is the real thing - signup = auth.LeapSRPRegister( - # XXX FIXME FIXME FIXME FIXME - # XXX FIXME 0 Force HTTPS !!! - # XXX FIXME FIXME FIXME FIXME - #schema="https", - schema="http", - provider=domain) - try: - ok, req = signup.register_user(username, password) - except socket.timeout: - self.set_validation_status( - "Error connecting to provider (timeout)") - return False - - except requests.exceptions.ConnectionError as exc: - logger.error(exc) - self.set_validation_status( - "Error connecting to provider " - "(connection error)") - return False - - if ok: - return True - - # something went wrong. - # not registered, let's catch what. - # get timeout - # ... - if req.status_code == 500: - self.set_validation_status( - "Error during registration (500)") - return False - - if req.status_code == 404: - self.set_validation_status( - "Error during registration (404)") - return False - - validation_msgs = json.loads(req.content) - logger.debug('validation errors: %s' % validation_msgs) - errors = validation_msgs.get('errors', None) - if errors and errors.get('login', None): - # XXX this sometimes catch the blank username - # but we're not allowing that (soon) - self.set_validation_status( - 'Username not available.') - else: - self.set_validation_status( - "Error during sign up") - return False + return True def nextId(self): wizard = self.wizard() if not wizard: return - return wizard.get_page_index('connecting') + return wizard.get_page_index('signupvalidation') diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py new file mode 100644 index 00000000..42b9ccd5 --- /dev/null +++ b/src/leap/gui/firstrun/regvalidation.py @@ -0,0 +1,140 @@ +""" +Provider Setup Validation Page, +used if First Run Wizard +""" +import logging +import json +import socket +import time + +from PyQt4 import QtGui + +import requests + +from leap.gui.progress import ValidationPage + +from leap.base import auth +from leap.gui.constants import APP_LOGO + +logger = logging.getLogger(__name__) + + +class RegisterUserValidationPage(ValidationPage): + + def __init__(self, parent=None): + + super(RegisterUserValidationPage, self).__init__(parent) + self.setTitle("User Creation") + self.setSubTitle( + "Registering account with provider.") + + self.setPixmap( + QtGui.QWizard.LogoPixmap, + QtGui.QPixmap(APP_LOGO)) + + def _do_checks(self, update_signal=None): + """ + executes actual checks in a separate thread + + we initialize the srp protocol register + and try to register user. + """ + wizard = self.wizard() + domain = self.field('provider_domain') + username = self.field('userName') + password = self.field('userPassword') + + update_signal.emit("head_sentinel") + update_signal.emit("registering with provider", 40) + time.sleep(4) + + if wizard and wizard.debug_server: + # We're debugging + dbgsrv = wizard.debug_server + schema = dbgsrv.scheme + netloc = dbgsrv.netloc + port = None + netloc_split = netloc.split(':') + if len(netloc_split) > 1: + provider, port = netloc_split + else: + provider = netloc + + signup = auth.LeapSRPRegister( + scheme=schema, + provider=provider, + port=port) + + else: + # this is the real thing + signup = auth.LeapSRPRegister( + # XXX FIXME FIXME FIXME FIXME + # XXX FIXME 0 Force HTTPS !!! + # XXX FIXME FIXME FIXME FIXME + #schema="https", + schema="http", + provider=domain) + try: + ok, req = signup.register_user(username, password) + except socket.timeout: + self.set_validation_status( + "Error connecting to provider (timeout)") + return False + + except requests.exceptions.ConnectionError as exc: + logger.error(exc) + self.set_validation_status( + "Error connecting to provider " + "(connection error)") + return False + + if ok: + return True + + # something went wrong. + # not registered, let's catch what. + # get timeout + # ... + if req.status_code == 500: + self.set_validation_status( + "Error during registration (500)") + return False + + if req.status_code == 404: + self.set_validation_status( + "Error during registration (404)") + return False + + validation_msgs = json.loads(req.content) + logger.debug('validation errors: %s' % validation_msgs) + errors = validation_msgs.get('errors', None) + if errors and errors.get('login', None): + # XXX this sometimes catch the blank username + # but we're not allowing that (soon) + self.set_validation_status( + 'Username not available.') + else: + self.set_validation_status( + "Error during sign up") + return False + + def _do_validation(self): + """ + called after _do_checks has finished + (connected to checker thread finished signal) + """ + wizard = self.wizard() + if self.errors: + print 'going back with errors' + wizard.set_validation_error( + 'signup', 'that name is taken') + self.go_back() + else: + print 'going next' + self.go_next() + + def nextId(self): + wizard = self.wizard() + if not wizard: + return + return wizard.get_page_index('connecting') diff --git a/src/leap/gui/firstrun/selectprovider.py b/src/leap/gui/firstrun/selectprovider.py deleted file mode 100644 index e95a4af2..00000000 --- a/src/leap/gui/firstrun/selectprovider.py +++ /dev/null @@ -1,177 +0,0 @@ -""" -Select Provider Page, used in First Run Wizard -""" -import logging - -from PyQt4 import QtCore -from PyQt4 import QtGui - -from leap.base import exceptions as baseexceptions -from leap.crypto import certs -from leap.eip import exceptions as eipexceptions - -from leap.gui.constants import APP_LOGO -from leap.gui.styles import ErrorLabelStyleSheet - -logger = logging.getLogger(__name__) - - -class SelectProviderPage(QtGui.QWizardPage): - def __init__(self, parent=None, providers=None): - super(SelectProviderPage, self).__init__(parent) - - self.setTitle("Enter Provider") - self.setSubTitle( - "Please enter the domain of the provider you want " - "to use for your connection." - ) - self.setPixmap( - QtGui.QWizard.LogoPixmap, - QtGui.QPixmap(APP_LOGO)) - - self.did_cert_check = False - - providerNameLabel = QtGui.QLabel("h&ttps://") - # note that we expect the bare domain name - # we will add the scheme later - providerNameEdit = QtGui.QLineEdit() - providerNameEdit.cursorPositionChanged.connect( - self.reset_validation_status) - providerNameLabel.setBuddy(providerNameEdit) - - # add regex validator - providerDomainRe = QtCore.QRegExp(r"^[a-z\d_-.]+$") - providerNameEdit.setValidator( - QtGui.QRegExpValidator(providerDomainRe, self)) - self.providerNameEdit = providerNameEdit - - # Eventually we will seed a list of - # well known providers here. - - #providercombo = QtGui.QComboBox() - #if providers: - #for provider in providers: - #providercombo.addItem(provider) - #providerNameSelect = providercombo - - self.registerField('provider_domain*', self.providerNameEdit) - #self.registerField('provider_name_index', providerNameSelect) - - validationMsg = QtGui.QLabel("") - validationMsg.setStyleSheet(ErrorLabelStyleSheet) - self.validationMsg = validationMsg - - # cert info - - # this is used in the callback - # for the checkbox changes. - # tricky, since the first time came - # from the exception message. - # should get string from exception too! - self.bad_cert_status = "Server certificate could not be verified." - - self.certInfo = QtGui.QLabel("") - self.certInfo.setWordWrap(True) - self.certWarning = QtGui.QLabel("") - self.trustProviderCertCheckBox = QtGui.QCheckBox( - "&Trust this provider certificate.") - - self.trustProviderCertCheckBox.stateChanged.connect( - self.onTrustCheckChanged) - - layout = QtGui.QGridLayout() - layout.addWidget(validationMsg, 0, 2) - layout.addWidget(providerNameLabel, 1, 1) - layout.addWidget(providerNameEdit, 1, 2) - - # XXX get a groupbox or something.... - certinfoGroup = QtGui.QGroupBox("Certificate validation") - certinfoLayout = QtGui.QVBoxLayout() - certinfoLayout.addWidget(self.certInfo) - certinfoLayout.addWidget(self.certWarning) - certinfoLayout.addWidget(self.trustProviderCertCheckBox) - certinfoGroup.setLayout(certinfoLayout) - - layout.addWidget(certinfoGroup, 4, 1, 4, 2) - self.certinfoGroup = certinfoGroup - self.certinfoGroup.hide() - - self.setLayout(layout) - - def is_insecure_cert_trusted(self): - return self.trustProviderCertCheckBox.isChecked() - - def onTrustCheckChanged(self, state): - checked = False - if state == 2: - checked = True - - if checked: - self.reset_validation_status() - else: - self.set_validation_status(self.bad_cert_status) - - # trigger signal to redraw next button - self.completeChanged.emit() - - def reset_validation_status(self): - """ - empty the validation msg - """ - self.validationMsg.setText('') - - def set_validation_status(self, status): - self.validationMsg.setText(status) - - def add_cert_info(self, certinfo): - self.certWarning.setText( - "Do you want to trust this provider certificate?") - self.certInfo.setText( - 'SHA-256 fingerprint: %s
' % certinfo) - self.certInfo.setWordWrap(True) - self.certinfoGroup.show() - - # pagewizard methods - - def isComplete(self): - if not self.did_cert_check: - return True - if self.is_insecure_cert_trusted(): - return True - return False - - def populateErrors(self): - # XXX could move this to ValidationMixin - - #logger.debug('getting errors') - errors = self.wizard().get_validation_error('providerselection') - if errors: - #logger.debug('errors! -> %s', errors) - self.validationMsg.setText(errors) - - def paintEvent(self, event): - """ - we hook our populate errors - on paintEvent because we need it to catch - when user enters the page coming from next, - and initializePage does not cover that case. - Maybe there's a better event to hook upon. - """ - super(SelectProviderPage, self).paintEvent(event) - self.populateErrors() - - def initializePage(self): - self.validationMsg.setText('') - self.certinfoGroup.hide() - - def validatePage(self): - """ - we are doing validation in next page - """ - return True - - def nextId(self): - wizard = self.wizard() - if not wizard: - return - return wizard.get_page_index('providerinfo') diff --git a/src/leap/gui/firstrun/wizard.py b/src/leap/gui/firstrun/wizard.py index fb601714..7a3d6973 100755 --- a/src/leap/gui/firstrun/wizard.py +++ b/src/leap/gui/firstrun/wizard.py @@ -109,12 +109,14 @@ class FirstRunWizard(QtGui.QWizard): pages_dict = OrderedDict(( ('intro', firstrun.intro.IntroPage), ('providerselection', - firstrun.selectprovider.SelectProviderPage), + firstrun.providerselect.SelectProviderPage), ('login', firstrun.login.LogInPage), ('providerinfo', firstrun.providerinfo.ProviderInfoPage), ('providersetupvalidation', firstrun.providersetup.ProviderSetupValidationPage), ('signup', firstrun.register.RegisterUserPage), + ('signupvalidation', + firstrun.regvalidation.RegisterUserValidationPage), ('connecting', firstrun.connect.ConnectingPage), ('lastpage', firstrun.last.LastPage) )) -- cgit v1.2.3 From b84007d8fec8c949ba4ac1d26695c710a210d797 Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 8 Nov 2012 08:37:24 +0900 Subject: more careful error catching during registration. added a twisted server that fakes some of the provider interaction. --- src/leap/gui/firstrun/connect.py | 38 +++--- src/leap/gui/firstrun/providersetup.py | 3 +- src/leap/gui/firstrun/regvalidation.py | 12 +- .../firstrun/tests/integration/fake_provider.py | 132 +++++++++++++++++++++ 4 files changed, 167 insertions(+), 18 deletions(-) create mode 100755 src/leap/gui/firstrun/tests/integration/fake_provider.py (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/connect.py b/src/leap/gui/firstrun/connect.py index 3172a526..283e81b2 100644 --- a/src/leap/gui/firstrun/connect.py +++ b/src/leap/gui/firstrun/connect.py @@ -91,12 +91,19 @@ class ConnectingPage(QtGui.QWizardPage): wizard, 'start_eipconnection_signal', None) - conductor.set_provider_domain(domain) - conductor.run_checks() - self.conductor = conductor - errors = self.eip_error_check() - if not errors and start_eip_signal: - start_eip_signal.emit() + if conductor: + conductor.set_provider_domain(domain) + conductor.run_checks() + self.conductor = conductor + errors = self.eip_error_check() + if not errors and start_eip_signal: + start_eip_signal.emit() + + else: + logger.warning( + "No conductor found. This means that " + "probably the wizard has been launched " + "in an stand-alone way") def eip_error_check(self): """ @@ -110,6 +117,7 @@ class ConnectingPage(QtGui.QWizardPage): # XXX missing! def fetch_and_validate(self): + # XXX MOVE TO validate function in register-validation import time domain = self.field('provider_domain') wizard = self.wizard() @@ -150,15 +158,15 @@ class ConnectingPage(QtGui.QWizardPage): # Download cert try: pCertChecker.download_new_client_cert( - credentials=credentials) - except auth.SRPAuthenticationError: - self.set_validation_status("Authentication error") - #self.set_validation_message( - #"Click next to introduce your " - #"credentials again") - self.goto_login_again = True - # We should do something here - # but it's broken + credentials=credentials, + # FIXME FIXME FIXME + # XXX FIX THIS!!!!! + # BUG #638. remove verify + # FIXME FIXME FIXME + verify=False) + except auth.SRPAuthenticationError as exc: + self.set_validation_status( + "Authentication error: %s" % exc.message) return False time.sleep(2) diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index c039dfc5..2609629a 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -100,7 +100,8 @@ class ProviderSetupValidationPage(ValidationPage): if self.errors: print 'going back with errors' wizard.set_validation_error( - 'signup', 'that name is taken') + 'providerselection', + 'error on provider setup') self.go_back() else: print 'going next' diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index 42b9ccd5..6cf150b6 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -39,14 +39,22 @@ class RegisterUserValidationPage(ValidationPage): we initialize the srp protocol register and try to register user. """ + print 'register user checks' + wizard = self.wizard() domain = self.field('provider_domain') username = self.field('userName') password = self.field('userPassword') - update_signal.emit("head_sentinel") + # XXX use pause_for_user from providerinfo + update_signal.emit("head_sentinel", 0) update_signal.emit("registering with provider", 40) - time.sleep(4) + time.sleep(0.5) + update_signal.emit("registering 2", 60) + time.sleep(1) + update_signal.emit("end_sentinel", 100) + time.sleep(0.5) + return if wizard and wizard.debug_server: # We're debugging diff --git a/src/leap/gui/firstrun/tests/integration/fake_provider.py b/src/leap/gui/firstrun/tests/integration/fake_provider.py new file mode 100755 index 00000000..27886d3b --- /dev/null +++ b/src/leap/gui/firstrun/tests/integration/fake_provider.py @@ -0,0 +1,132 @@ +#/usr/bin/env python +"""A server faking some of the provider resources and apis, +used for testing Leap Client requests. + +Right needs that you create a subfolder named 'certs', +and that you place the following files: + +[ ] certs/leaptestscert.pem +[ ] certs/leaptestskey.pem +[ ] certs/cacert.pem +[ ] certs/openvpn.pem + +[ ] provider.json +[ ] eip-service.json + +""" +import json +import os +import sys + +# GnuTLS Example -- is not working as expected +from gnutls import crypto +from gnutls.constants import COMP_LZO, COMP_DEFLATE, COMP_NULL +from gnutls.interfaces.twisted import X509Credentials + +# Going with OpenSSL as a workaround instead +# But we DO NOT want to introduce this dependency. +from OpenSSL import SSL + +from twisted.web.server import Site +from twisted.web.static import File +from twisted.web.resource import Resource +from twisted.internet import reactor + +# See +# http://twistedmatrix.com/documents/current/web/howto/web-in-60/index.htmln +# for more examples + + +class FakeSession(Resource): + def __init__(self, name): + self.name = name + + def render_GET(self, request): + return json.dumps({'errors': None}) + + def render_POST(self, request): + return json.dumps( + {'salt': 'deadbeef', 'B': 'deadbeef', 'errors': None}) + + def render_PUT(self, request): + return json.dumps( + {'M2': 'deadbeef', 'errors': None}) + + +class API_Sessions(Resource): + def getChild(self, name, request): + return FakeSession(name) + + +def get_certs_path(): + script_path = os.path.realpath(os.path.dirname(sys.argv[0])) + certs_path = os.path.join(script_path, 'certs') + return certs_path + + +def get_TLS_credentials(): + # XXX this is giving errors + # XXX REview! We want to use gnutls! + certs_path = get_certs_path() + + cert = crypto.X509Certificate( + open(certs_path + '/leaptestscert.pem').read()) + key = crypto.X509PrivateKey( + open(certs_path + '/leaptestskey.pem').read()) + ca = crypto.X509Certificate( + open(certs_path + '/cacert.pem').read()) + #crl = crypto.X509CRL(open(certs_path + '/crl.pem').read()) + #cred = crypto.X509Credentials(cert, key, [ca], [crl]) + cred = X509Credentials(cert, key, [ca]) + cred.verify_peer = True + cred.session_params.compressions = (COMP_LZO, COMP_DEFLATE, COMP_NULL) + return cred + + +class OpenSSLServerContextFactory: + # XXX workaround for broken TLS interface + # from gnuTLS. + + def getContext(self): + """Create an SSL context. + This is a sample implementation that loads a certificate from a file + called 'server.pem'.""" + certs_path = get_certs_path() + + ctx = SSL.Context(SSL.SSLv23_METHOD) + ctx.use_certificate_file(certs_path + '/leaptestscert.pem') + ctx.use_privatekey_file(certs_path + '/leaptestskey.pem') + return ctx + + +if __name__ == "__main__": + + from twisted.python import log + log.startLogging(sys.stdout) + + root = Resource() + root.putChild("provider.json", File("./provider.json")) + config = Resource() + config.putChild( + "eip-service.json", + File("./eip-service.json")) + apiv1 = Resource() + apiv1.putChild("config", config) + apiv1.putChild("sessions.json", API_Sessions()) + apiv1.putChild("cert", File(get_certs_path() + '/openvpn.pem')) + root.putChild("1", apiv1) + + cred = get_TLS_credentials() + + factory = Site(root) + + # regular http + reactor.listenTCP(8000, factory) + + # TLS with gnutls --- seems broken :( + #reactor.listenTLS(8003, factory, cred) + + # OpenSSL + reactor.listenSSL(8443, factory, OpenSSLServerContextFactory()) + + reactor.run() -- cgit v1.2.3 From 8118056a244ca74d16380ad26a70e3da40e7e401 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 9 Nov 2012 11:21:40 +0900 Subject: connect page merged into regvalidation. Flow nearly working with fake provider, except for authentication. --- src/leap/gui/firstrun/constants.py | 0 src/leap/gui/firstrun/providerinfo.py | 24 +---- src/leap/gui/firstrun/providerselect.py | 10 +- src/leap/gui/firstrun/register.py | 49 ++++++--- src/leap/gui/firstrun/regvalidation.py | 186 +++++++++++++++++++++++--------- 5 files changed, 178 insertions(+), 91 deletions(-) create mode 100644 src/leap/gui/firstrun/constants.py (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/constants.py b/src/leap/gui/firstrun/constants.py new file mode 100644 index 00000000..e69de29b diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index 9b959602..4df477a7 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -2,7 +2,6 @@ Provider Info Page, used in First run Wizard """ import logging -import time from PyQt4 import QtCore from PyQt4 import QtGui @@ -14,29 +13,12 @@ from leap.crypto import certs from leap.eip import exceptions as eipexceptions from leap.gui.progress import ValidationPage +from leap.util.web import get_https_domain_and_port -from leap.gui.constants import APP_LOGO +from leap.gui.constants import APP_LOGO, pause_for_user logger = logging.getLogger(__name__) -GUI_PAUSE_FOR_USER_SECONDS = 1 -pause_for_user = lambda: time.sleep(GUI_PAUSE_FOR_USER_SECONDS) - - -def get_https_domain_and_port(full_domain): - """ - returns a tuple with domain and port - from a full_domain string that can - contain a colon - """ - domain_split = full_domain.split(':') - _len = len(domain_split) - if _len == 1: - domain, port = full_domain, 443 - if _len == 2: - domain, port = domain_split - return domain, port - class ProviderInfoPage(ValidationPage): def __init__(self, parent=None): @@ -127,7 +109,7 @@ class ProviderInfoPage(ValidationPage): domain) except baseexceptions.LeapException as exc: - logger.debug('exception') + logger.error(exc.message) wizard.set_validation_error( prevpage, exc.usermessage) pause_and_finish() diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index c282e3ab..a20f40b3 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -6,9 +6,9 @@ import logging from PyQt4 import QtCore from PyQt4 import QtGui -from leap.base import exceptions as baseexceptions -from leap.crypto import certs -from leap.eip import exceptions as eipexceptions +#from leap.base import exceptions as baseexceptions +#from leap.crypto import certs +#from leap.eip import exceptions as eipexceptions from leap.gui.constants import APP_LOGO from leap.gui.styles import ErrorLabelStyleSheet @@ -30,6 +30,7 @@ class SelectProviderPage(QtGui.QWizardPage): QtGui.QPixmap(APP_LOGO)) self.did_cert_check = False + self.current_page = 'providerselection' providerNameLabel = QtGui.QLabel("h&ttps://") # note that we expect the bare domain name @@ -154,7 +155,8 @@ class SelectProviderPage(QtGui.QWizardPage): # XXX could move this to ValidationMixin #logger.debug('getting errors') - errors = self.wizard().get_validation_error('providerselection') + errors = self.wizard().get_validation_error( + self.current_page) if errors: #logger.debug('errors! -> %s', errors) self.validationMsg.setText(errors) diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index d7e8db0e..0a7ba34b 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -17,23 +17,18 @@ from leap.gui.styles import ErrorLabelStyleSheet class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): - setSigningUpStatus = QtCore.pyqtSignal([]) - def __init__(self, parent=None): super(RegisterUserPage, self).__init__(parent) - # bind wizard page signals - self.setSigningUpStatus.connect( - lambda: self.set_validation_status( - 'validating')) - self.setTitle("Sign Up") self.setPixmap( QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) + self.current_page = "signup" + userNameLabel = QtGui.QLabel("User &name:") userNameLineEdit = QtGui.QLineEdit() userNameLineEdit.cursorPositionChanged.connect( @@ -88,18 +83,28 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): layout.addWidget(rememberPasswordCheckBox, 4, 3, 4, 4) self.setLayout(layout) - # overwritten methods + # pagewizard methods - def initializePage(self): + def populateErrors(self): + # XXX could move this to ValidationMixin + + #logger.debug('getting errors') + errors = self.wizard().get_validation_error( + self.current_page) + if errors: + #logger.debug('errors! -> %s', errors) + self.validationMsg.setText(errors) + + def paintEvent(self, event): """ - inits wizard page + we hook our populate errors + on paintEvent because we need it to catch + when user enters the page coming from next, + and initializePage does not cover that case. + Maybe there's a better event to hook upon. """ - provider = self.field('provider_domain') - self.setSubTitle( - "Register a new user with provider %s." % - provider) - self.validationMsg.setText('') - self.userPassword2LineEdit.setText('') + super(RegisterUserPage, self).paintEvent(event) + self.populateErrors() def validatePage(self): """ @@ -110,7 +115,6 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): and if any errors are thrown there we come back and re-display the validation label. """ - self.setSigningUpStatus.emit() #username = self.userNameLineEdit.text() password = self.userPasswordLineEdit.text() @@ -135,6 +139,17 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): return True + def initializePage(self): + """ + inits wizard page + """ + provider = self.field('provider_domain') + self.setSubTitle( + "Register a new user with provider %s." % + provider) + self.validationMsg.setText('') + self.userPassword2LineEdit.setText('') + def nextId(self): wizard = self.wizard() if not wizard: diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index 6cf150b6..f6d69a60 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -5,16 +5,16 @@ used if First Run Wizard import logging import json import socket -import time from PyQt4 import QtGui import requests from leap.gui.progress import ValidationPage +from leap.util.web import get_https_domain_and_port from leap.base import auth -from leap.gui.constants import APP_LOGO +from leap.gui.constants import APP_LOGO, pause_for_user logger = logging.getLogger(__name__) @@ -22,6 +22,10 @@ logger = logging.getLogger(__name__) class RegisterUserValidationPage(ValidationPage): def __init__(self, parent=None): + # XXX TODO: + # We should check if we come from signup + # or login, and change title / first step + # accordingly. super(RegisterUserValidationPage, self).__init__(parent) self.setTitle("User Creation") @@ -39,25 +43,40 @@ class RegisterUserValidationPage(ValidationPage): we initialize the srp protocol register and try to register user. """ - print 'register user checks' - wizard = self.wizard() - domain = self.field('provider_domain') - username = self.field('userName') - password = self.field('userPassword') + full_domain = self.field('provider_domain') + domain, port = get_https_domain_and_port(full_domain) - # XXX use pause_for_user from providerinfo - update_signal.emit("head_sentinel", 0) - update_signal.emit("registering with provider", 40) - time.sleep(0.5) - update_signal.emit("registering 2", 60) - time.sleep(1) - update_signal.emit("end_sentinel", 100) - time.sleep(0.5) - return + # FIXME #BUG 638 FIXME FIXME FIXME + verify = False # !!!!!!!!!!!!!!!! + # FIXME #BUG 638 FIXME FIXME FIXME + + ########################################### + # Set Credentials. + # username and password are in different fields + # if they were stored in log_in or sign_up pages. + + from_login = self.wizard().from_login + unamek_base = 'userName' + passwk_base = 'userPassword' + unamek = 'login_%s' % unamek_base if from_login else unamek_base + passwk = 'login_%s' % passwk_base if from_login else passwk_base + + username = self.field(unamek) + password = self.field(passwk) + credentials = username, password + + eipconfigchecker = wizard.eipconfigchecker() + pCertChecker = wizard.providercertchecker( + domain=domain) + + ########################################### + # XXX this only should be setup + # if not from_login. if wizard and wizard.debug_server: # We're debugging + # XXX remove this branch? dbgsrv = wizard.debug_server schema = dbgsrv.scheme netloc = dbgsrv.netloc @@ -71,71 +90,140 @@ class RegisterUserValidationPage(ValidationPage): signup = auth.LeapSRPRegister( scheme=schema, provider=provider, - port=port) + port=port, + verify=verify) else: # this is the real thing signup = auth.LeapSRPRegister( - # XXX FIXME FIXME FIXME FIXME - # XXX FIXME 0 Force HTTPS !!! - # XXX FIXME FIXME FIXME FIXME - #schema="https", - schema="http", - provider=domain) + schema="https", + port=port, + provider=domain, + verify=verify) + + update_signal.emit("head_sentinel", 0) + + ################################################## + # 1) register user + ################################################## + # XXX this only should be DONE + # if NOT from_login. + + step = "register" + update_signal.emit("registering with provider", 40) + logger.debug('registering user') + try: - ok, req = signup.register_user(username, password) + ok, req = signup.register_user( + username, password) + except socket.timeout: - self.set_validation_status( + self.set_error( + step, "Error connecting to provider (timeout)") + pause_for_user() return False except requests.exceptions.ConnectionError as exc: - logger.error(exc) - self.set_validation_status( + logger.error(exc.message) + self.set_error( + step, "Error connecting to provider " "(connection error)") + # XXX we should signal a BAD step + pause_for_user() + update_signal.emit("connection error!", 50) + pause_for_user() return False - if ok: - return True - - # something went wrong. - # not registered, let's catch what. - # get timeout - # ... - if req.status_code == 500: - self.set_validation_status( - "Error during registration (500)") - return False + # XXX check for != OK instead??? - if req.status_code == 404: - self.set_validation_status( - "Error during registration (404)") + if req.status_code in (404, 500): + self.set_error( + step, + "Error during registration (%s)" % req.status_code) + pause_for_user() return False validation_msgs = json.loads(req.content) - logger.debug('validation errors: %s' % validation_msgs) errors = validation_msgs.get('errors', None) + logger.debug('validation errors: %s' % validation_msgs) + if errors and errors.get('login', None): # XXX this sometimes catch the blank username # but we're not allowing that (soon) - self.set_validation_status( + self.set_error( + step, 'Username not available.') - else: - self.set_validation_status( - "Error during sign up") - return False + pause_for_user() + return False + + pause_for_user() + + ################################################## + # 2) fetching eip service config + ################################################## + + step = "fetch_eipconf" + fetching_eipconf_msg = "Fetching eip service configuration" + update_signal.emit(fetching_eipconf_msg, 60) + try: + eipconfigchecker.fetch_eip_service_config( + domain=full_domain) + + # XXX get specific exception + except: + self.set_error( + step, + 'Could not download eip config.') + pause_for_user() + return False + pause_for_user() + + ################################################## + # 3) getting client certificate + ################################################## + + step = "fetch_eipcert" + fetching_clientcert_msg = "Fetching eip certificate" + update_signal.emit(fetching_clientcert_msg, 80) + + try: + pCertChecker.download_new_client_cert( + credentials=credentials, + verify=verify) + + except auth.SRPAuthenticationError as exc: + self.set_error( + step, + "Authentication error: %s" % exc.message) + return False + + pause_for_user() + + ################ + # end ! + ################ + + update_signal.emit("end_sentinel", 100) + pause_for_user() def _do_validation(self): """ called after _do_checks has finished (connected to checker thread finished signal) """ + is_signup = self.field("is_signup") + prevpage = "signup" if is_signup else "login" + wizard = self.wizard() if self.errors: print 'going back with errors' + logger.error(self.errors) + name, first_error = self.pop_first_error() wizard.set_validation_error( - 'signup', 'that name is taken') + prevpage, + first_error) self.go_back() else: print 'going next' @@ -145,4 +233,4 @@ class RegisterUserValidationPage(ValidationPage): wizard = self.wizard() if not wizard: return - return wizard.get_page_index('connecting') + return wizard.get_page_index('lastpage') -- cgit v1.2.3 From 8fd77ba036cb78c81939bbfce312b12cdc90d881 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 9 Nov 2012 18:13:32 +0900 Subject: working version of the fake provider. wizard can now be completely tested against this. --- .../firstrun/tests/integration/fake_provider.py | 175 ++++++++++++++++++++- 1 file changed, 167 insertions(+), 8 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/tests/integration/fake_provider.py b/src/leap/gui/firstrun/tests/integration/fake_provider.py index 27886d3b..09c6c468 100755 --- a/src/leap/gui/firstrun/tests/integration/fake_provider.py +++ b/src/leap/gui/firstrun/tests/integration/fake_provider.py @@ -1,8 +1,8 @@ -#/usr/bin/env python +#!/usr/bin/env python """A server faking some of the provider resources and apis, -used for testing Leap Client requests. +used for testing Leap Client requests -Right needs that you create a subfolder named 'certs', +It needs that you create a subfolder named 'certs', and that you place the following files: [ ] certs/leaptestscert.pem @@ -14,10 +14,14 @@ and that you place the following files: [ ] eip-service.json """ +import binascii import json import os import sys +# python SRP LIB (! important MUST be >=1.0.1 !) +import srp + # GnuTLS Example -- is not working as expected from gnutls import crypto from gnutls.constants import COMP_LZO, COMP_DEFLATE, COMP_NULL @@ -27,6 +31,8 @@ from gnutls.interfaces.twisted import X509Credentials # But we DO NOT want to introduce this dependency. from OpenSSL import SSL +from zope.interface import Interface, Attribute, implements + from twisted.web.server import Site from twisted.web.static import File from twisted.web.resource import Resource @@ -36,21 +42,173 @@ from twisted.internet import reactor # http://twistedmatrix.com/documents/current/web/howto/web-in-60/index.htmln # for more examples +""" +Testing the FAKE_API: +##################### + + 1) register an user + >> curl -d "user[login]=me" -d "user[password_salt]=foo" -d "user[password_verifier]=beef" http://localhost:8000/1/users.json + << {"errors": null} + + 2) check that if you try to register again, it will fail: + >> curl -d "user[login]=me" -d "user[password_salt]=foo" -d "user[password_verifier]=beef" http://localhost:8000/1/users.json + << {"errors": {"login": "already taken!"}} + +""" + +# Globals to mock user/sessiondb + +USERDB = {} +SESSIONDB = {} + + +safe_unhexlify = lambda x: binascii.unhexlify(x) \ + if (len(x) % 2 == 0) else binascii.unhexlify('0' + x) + + +class IUser(Interface): + login = Attribute("User login.") + salt = Attribute("Password salt.") + verifier = Attribute("Password verifier.") + session = Attribute("Session.") + svr = Attribute("Server verifier.") + + +class User(object): + implements(IUser) + + def __init__(self, login, salt, verifier): + self.login = login + self.salt = salt + self.verifier = verifier + self.session = None + + def set_server_verifier(self, svr): + self.svr = svr + + def set_session(self, session): + SESSIONDB[session] = self + self.session = session + + +class FakeUsers(Resource): + def __init__(self, name): + self.name = name + + def render_POST(self, request): + args = request.args + + login = args['user[login]'][0] + salt = args['user[password_salt]'][0] + verifier = args['user[password_verifier]'][0] + + if login in USERDB: + return "%s\n" % json.dumps( + {'errors': {'login': 'already taken!'}}) + + print login, verifier, salt + user = User(login, salt, verifier) + USERDB[login] = user + return json.dumps({'errors': None}) + + +def get_user(request): + login = request.args.get('login') + if login: + user = USERDB.get(login[0], None) + if user: + return user + + session = request.getSession() + user = SESSIONDB.get(session, None) + return user + class FakeSession(Resource): def __init__(self, name): self.name = name def render_GET(self, request): - return json.dumps({'errors': None}) + return "%s\n" % json.dumps({'errors': None}) def render_POST(self, request): - return json.dumps( - {'salt': 'deadbeef', 'B': 'deadbeef', 'errors': None}) + + user = get_user(request) + + if not user: + # XXX get real error from demo provider + return json.dumps({'errors': 'no such user'}) + + A = request.args['A'][0] + + _A = safe_unhexlify(A) + _salt = safe_unhexlify(user.salt) + _verifier = safe_unhexlify(user.verifier) + + svr = srp.Verifier( + user.login, + _salt, + _verifier, + _A, + hash_alg=srp.SHA256, + ng_type=srp.NG_1024) + + s, B = svr.get_challenge() + + _B = binascii.hexlify(B) + + print 'login = %s' % user.login + print 'salt = %s' % user.salt + print 'len(_salt) = %s' % len(_salt) + print 'vkey = %s' % user.verifier + print 'len(vkey) = %s' % len(_verifier) + print 's = %s' % binascii.hexlify(s) + print 'B = %s' % _B + print 'len(B) = %s' % len(_B) + + session = request.getSession() + user.set_session(session) + user.set_server_verifier(svr) + + # yep, this is tricky. + # some things are *already* unhexlified. + data = { + 'salt': user.salt, + 'B': _B, + 'errors': None} + + return json.dumps(data) def render_PUT(self, request): + + # XXX check session??? + user = get_user(request) + + if not user: + print 'NO USER' + return json.dumps({'errors': 'no such user'}) + + data = request.content.read() + auth = data.split("client_auth=") + M = auth[1] if len(auth) > 1 else None + # if not H, return + if not M: + return json.dumps({'errors': 'no M proof passed by client'}) + + svr = user.svr + HAMK = svr.verify_session(binascii.unhexlify(M)) + if HAMK is None: + print 'verification failed!!!' + raise Exception("Authentication failed!") + #import ipdb;ipdb.set_trace() + + assert svr.authenticated() + print "***" + print 'server authenticated user SRP!' + print "***" + return json.dumps( - {'M2': 'deadbeef', 'errors': None}) + {'M2': binascii.hexlify(HAMK), 'errors': None}) class API_Sessions(Resource): @@ -113,6 +271,7 @@ if __name__ == "__main__": apiv1 = Resource() apiv1.putChild("config", config) apiv1.putChild("sessions.json", API_Sessions()) + apiv1.putChild("users.json", FakeUsers(None)) apiv1.putChild("cert", File(get_certs_path() + '/openvpn.pem')) root.putChild("1", apiv1) @@ -120,7 +279,7 @@ if __name__ == "__main__": factory = Site(root) - # regular http + # regular http (for debugging with curl) reactor.listenTCP(8000, factory) # TLS with gnutls --- seems broken :( -- cgit v1.2.3 From fc857d25025ea07d46a8c8f5ffd4fb2902a76c13 Mon Sep 17 00:00:00 2001 From: kali Date: Mon, 12 Nov 2012 10:04:09 +0900 Subject: fix cert fetching over https --- src/leap/gui/firstrun/regvalidation.py | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index f6d69a60..7f149ae7 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -68,38 +68,16 @@ class RegisterUserValidationPage(ValidationPage): eipconfigchecker = wizard.eipconfigchecker() pCertChecker = wizard.providercertchecker( - domain=domain) + domain=full_domain) ########################################### # XXX this only should be setup # if not from_login. - if wizard and wizard.debug_server: - # We're debugging - # XXX remove this branch? - dbgsrv = wizard.debug_server - schema = dbgsrv.scheme - netloc = dbgsrv.netloc - port = None - netloc_split = netloc.split(':') - if len(netloc_split) > 1: - provider, port = netloc_split - else: - provider = netloc - - signup = auth.LeapSRPRegister( - scheme=schema, - provider=provider, - port=port, - verify=verify) - - else: - # this is the real thing - signup = auth.LeapSRPRegister( - schema="https", - port=port, - provider=domain, - verify=verify) + signup = auth.LeapSRPRegister( + schema="https", + provider=full_domain, + verify=verify) update_signal.emit("head_sentinel", 0) -- cgit v1.2.3 From 017ed666038adba315155ad7508f8f3b48368b9f Mon Sep 17 00:00:00 2001 From: kali Date: Mon, 12 Nov 2012 10:16:32 +0900 Subject: add signal to start eip conductor after last checks --- src/leap/gui/firstrun/connect.py | 5 ++++ src/leap/gui/firstrun/regvalidation.py | 49 +++++++++++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 3 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/connect.py b/src/leap/gui/firstrun/connect.py index 283e81b2..a0fe021c 100644 --- a/src/leap/gui/firstrun/connect.py +++ b/src/leap/gui/firstrun/connect.py @@ -1,6 +1,11 @@ """ Connecting Page, used in First Run Wizard """ +# XXX FIXME +# DEPRECATED. All functionality moved to regvalidation +# This file should be removed after checking that one is ok. +# XXX + import logging from PyQt4 import QtGui diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index 7f149ae7..e2d6d425 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -1,7 +1,13 @@ """ Provider Setup Validation Page, -used if First Run Wizard +used in First Run Wizard """ +# XXX This page is called regvalidation +# but it's implementing functionality in the former +# connect page. +# We should remame it to connect again, when we integrate +# the login branch of the wizard. + import logging import json import socket @@ -186,6 +192,41 @@ class RegisterUserValidationPage(ValidationPage): update_signal.emit("end_sentinel", 100) pause_for_user() + # here we go! :) + self.run_eip_checks_for_provider_and_connect(domain) + + def run_eip_checks_for_provider_and_connect(self, domain): + wizard = self.wizard() + conductor = wizard.conductor + start_eip_signal = getattr( + wizard, + 'start_eipconnection_signal', None) + + if conductor: + conductor.set_provider_domain(domain) + conductor.run_checks() + self.conductor = conductor + errors = self.eip_error_check() + if not errors and start_eip_signal: + start_eip_signal.emit() + + else: + logger.warning( + "No conductor found. This means that " + "probably the wizard has been launched " + "in an stand-alone way.") + + def eip_error_check(self): + """ + a version of the main app error checker, + but integrated within the connecting page of the wizard. + consumes the conductor error queue. + pops errors, and add those to the wizard page + """ + logger.debug('eip error check from connecting page') + errq = self.conductor.error_queue + # XXX missing! + def _do_validation(self): """ called after _do_checks has finished @@ -196,7 +237,7 @@ class RegisterUserValidationPage(ValidationPage): wizard = self.wizard() if self.errors: - print 'going back with errors' + logger.debug('going back with errors') logger.error(self.errors) name, first_error = self.pop_first_error() wizard.set_validation_error( @@ -204,7 +245,9 @@ class RegisterUserValidationPage(ValidationPage): first_error) self.go_back() else: - print 'going next' + logger.debug('going next') + # check if this "next" interferes + # with the eip signal. self.go_next() def nextId(self): -- cgit v1.2.3 From 23c3aa67e3f109eb7d75a89caa34b90144f99efa Mon Sep 17 00:00:00 2001 From: kali Date: Mon, 12 Nov 2012 11:48:39 +0900 Subject: fix layout on providerinfo page --- src/leap/gui/firstrun/providerinfo.py | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index 4df477a7..0c557d66 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -9,7 +9,7 @@ from PyQt4 import QtGui import requests from leap.base import exceptions as baseexceptions -from leap.crypto import certs +#from leap.crypto import certs from leap.eip import exceptions as eipexceptions from leap.gui.progress import ValidationPage @@ -32,26 +32,36 @@ class ProviderInfoPage(ValidationPage): QtGui.QPixmap(APP_LOGO)) def create_info_panel(self): + # Use stacked widget instead + # of reparenting the layout. + + self.infoWidget = QtGui.QStackedWidget() + + info = QtGui.QWidget() + layout = QtGui.QVBoxLayout() + displayName = QtGui.QLabel("") description = QtGui.QLabel("") enrollment_policy = QtGui.QLabel("") # XXX set stylesheet... # prettify a little bit. # bigger fonts and so on... - self.displayName = displayName - self.description = description - self.enrollment_policy = enrollment_policy - # this trick allows us to reparent - QtCore.QObjectCleanupHandler().add(self.layout) - layout = QtGui.QGridLayout() + layout.addWidget(displayName) + layout.addWidget(description) + layout.addWidget(enrollment_policy) + layout.addStretch(1) + + info.setLayout(layout) + self.infoWidget.addWidget(info) - layout.addWidget(displayName, 0, 1) - layout.addWidget(description, 1, 1) - layout.addWidget(enrollment_policy, 2, 1) + self.layout.addWidget(self.infoWidget) - self.setLayout(layout) - self.update() + # add refs to self to allow for + # updates. + self.displayName = displayName + self.description = description + self.enrollment_policy = enrollment_policy def show_provider_info(self): -- cgit v1.2.3 From fe16e62fa83c24d2ef379a3f9e102d336e527656 Mon Sep 17 00:00:00 2001 From: kali Date: Mon, 12 Nov 2012 12:25:11 +0900 Subject: cleanup errors on page init and on field change --- src/leap/gui/firstrun/providerinfo.py | 3 +++ src/leap/gui/firstrun/providerselect.py | 18 ++++++++++++++++-- src/leap/gui/firstrun/register.py | 18 +++++++++++++++--- 3 files changed, 34 insertions(+), 5 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index 0c557d66..ef3b32c1 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -31,6 +31,9 @@ class ProviderInfoPage(ValidationPage): QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) + self.prev_page = "providerselection" + #self.current_page = "providerinfo" + def create_info_panel(self): # Use stacked widget instead # of reparenting the layout. diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index a20f40b3..3fb76557 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -153,13 +153,27 @@ class SelectProviderPage(QtGui.QWizardPage): def populateErrors(self): # XXX could move this to ValidationMixin + # with some defaults for the validating fields + # (now it only allows one field, manually specified) #logger.debug('getting errors') errors = self.wizard().get_validation_error( self.current_page) if errors: - #logger.debug('errors! -> %s', errors) - self.validationMsg.setText(errors) + bad_str = getattr(self, 'bad_string', None) + cur_str = self.providerNameEdit.text() + showerr = self.validationMsg.setText + if bad_str is None: + # first time we fall here. + # save the current bad_string value + self.bad_string = cur_str + showerr(errors) + else: + # not the first time + if cur_str == bad_str: + showerr(errors) + else: + showerr('') def paintEvent(self, event): """ diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index 0a7ba34b..6d15c156 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -87,13 +87,25 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): def populateErrors(self): # XXX could move this to ValidationMixin + # used in providerselect too - #logger.debug('getting errors') errors = self.wizard().get_validation_error( self.current_page) if errors: - #logger.debug('errors! -> %s', errors) - self.validationMsg.setText(errors) + bad_str = getattr(self, 'bad_string', None) + cur_str = self.userNameLineEdit.text() + showerr = self.validationMsg.setText + if bad_str is None: + # first time we fall here. + # save the current bad_string value + self.bad_string = cur_str + showerr(errors) + else: + # not the first time + if cur_str == bad_str: + showerr(errors) + else: + showerr('') def paintEvent(self, event): """ -- cgit v1.2.3 From 42ba228eecb5726506848bd08758bd1f925905cc Mon Sep 17 00:00:00 2001 From: kali Date: Mon, 12 Nov 2012 12:45:37 +0900 Subject: fix prevalidation error showing in register page. --- src/leap/gui/firstrun/providerselect.py | 14 ++++++++++++++ src/leap/gui/firstrun/register.py | 27 +++++++++++++++++++++++---- src/leap/gui/firstrun/regvalidation.py | 1 + 3 files changed, 38 insertions(+), 4 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index 3fb76557..8d1aa869 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -175,6 +175,13 @@ class SelectProviderPage(QtGui.QWizardPage): else: showerr('') + def cleanup_errormsg(self): + """ + we reset bad_string to None + should be called before leaving the page + """ + self.bad_string = None + def paintEvent(self, event): """ we hook our populate errors @@ -190,6 +197,13 @@ class SelectProviderPage(QtGui.QWizardPage): self.validationMsg.setText('') self.certinfoGroup.hide() + def validatePage(self): + # some cleanup before we leave the page + self.cleanup_errormsg() + + # go + return True + def nextId(self): wizard = self.wizard() if not wizard: diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index 6d15c156..b46dd4cd 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -95,18 +95,30 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): bad_str = getattr(self, 'bad_string', None) cur_str = self.userNameLineEdit.text() showerr = self.validationMsg.setText + prev_er = getattr(self, 'prevalidation_error', None) + if bad_str is None: # first time we fall here. # save the current bad_string value self.bad_string = cur_str showerr(errors) else: + if prev_er: + showerr(prev_er) + return # not the first time if cur_str == bad_str: showerr(errors) else: showerr('') + def cleanup_errormsg(self): + """ + we reset bad_string to None + should be called before leaving the page + """ + self.bad_string = None + def paintEvent(self, event): """ we hook our populate errors @@ -118,6 +130,9 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): super(RegisterUserPage, self).paintEvent(event) self.populateErrors() + def set_prevalidation_error(self, error): + self.prevalidation_error = error + def validatePage(self): """ we only pre-validate here password weakness @@ -137,18 +152,22 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): # to assess strenght and avoid silly stuff. if password != password2: - self.set_validation_status('Password does not match.') + self.set_prevalidation_error('Password does not match.') return False if len(password) < 6: - self.set_validation_status('Password too short.') + self.set_prevalidation_error('Password too short.') return False if password == "123456": - # joking - self.set_validation_status('Password too obvious.') + # joking, but not too much. + self.set_prevalidation_error('Password too obvious.') return False + # some cleanup before we leave the page + self.cleanup_errormsg() + + # go return True def initializePage(self): diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index e2d6d425..b1308051 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -94,6 +94,7 @@ class RegisterUserValidationPage(ValidationPage): # if NOT from_login. step = "register" + update_signal.emit("checking availability", 20) update_signal.emit("registering with provider", 40) logger.debug('registering user') -- cgit v1.2.3 From 6dac344ee1826f9413a40c7783517bc640f826ca Mon Sep 17 00:00:00 2001 From: kali Date: Mon, 12 Nov 2012 22:09:05 +0900 Subject: uncomment download_ca_cert call --- src/leap/gui/firstrun/providersetup.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index 2609629a..a1710a3a 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -7,7 +7,7 @@ from PyQt4 import QtGui from leap.gui.progress import ValidationPage -from leap.gui.constants import APP_LOGO +from leap.gui.constants import APP_LOGO, pause_for_user class ProviderSetupValidationPage(ValidationPage): @@ -25,7 +25,6 @@ class ProviderSetupValidationPage(ValidationPage): """ executes actual checks in a separate thread """ - import time domain = self.field('provider_domain') wizard = self.wizard() pconfig = wizard.providerconfig @@ -33,7 +32,9 @@ class ProviderSetupValidationPage(ValidationPage): pCertChecker = wizard.providercertchecker certchecker = pCertChecker(domain=domain) + update_signal.emit('head_sentinel', 0) update_signal.emit('Fetching CA certificate', 30) + pause_for_user() if pconfig: ca_cert_uri = pconfig.get('ca_cert_uri').geturl() @@ -47,11 +48,10 @@ class ProviderSetupValidationPage(ValidationPage): # (Check with the trusted fingerprints dict # or something smart) - #certchecker.download_ca_cert( - #uri=ca_cert_uri, - #verify=False) - - time.sleep(2) + certchecker.download_ca_cert( + uri=ca_cert_uri, + verify=False) + pause_for_user() update_signal.emit('Checking CA fingerprint', 66) #ca_cert_fingerprint = pconfig.get('ca_cert_fingerprint', None) @@ -61,7 +61,6 @@ class ProviderSetupValidationPage(ValidationPage): #validate_fpr = certchecker.check_ca_cert_fingerprint( #fingerprint=sha256_fpr) - time.sleep(0.5) #if not validate_fpr: # XXX update validationMsg # should catch exception @@ -85,11 +84,11 @@ class ProviderSetupValidationPage(ValidationPage): # XXX update validationMsg # should catch exception #return False - time.sleep(0.5) + pause_for_user() #ca_cert_path = checker.ca_cert_path update_signal.emit('end_sentinel', 100) - time.sleep(1) + pause_for_user() def _do_validation(self): """ -- cgit v1.2.3 From 72f3ef94f0d7deffa9adfba6bde57ae3d9c8d165 Mon Sep 17 00:00:00 2001 From: kali Date: Mon, 12 Nov 2012 23:03:12 +0900 Subject: connect wizard cancel button with shutdown --- src/leap/gui/firstrun/wizard.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/wizard.py b/src/leap/gui/firstrun/wizard.py index 7a3d6973..bbb48149 100755 --- a/src/leap/gui/firstrun/wizard.py +++ b/src/leap/gui/firstrun/wizard.py @@ -61,7 +61,8 @@ class FirstRunWizard(QtGui.QWizard): eipconfigchecker=eipchecks.EIPConfigChecker, start_eipconnection_signal=None, eip_statuschange_signal=None, - debug_server=None): + debug_server=None, + quitcallback=None): super(FirstRunWizard, self).__init__( parent, QtCore.Qt.WindowStaysOnTopHint) @@ -97,6 +98,11 @@ class FirstRunWizard(QtGui.QWizard): self.start_eipconnection_signal = start_eipconnection_signal self.eip_statuschange_signal = eip_statuschange_signal + if quitcallback is not None: + self.button( + QtGui.QWizard.CancelButton).clicked.connect( + quitcallback) + self.providerconfig = None # previously registered # if True, jumps to LogIn page. -- cgit v1.2.3 From 971c5e2217d17f4dab68336c9d8f562ca63fc84b Mon Sep 17 00:00:00 2001 From: kali Date: Tue, 13 Nov 2012 00:14:53 +0900 Subject: check credentials on login branch plus fix repaint on populateErrors on login page, should refactor to ToBeValidated class or something similar, with the other paintEvent functions that implement the painting of errors coming from the "next" validating page. --- src/leap/gui/firstrun/login.py | 118 +++++++++++++++++++------- src/leap/gui/firstrun/providersetup.py | 75 ++++++++++++++--- src/leap/gui/firstrun/regvalidation.py | 150 +++++++++++++++++---------------- 3 files changed, 230 insertions(+), 113 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/login.py b/src/leap/gui/firstrun/login.py index ae4b23c6..4271c774 100644 --- a/src/leap/gui/firstrun/login.py +++ b/src/leap/gui/firstrun/login.py @@ -4,7 +4,7 @@ LogIn Page, used inf First Run Wizard from PyQt4 import QtCore from PyQt4 import QtGui -import requests +#import requests from leap.gui.firstrun.mixins import UserFormMixIn @@ -18,6 +18,7 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): self.setTitle("Log In") self.setSubTitle("Log in with your credentials.") + self.current_page = "login" self.setPixmap( QtGui.QWizard.LogoPixmap, @@ -68,30 +69,89 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): # pagewizard methods + #### begin possible refactor + + def populateErrors(self): + # XXX could move this to ValidationMixin + # used in providerselect and register too + + errors = self.wizard().get_validation_error( + self.current_page) + prev_er = getattr(self, 'prevalidation_error', None) + showerr = self.validationMsg.setText + + if not errors and prev_er: + showerr(prev_er) + return + + if errors: + bad_str = getattr(self, 'bad_string', None) + cur_str = self.userNameLineEdit.text() + + if bad_str is None: + # first time we fall here. + # save the current bad_string value + self.bad_string = cur_str + showerr(errors) + else: + if prev_er: + showerr(prev_er) + return + # not the first time + if cur_str == bad_str: + showerr(errors) + else: + showerr('') + + def cleanup_errormsg(self): + """ + we reset bad_string to None + should be called before leaving the page + """ + self.bad_string = None + + def paintEvent(self, event): + """ + we hook our populate errors + on paintEvent because we need it to catch + when user enters the page coming from next, + and initializePage does not cover that case. + Maybe there's a better event to hook upon. + """ + super(LogInPage, self).paintEvent(event) + self.populateErrors() + + def set_prevalidation_error(self, error): + self.prevalidation_error = error + + #### end possible refactor + def nextId(self): wizard = self.wizard() if not wizard: return - if wizard.is_provider_setup is True: - next_ = 'connecting' if wizard.is_provider_setup is False: - next_ = 'providersetup' + next_ = 'providersetupvalidation' + if wizard.is_provider_setup is True: + # XXX bad name, ok, gonna change that + next_ = 'signupvalidation' return wizard.get_page_index(next_) def initializePage(self): + super(LogInPage, self).initializePage() self.userNameLineEdit.setText('username@provider.example.org') self.userNameLineEdit.cursorPositionChanged.connect( self.onUserNameEdit) self.initial_username_sample = True def validatePage(self): - wizard = self.wizard() - eipconfigchecker = wizard.eipconfigchecker() + #wizard = self.wizard() + #eipconfigchecker = wizard.eipconfigchecker() full_username = self.userNameLineEdit.text() password = self.userPasswordLineEdit.text() if full_username.count('@') != 1: - self.set_validation_status( + self.set_prevalidation_error( "Username must be in the username@provider form.") return False @@ -100,33 +160,33 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): self.setField('login_userName', username) self.setField('login_userPassword', password) + #################################################### + # Validation logic: + # move to provider setup page + #################################################### # Able to contact domain? # can get definition? # two-by-one - try: - eipconfigchecker.fetch_definition(domain=domain) - + #try: + #eipconfigchecker.fetch_definition(domain=domain) +# # we're using requests here for all # the possible error cases that it catches. - except requests.exceptions.ConnectionError as exc: - self.set_validation_status(exc.message[1]) - return False - except requests.exceptions.HTTPError as exc: - self.set_validation_status(exc.message) - return False - wizard.set_providerconfig( - eipconfigchecker.defaultprovider.config) - - # XXX validate user? or we leave that for later? - # I think the best thing to do for that is - # continue to provider setup page, and if - # we catch authentication error there, redirect - # again to this page (by clicking "next" to - # come here). - # Rationale is that we need to verify server certs - # and so on. - - # mark that we came from login page. + #except requests.exceptions.ConnectionError as exc: + #self.set_validation_status(exc.message[1]) + #return False + #except requests.exceptions.HTTPError as exc: + #self.set_validation_status(exc.message) + #return False + #wizard.set_providerconfig( + #eipconfigchecker.defaultprovider.config) + #################################################### + + # XXX I think this is not needed + # since we're also checking for the is_signup field. self.wizard().from_login = True + # some cleanup before we leave the page + self.cleanup_errormsg() + return True diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index a1710a3a..3fb9a19b 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -2,17 +2,24 @@ Provider Setup Validation Page, used if First Run Wizard """ +import logging from PyQt4 import QtGui +from leap.base import auth from leap.gui.progress import ValidationPage from leap.gui.constants import APP_LOGO, pause_for_user +logger = logging.getLogger(__name__) + class ProviderSetupValidationPage(ValidationPage): def __init__(self, parent=None): super(ProviderSetupValidationPage, self).__init__(parent) + is_signup = self.field("is_signup") + self.is_signup = is_signup + self.setTitle("Setting up provider") #self.setSubTitle( #"auto configuring provider...") @@ -25,14 +32,56 @@ class ProviderSetupValidationPage(ValidationPage): """ executes actual checks in a separate thread """ - domain = self.field('provider_domain') + full_domain = self.field('provider_domain') wizard = self.wizard() pconfig = wizard.providerconfig - pCertChecker = wizard.providercertchecker - certchecker = pCertChecker(domain=domain) + #pCertChecker = wizard.providercertchecker + #certchecker = pCertChecker(domain=full_domain) + pCertChecker = wizard.providercertchecker( + domain=full_domain) update_signal.emit('head_sentinel', 0) + + ###################################### + if not self.is_signup: + # We come from login page. + # We try a call to an authenticated + # page here as a mean to catch + # srp authentication errors while + # we are still at one page's reach + # of the login credentials input page. + # (so we're able to go back an correct) + + step = "fetch_eipcert" + update_signal.emit('validating credentials', 20) + + unamek = 'login_userName' + passwk = 'login_userPassword' + + username = self.field(unamek) + password = self.field(passwk) + credentials = username, password + + ################# + # FIXME #BUG #638 + verify = False + + try: + pCertChecker.download_new_client_cert( + credentials=credentials, + verify=verify) + + except auth.SRPAuthenticationError as exc: + self.set_error( + step, + "Authentication error: %s" % exc.message) + return False + + pause_for_user() + + ####################################### + update_signal.emit('Fetching CA certificate', 30) pause_for_user() @@ -48,7 +97,7 @@ class ProviderSetupValidationPage(ValidationPage): # (Check with the trusted fingerprints dict # or something smart) - certchecker.download_ca_cert( + pCertChecker.download_ca_cert( uri=ca_cert_uri, verify=False) pause_for_user() @@ -59,7 +108,7 @@ class ProviderSetupValidationPage(ValidationPage): # XXX get fingerprint dict (types) #sha256_fpr = ca_cert_fingerprint.split('=')[1] - #validate_fpr = certchecker.check_ca_cert_fingerprint( + #validate_fpr = pCertChecker.check_ca_cert_fingerprint( #fingerprint=sha256_fpr) #if not validate_fpr: # XXX update validationMsg @@ -70,7 +119,7 @@ class ProviderSetupValidationPage(ValidationPage): #api_uri = pconfig.get('api_uri', None) #try: - #api_cert_verified = certchecker.verify_api_https(api_uri) + #api_cert_verified = pCertChecker.verify_api_https(api_uri) #except requests.exceptions.SSLError as exc: #logger.error('BUG #638. %s' % exc.message) # XXX RAISE! See #638 @@ -95,15 +144,18 @@ class ProviderSetupValidationPage(ValidationPage): called after _do_checks has finished (connected to checker thread finished signal) """ + prevpage = "providerselection" if self.is_signup else "login" wizard = self.wizard() + if self.errors: - print 'going back with errors' + logger.debug('going back with errors') + name, first_error = self.pop_first_error() wizard.set_validation_error( - 'providerselection', - 'error on provider setup') + prevpage, + first_error) self.go_back() else: - print 'going next' + logger.debug('going next') self.go_next() def nextId(self): @@ -114,5 +166,6 @@ class ProviderSetupValidationPage(ValidationPage): if is_signup is True: next_ = 'signup' if is_signup is False: - next_ = 'connecting' + # XXX bad name. change to connect again. + next_ = 'signupvalidation' return wizard.get_page_index(next_) diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index b1308051..e85c2ac6 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -28,15 +28,20 @@ logger = logging.getLogger(__name__) class RegisterUserValidationPage(ValidationPage): def __init__(self, parent=None): - # XXX TODO: - # We should check if we come from signup - # or login, and change title / first step - # accordingly. - super(RegisterUserValidationPage, self).__init__(parent) - self.setTitle("User Creation") - self.setSubTitle( - "Registering account with provider.") + is_signup = self.field("is_signup") + self.is_signup = is_signup + + if is_signup: + title = "User Creation" + subtitle = "Registering account with provider." + else: + title = "Connecting..." + # XXX uh... really? + subtitle = "Checking connection with provider." + + self.setTitle(title) + self.setSubTitle(subtitle) self.setPixmap( QtGui.QWizard.LogoPixmap, @@ -61,12 +66,12 @@ class RegisterUserValidationPage(ValidationPage): # Set Credentials. # username and password are in different fields # if they were stored in log_in or sign_up pages. + is_signup = self.is_signup - from_login = self.wizard().from_login unamek_base = 'userName' passwk_base = 'userPassword' - unamek = 'login_%s' % unamek_base if from_login else unamek_base - passwk = 'login_%s' % passwk_base if from_login else passwk_base + unamek = 'login_%s' % unamek_base if not is_signup else unamek_base + passwk = 'login_%s' % passwk_base if not is_signup else passwk_base username = self.field(unamek) password = self.field(passwk) @@ -77,73 +82,73 @@ class RegisterUserValidationPage(ValidationPage): domain=full_domain) ########################################### - # XXX this only should be setup - # if not from_login. - - signup = auth.LeapSRPRegister( - schema="https", - provider=full_domain, - verify=verify) + # only if from signup + if is_signup: + signup = auth.LeapSRPRegister( + schema="https", + provider=full_domain, + verify=verify) update_signal.emit("head_sentinel", 0) ################################################## # 1) register user ################################################## - # XXX this only should be DONE - # if NOT from_login. - - step = "register" - update_signal.emit("checking availability", 20) - update_signal.emit("registering with provider", 40) - logger.debug('registering user') - - try: - ok, req = signup.register_user( - username, password) + # only if from signup. + + if is_signup: + + step = "register" + update_signal.emit("checking availability", 20) + update_signal.emit("registering with provider", 40) + logger.debug('registering user') + + try: + ok, req = signup.register_user( + username, password) + + except socket.timeout: + self.set_error( + step, + "Error connecting to provider (timeout)") + pause_for_user() + return False + + except requests.exceptions.ConnectionError as exc: + logger.error(exc.message) + self.set_error( + step, + "Error connecting to provider " + "(connection error)") + # XXX we should signal a BAD step + pause_for_user() + update_signal.emit("connection error!", 50) + pause_for_user() + return False + + # XXX check for != OK instead??? + + if req.status_code in (404, 500): + self.set_error( + step, + "Error during registration (%s)" % req.status_code) + pause_for_user() + return False + + validation_msgs = json.loads(req.content) + errors = validation_msgs.get('errors', None) + logger.debug('validation errors: %s' % validation_msgs) + + if errors and errors.get('login', None): + # XXX this sometimes catch the blank username + # but we're not allowing that (soon) + self.set_error( + step, + 'Username not available.') + pause_for_user() + return False - except socket.timeout: - self.set_error( - step, - "Error connecting to provider (timeout)") pause_for_user() - return False - - except requests.exceptions.ConnectionError as exc: - logger.error(exc.message) - self.set_error( - step, - "Error connecting to provider " - "(connection error)") - # XXX we should signal a BAD step - pause_for_user() - update_signal.emit("connection error!", 50) - pause_for_user() - return False - - # XXX check for != OK instead??? - - if req.status_code in (404, 500): - self.set_error( - step, - "Error during registration (%s)" % req.status_code) - pause_for_user() - return False - - validation_msgs = json.loads(req.content) - errors = validation_msgs.get('errors', None) - logger.debug('validation errors: %s' % validation_msgs) - - if errors and errors.get('login', None): - # XXX this sometimes catch the blank username - # but we're not allowing that (soon) - self.set_error( - step, - 'Username not available.') - pause_for_user() - return False - - pause_for_user() ################################################## # 2) fetching eip service config @@ -168,7 +173,7 @@ class RegisterUserValidationPage(ValidationPage): ################################################## # 3) getting client certificate ################################################## - + # XXX maybe only do this if we come from signup step = "fetch_eipcert" fetching_clientcert_msg = "Fetching eip certificate" update_signal.emit(fetching_clientcert_msg, 80) @@ -233,8 +238,7 @@ class RegisterUserValidationPage(ValidationPage): called after _do_checks has finished (connected to checker thread finished signal) """ - is_signup = self.field("is_signup") - prevpage = "signup" if is_signup else "login" + prevpage = "signup" if self.is_signup else "login" wizard = self.wizard() if self.errors: -- cgit v1.2.3 From d2dcf5a1060d60c451570349a6a06ad102d6924c Mon Sep 17 00:00:00 2001 From: kali Date: Tue, 13 Nov 2012 21:54:04 +0900 Subject: fix missing provider parameter in leapconfig objects chain --- src/leap/gui/firstrun/last.py | 1 + src/leap/gui/firstrun/providerinfo.py | 9 ++++++--- src/leap/gui/firstrun/regvalidation.py | 9 +++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/last.py b/src/leap/gui/firstrun/last.py index 6f9abbb5..13b2f548 100644 --- a/src/leap/gui/firstrun/last.py +++ b/src/leap/gui/firstrun/last.py @@ -28,6 +28,7 @@ class LastPage(QtGui.QWizardPage): self.label = QtGui.QLabel() self.label.setWordWrap(True) + # XXX REFACTOR to a Validating Page... self.status_line_1 = QtGui.QLabel() self.status_line_2 = QtGui.QLabel() self.status_line_3 = QtGui.QLabel() diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index ef3b32c1..e642fcd0 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -99,9 +99,6 @@ class ProviderInfoPage(ValidationPage): wizard = self.wizard() prevpage = "providerselection" - netchecker = wizard.netchecker() - providercertchecker = wizard.providercertchecker() - eipconfigchecker = wizard.eipconfigchecker() full_domain = self.field('provider_domain') @@ -109,6 +106,10 @@ class ProviderInfoPage(ValidationPage): domain, port = get_https_domain_and_port(full_domain) _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain) + netchecker = wizard.netchecker() + providercertchecker = wizard.providercertchecker() + eipconfigchecker = wizard.eipconfigchecker(domain=_domain) + update_signal.emit("head_sentinel", 0) pause_for_user() @@ -178,6 +179,8 @@ class ProviderInfoPage(ValidationPage): update_signal.emit("Downloading provider info", 70) try: + # XXX we already set _domain in the initialization + # so it should not be needed here. eipconfigchecker.fetch_definition(domain=_domain) wizard.set_providerconfig( eipconfigchecker.defaultprovider.config) diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index e85c2ac6..6681b953 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -57,6 +57,7 @@ class RegisterUserValidationPage(ValidationPage): wizard = self.wizard() full_domain = self.field('provider_domain') domain, port = get_https_domain_and_port(full_domain) + _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain) # FIXME #BUG 638 FIXME FIXME FIXME verify = False # !!!!!!!!!!!!!!!! @@ -77,7 +78,8 @@ class RegisterUserValidationPage(ValidationPage): password = self.field(passwk) credentials = username, password - eipconfigchecker = wizard.eipconfigchecker() + eipconfigchecker = wizard.eipconfigchecker(domain=_domain) + #XXX change for _domain (sanitized) pCertChecker = wizard.providercertchecker( domain=full_domain) @@ -174,6 +176,7 @@ class RegisterUserValidationPage(ValidationPage): # 3) getting client certificate ################################################## # XXX maybe only do this if we come from signup + step = "fetch_eipcert" fetching_clientcert_msg = "Fetching eip certificate" update_signal.emit(fetching_clientcert_msg, 80) @@ -199,7 +202,7 @@ class RegisterUserValidationPage(ValidationPage): pause_for_user() # here we go! :) - self.run_eip_checks_for_provider_and_connect(domain) + self.run_eip_checks_for_provider_and_connect(_domain) def run_eip_checks_for_provider_and_connect(self, domain): wizard = self.wizard() @@ -208,6 +211,8 @@ class RegisterUserValidationPage(ValidationPage): wizard, 'start_eipconnection_signal', None) + import pdb4qt; pdb4qt.set_trace() + if conductor: conductor.set_provider_domain(domain) conductor.run_checks() -- cgit v1.2.3 From d24c7328fa845737dbb83d512e4b3f287634c4cc Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 14 Nov 2012 00:33:05 +0900 Subject: make tests pass + pep8 They were breaking mainly because I did not bother to have a pass over them to change the PROVIDER settings from the branding case. All good now, although much testing is yet needed and some refactor could be used. long live green tests! --- src/leap/gui/firstrun/__init__.py | 9 ++++++--- src/leap/gui/firstrun/regvalidation.py | 2 -- src/leap/gui/firstrun/tests/integration/fake_provider.py | 10 +++++++--- 3 files changed, 13 insertions(+), 8 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/__init__.py b/src/leap/gui/firstrun/__init__.py index 477e7269..8a70d90e 100644 --- a/src/leap/gui/firstrun/__init__.py +++ b/src/leap/gui/firstrun/__init__.py @@ -1,6 +1,9 @@ -import sip -sip.setapi('QString', 2) -sip.setapi('QVariant', 2) +try: + import sip + sip.setapi('QString', 2) + sip.setapi('QVariant', 2) +except ValueError: + pass import connect import intro diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index 6681b953..dbe30d3c 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -211,8 +211,6 @@ class RegisterUserValidationPage(ValidationPage): wizard, 'start_eipconnection_signal', None) - import pdb4qt; pdb4qt.set_trace() - if conductor: conductor.set_provider_domain(domain) conductor.run_checks() diff --git a/src/leap/gui/firstrun/tests/integration/fake_provider.py b/src/leap/gui/firstrun/tests/integration/fake_provider.py index 09c6c468..33ee0ee6 100755 --- a/src/leap/gui/firstrun/tests/integration/fake_provider.py +++ b/src/leap/gui/firstrun/tests/integration/fake_provider.py @@ -12,8 +12,10 @@ and that you place the following files: [ ] provider.json [ ] eip-service.json - """ +# XXX NOTE: intended for manual debug. +# I intend to include this as a regular test after 0.2.0 release +# (so we can add twisted as a dep there) import binascii import json import os @@ -47,11 +49,13 @@ Testing the FAKE_API: ##################### 1) register an user - >> curl -d "user[login]=me" -d "user[password_salt]=foo" -d "user[password_verifier]=beef" http://localhost:8000/1/users.json + >> curl -d "user[login]=me" -d "user[password_salt]=foo" \ + -d "user[password_verifier]=beef" http://localhost:8000/1/users.json << {"errors": null} 2) check that if you try to register again, it will fail: - >> curl -d "user[login]=me" -d "user[password_salt]=foo" -d "user[password_verifier]=beef" http://localhost:8000/1/users.json + >> curl -d "user[login]=me" -d "user[password_salt]=foo" \ + -d "user[password_verifier]=beef" http://localhost:8000/1/users.json << {"errors": {"login": "already taken!"}} """ -- cgit v1.2.3 From 4153bee65d2541b99d4e41aaaf2fd6b2b71b2cc3 Mon Sep 17 00:00:00 2001 From: kali Date: Mon, 19 Nov 2012 23:15:36 +0900 Subject: disable "next" button during validation and wait for user to click it. Closes #973 --- src/leap/gui/firstrun/providerinfo.py | 48 +++++++++++++++++++++++----- src/leap/gui/firstrun/providersetup.py | 19 ++++++----- src/leap/gui/firstrun/register.py | 1 + src/leap/gui/firstrun/regvalidation.py | 58 ++++++++++++++++++++-------------- src/leap/gui/firstrun/wizard.py | 3 ++ 5 files changed, 89 insertions(+), 40 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index e642fcd0..8a3243fc 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -32,6 +32,7 @@ class ProviderInfoPage(ValidationPage): QtGui.QPixmap(APP_LOGO)) self.prev_page = "providerselection" + self.infoWidget = None #self.current_page = "providerinfo" def create_info_panel(self): @@ -62,6 +63,8 @@ class ProviderInfoPage(ValidationPage): # add refs to self to allow for # updates. + # Watch out! Have to get rid of these references! + # this should be better handled with signals !! self.displayName = displayName self.description = description self.enrollment_policy = enrollment_policy @@ -93,8 +96,11 @@ class ProviderInfoPage(ValidationPage): """ executes actual checks in a separate thread """ + finish = lambda: update_signal.emit("end_sentinel", 100) + def pause_and_finish(): - update_signal.emit("end_sentinel", 100) + # only for local debug + finish() pause_for_user() wizard = self.wizard() @@ -164,13 +170,13 @@ class ProviderInfoPage(ValidationPage): #self.did_cert_check = True #self.completeChanged.emit() #return False - pause_and_finish() + finish() return False except baseexceptions.LeapException as exc: wizard.set_validation_error( prevpage, exc.usermessage) - pause_and_finish() + finish() return False ################################## @@ -190,19 +196,20 @@ class ProviderInfoPage(ValidationPage): wizard.set_validation_error( prevpage, "Could not get info from provider.") - pause_and_finish() + finish() return False except requests.exceptions.ConnectionError: wizard.set_validation_error( prevpage, "Could not download provider info " "(refused conn.).") - pause_and_finish() + finish() return False # XXX catch more errors... # We're done! - pause_and_finish() + self.set_done() + finish() def _do_validation(self): """ @@ -214,8 +221,7 @@ class ProviderInfoPage(ValidationPage): errors = self.wizard().get_validation_error(prevpage) if not errors: - self.progress.hide() - self.stepsTableWidget.hide() + self.hide_progress() self.create_info_panel() self.show_provider_info() @@ -228,3 +234,29 @@ class ProviderInfoPage(ValidationPage): wizard = self.wizard() next_ = "providersetupvalidation" return wizard.get_page_index(next_) + + #def isComplete(self): + #return self.is_done() + + def initializePage(self): + logger.error('INITIALIZE PAGE --------------') + logger.error('**') + logger.error('**') + super(ProviderInfoPage, self).initializePage() + self.show_progress() + self.set_undone() + self.completeChanged.emit() + + def cleanupPage(self): + logger.error('CLEANUP PAGE --------------') + + del self.wizard().providerconfig + + if self.infoWidget: + QtCore.QObjectCleanupHandler().add( + self.infoWidget) + + # refactor this into some kind of destructor + del self.displayName + del self.description + del self.enrollment_policy diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index 3fb9a19b..5b50db87 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -78,12 +78,12 @@ class ProviderSetupValidationPage(ValidationPage): "Authentication error: %s" % exc.message) return False - pause_for_user() + #pause_for_user() ####################################### update_signal.emit('Fetching CA certificate', 30) - pause_for_user() + #pause_for_user() if pconfig: ca_cert_uri = pconfig.get('ca_cert_uri').geturl() @@ -100,7 +100,7 @@ class ProviderSetupValidationPage(ValidationPage): pCertChecker.download_ca_cert( uri=ca_cert_uri, verify=False) - pause_for_user() + #pause_for_user() update_signal.emit('Checking CA fingerprint', 66) #ca_cert_fingerprint = pconfig.get('ca_cert_fingerprint', None) @@ -133,11 +133,13 @@ class ProviderSetupValidationPage(ValidationPage): # XXX update validationMsg # should catch exception #return False - pause_for_user() + + #pause_for_user() #ca_cert_path = checker.ca_cert_path + self.set_done() update_signal.emit('end_sentinel', 100) - pause_for_user() + #pause_for_user() def _do_validation(self): """ @@ -153,10 +155,11 @@ class ProviderSetupValidationPage(ValidationPage): wizard.set_validation_error( prevpage, first_error) - self.go_back() + # XXX don't go back, signal error + #self.go_back() else: - logger.debug('going next') - self.go_next() + logger.debug('should be going next, wait on user') + #self.go_next() def nextId(self): wizard = self.wizard() diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index b46dd4cd..e1a8149c 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -59,6 +59,7 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): self.registerField('userName*', self.userNameLineEdit) self.registerField('userPassword*', self.userPasswordLineEdit) + self.registerField('userPassword2*', self.userPassword2LineEdit) # XXX missing password confirmation # XXX validator! diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index dbe30d3c..6db2bf6e 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -29,16 +29,10 @@ class RegisterUserValidationPage(ValidationPage): def __init__(self, parent=None): super(RegisterUserValidationPage, self).__init__(parent) - is_signup = self.field("is_signup") - self.is_signup = is_signup - if is_signup: - title = "User Creation" - subtitle = "Registering account with provider." - else: - title = "Connecting..." - # XXX uh... really? - subtitle = "Checking connection with provider." + title = "Connecting..." + # XXX uh... really? + subtitle = "Checking connection with provider." self.setTitle(title) self.setSubTitle(subtitle) @@ -67,7 +61,7 @@ class RegisterUserValidationPage(ValidationPage): # Set Credentials. # username and password are in different fields # if they were stored in log_in or sign_up pages. - is_signup = self.is_signup + is_signup = self.field("is_signup") unamek_base = 'userName' passwk_base = 'userPassword' @@ -85,6 +79,7 @@ class RegisterUserValidationPage(ValidationPage): ########################################### # only if from signup + # MOVE TO SIGNUP PAGE... if is_signup: signup = auth.LeapSRPRegister( schema="https", @@ -97,6 +92,8 @@ class RegisterUserValidationPage(ValidationPage): # 1) register user ################################################## # only if from signup. + # XXX MOVE THIS STEP TO SIGNUP-IN-PLACE VALIDATION + # WIDGET.......................................... if is_signup: @@ -113,7 +110,7 @@ class RegisterUserValidationPage(ValidationPage): self.set_error( step, "Error connecting to provider (timeout)") - pause_for_user() + #pause_for_user() return False except requests.exceptions.ConnectionError as exc: @@ -123,9 +120,9 @@ class RegisterUserValidationPage(ValidationPage): "Error connecting to provider " "(connection error)") # XXX we should signal a BAD step - pause_for_user() + #pause_for_user() update_signal.emit("connection error!", 50) - pause_for_user() + #pause_for_user() return False # XXX check for != OK instead??? @@ -147,10 +144,10 @@ class RegisterUserValidationPage(ValidationPage): self.set_error( step, 'Username not available.') - pause_for_user() + #pause_for_user() return False - pause_for_user() + #pause_for_user() ################################################## # 2) fetching eip service config @@ -168,9 +165,9 @@ class RegisterUserValidationPage(ValidationPage): self.set_error( step, 'Could not download eip config.') - pause_for_user() + #pause_for_user() return False - pause_for_user() + #pause_for_user() ################################################## # 3) getting client certificate @@ -192,16 +189,17 @@ class RegisterUserValidationPage(ValidationPage): "Authentication error: %s" % exc.message) return False - pause_for_user() + #pause_for_user() ################ # end ! ################ update_signal.emit("end_sentinel", 100) - pause_for_user() + #pause_for_user() # here we go! :) + # this should be called CONNECT PAGE AGAIN. self.run_eip_checks_for_provider_and_connect(_domain) def run_eip_checks_for_provider_and_connect(self, domain): @@ -225,6 +223,14 @@ class RegisterUserValidationPage(ValidationPage): "probably the wizard has been launched " "in an stand-alone way.") + # XXX look for a better place to signal + # we are done. + # We could probably have a fake validatePage + # that checks if the domain transfer has been + # done to conductor object, triggers the start_signal + # and does the go_next() + self.set_done() + def eip_error_check(self): """ a version of the main app error checker, @@ -241,7 +247,8 @@ class RegisterUserValidationPage(ValidationPage): called after _do_checks has finished (connected to checker thread finished signal) """ - prevpage = "signup" if self.is_signup else "login" + is_signup = self.field("is_signup") + prevpage = "signup" if is_signup else "login" wizard = self.wizard() if self.errors: @@ -253,13 +260,16 @@ class RegisterUserValidationPage(ValidationPage): first_error) self.go_back() else: - logger.debug('going next') - # check if this "next" interferes - # with the eip signal. - self.go_next() + logger.debug('should go next, wait for user to click next') + #self.go_next() def nextId(self): wizard = self.wizard() if not wizard: return return wizard.get_page_index('lastpage') + + def initializePage(self): + super(RegisterUserValidationPage, self).initializePage() + self.set_undone() + self.completeChanged.emit() diff --git a/src/leap/gui/firstrun/wizard.py b/src/leap/gui/firstrun/wizard.py index bbb48149..8efa2018 100755 --- a/src/leap/gui/firstrun/wizard.py +++ b/src/leap/gui/firstrun/wizard.py @@ -137,6 +137,9 @@ class FirstRunWizard(QtGui.QWizard): QtGui.QWizard.BackgroundPixmap, QtGui.QPixmap(':/images/background.png')) + # set options + self.setOption(QtGui.QWizard.IndependentPages, on=False) + self.setWindowTitle("First Run Wizard") # TODO: set style for MAC / windows ... -- cgit v1.2.3 From 7ab2ea1adb82d8c1c6bbae4dc58a157326f579a2 Mon Sep 17 00:00:00 2001 From: kali Date: Mon, 19 Nov 2012 23:23:50 +0900 Subject: set commit page (no back button after validation) --- src/leap/gui/firstrun/register.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index e1a8149c..f872a127 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -29,6 +29,13 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): self.current_page = "signup" + # commit page means there's no way back after this... + # XXX should change the text on the "commit" button... + self.setCommitPage(True) + + self.initUI() + + def initUI(self): userNameLabel = QtGui.QLabel("User &name:") userNameLineEdit = QtGui.QLineEdit() userNameLineEdit.cursorPositionChanged.connect( -- cgit v1.2.3 From a91001e9b84896e8df10ab13aad2dbccd3b6cf36 Mon Sep 17 00:00:00 2001 From: kali Date: Mon, 19 Nov 2012 23:34:03 +0900 Subject: add domain name to providerinfo page --- src/leap/gui/firstrun/providerinfo.py | 9 +++------ src/leap/gui/firstrun/providersetup.py | 5 +++++ 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index 8a3243fc..c5f39938 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -79,8 +79,10 @@ class ProviderInfoPage(ValidationPage): dn = pconfig.get('display_name') display_name = dn[lang] if dn else '' + domain_name = self.field('provider_domain') + self.displayName.setText( - "%s" % display_name) + "%s https://%s" % (display_name, domain_name)) desc = pconfig.get('description') description_text = desc[lang] if desc else '' @@ -239,17 +241,12 @@ class ProviderInfoPage(ValidationPage): #return self.is_done() def initializePage(self): - logger.error('INITIALIZE PAGE --------------') - logger.error('**') - logger.error('**') super(ProviderInfoPage, self).initializePage() self.show_progress() self.set_undone() self.completeChanged.emit() def cleanupPage(self): - logger.error('CLEANUP PAGE --------------') - del self.wizard().providerconfig if self.infoWidget: diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index 5b50db87..0f0bdbd0 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -172,3 +172,8 @@ class ProviderSetupValidationPage(ValidationPage): # XXX bad name. change to connect again. next_ = 'signupvalidation' return wizard.get_page_index(next_) + + def initializePage(self): + super(ProviderSetupValidationPage, self).initializePage() + self.set_undone() + self.completeChanged.emit() -- cgit v1.2.3 From d225d5a4eb0a8e63eb11a0311c732bda88e8385b Mon Sep 17 00:00:00 2001 From: kali Date: Tue, 20 Nov 2012 04:11:01 +0900 Subject: TableWidget refactor so we can use it also in the inline validation widgets. --- src/leap/gui/firstrun/providerselect.py | 107 ++++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 20 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index 8d1aa869..fc030cf3 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -11,12 +11,13 @@ from PyQt4 import QtGui #from leap.eip import exceptions as eipexceptions from leap.gui.constants import APP_LOGO +from leap.gui.progress import InlineValidationPage from leap.gui.styles import ErrorLabelStyleSheet logger = logging.getLogger(__name__) -class SelectProviderPage(QtGui.QWizardPage): +class SelectProviderPage(InlineValidationPage): def __init__(self, parent=None, providers=None): super(SelectProviderPage, self).__init__(parent) @@ -32,6 +33,18 @@ class SelectProviderPage(QtGui.QWizardPage): self.did_cert_check = False self.current_page = 'providerselection' + self.is_done = False + + self.setupSteps() + self.setupUI() + + self.stepChanged.connect( + self.onStepStatusChanged) + + def setupUI(self): + """ + initializes the UI + """ providerNameLabel = QtGui.QLabel("h&ttps://") # note that we expect the bare domain name # we will add the scheme later @@ -61,6 +74,8 @@ class SelectProviderPage(QtGui.QWizardPage): validationMsg = QtGui.QLabel("") validationMsg.setStyleSheet(ErrorLabelStyleSheet) self.validationMsg = validationMsg + providerCheckButton = QtGui.QPushButton("check") + self.providerCheckButton = providerCheckButton # cert info @@ -81,25 +96,66 @@ class SelectProviderPage(QtGui.QWizardPage): self.onTrustCheckChanged) self.providerNameEdit.textChanged.connect( self.onProviderChanged) + self.providerCheckButton.clicked.connect( + self.onCheckButtonClicked) layout = QtGui.QGridLayout() layout.addWidget(validationMsg, 0, 2) layout.addWidget(providerNameLabel, 1, 1) layout.addWidget(providerNameEdit, 1, 2) + layout.addWidget(providerCheckButton, 1, 3) + + # add certinfo group + # XXX not shown now. should move to validation box. + #layout.addWidget(certinfoGroup, 4, 1, 4, 2) + #self.certinfoGroup = certinfoGroup + #self.certinfoGroup.hide() + + # add validation frame + self.setupValidationFrame() + layout.addWidget(self.valFrame, 4, 1, 4, 2) + self.valFrame.hide() + + self.setLayout(layout) - # XXX get a groupbox or something.... + # certinfo + + def setupCertInfoGroup(self): + # XXX not used now. certinfoGroup = QtGui.QGroupBox("Certificate validation") certinfoLayout = QtGui.QVBoxLayout() certinfoLayout.addWidget(self.certInfo) certinfoLayout.addWidget(self.certWarning) certinfoLayout.addWidget(self.trustProviderCertCheckBox) certinfoGroup.setLayout(certinfoLayout) + self.certinfoGroup = self.certinfoGroup + + # progress frame + + def setupValidationFrame(self): + qframe = QtGui.QFrame + valFrame = qframe() + valFrame.setFrameStyle(qframe.StyledPanel) # | qframe.Sunken) + valframeLayout = QtGui.QVBoxLayout() + + #dummylabel = QtGui.QLabel('test foo') + #valframeLayout.addWidget(dummylabel) + valframeLayout.addWidget(self.stepsTableWidget) + valFrame.setLayout(valframeLayout) + self.valFrame = valFrame + + # check domain + + def onCheckButtonClicked(self): + import time + time.sleep(1) + self.is_done = True + self.providerCheckButton.setDisabled(True) + self.stepChanged.emit('foo check', 0) + self.valFrame.show() + self.completeChanged.emit() - layout.addWidget(certinfoGroup, 4, 1, 4, 2) - self.certinfoGroup = certinfoGroup - self.certinfoGroup.hide() - - self.setLayout(layout) + # cert trust verification def is_insecure_cert_trusted(self): return self.trustProviderCertCheckBox.isChecked() @@ -117,7 +173,20 @@ class SelectProviderPage(QtGui.QWizardPage): # trigger signal to redraw next button self.completeChanged.emit() + def add_cert_info(self, certinfo): + self.certWarning.setText( + "Do you want to trust this provider certificate?") + self.certInfo.setText( + 'SHA-256 fingerprint: %s
' % certinfo) + self.certInfo.setWordWrap(True) + self.certinfoGroup.show() + def onProviderChanged(self, text): + provider = self.providerNameEdit.text() + if provider: + self.providerCheckButton.setDisabled(False) + else: + self.providerCheckButton.setDisabled(True) self.completeChanged.emit() def reset_validation_status(self): @@ -126,29 +195,23 @@ class SelectProviderPage(QtGui.QWizardPage): """ self.validationMsg.setText('') - #def set_validation_status(selF, STATUS): - #self.validationMsg.setText(status) - - def add_cert_info(self, certinfo): - self.certWarning.setText( - "Do you want to trust this provider certificate?") - self.certInfo.setText( - 'SHA-256 fingerprint: %s
' % certinfo) - self.certInfo.setWordWrap(True) - self.certinfoGroup.show() - # pagewizard methods def isComplete(self): provider = self.providerNameEdit.text() + if not self.is_done: + return False + if not provider: return False else: if self.is_insecure_cert_trusted(): return True if not self.did_cert_check: - return True + if self.is_done: + # XXX sure? + return True return False def populateErrors(self): @@ -195,7 +258,11 @@ class SelectProviderPage(QtGui.QWizardPage): def initializePage(self): self.validationMsg.setText('') - self.certinfoGroup.hide() + if hasattr(self, 'certinfoGroup'): + # XXX remove ? + self.certinfoGroup.hide() + self.is_done = False + self.providerCheckButton.setDisabled(True) def validatePage(self): # some cleanup before we leave the page -- cgit v1.2.3 From 4e1d0ed099a82843cbb91d5f417c552e9f1674e2 Mon Sep 17 00:00:00 2001 From: kali Date: Tue, 20 Nov 2012 19:09:11 +0900 Subject: added inline panel within zero-margin frame --- src/leap/gui/firstrun/providerselect.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index fc030cf3..3f021ee9 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -74,7 +74,7 @@ class SelectProviderPage(InlineValidationPage): validationMsg = QtGui.QLabel("") validationMsg.setStyleSheet(ErrorLabelStyleSheet) self.validationMsg = validationMsg - providerCheckButton = QtGui.QPushButton("check") + providerCheckButton = QtGui.QPushButton("chec&k") self.providerCheckButton = providerCheckButton # cert info @@ -113,7 +113,7 @@ class SelectProviderPage(InlineValidationPage): # add validation frame self.setupValidationFrame() - layout.addWidget(self.valFrame, 4, 1, 4, 2) + layout.addWidget(self.valFrame, 4, 2, 4, 2) self.valFrame.hide() self.setLayout(layout) @@ -135,8 +135,13 @@ class SelectProviderPage(InlineValidationPage): def setupValidationFrame(self): qframe = QtGui.QFrame valFrame = qframe() - valFrame.setFrameStyle(qframe.StyledPanel) # | qframe.Sunken) + valFrame.setFrameStyle(qframe.NoFrame) + # Box | qframe.Plain) + # NoFrame, StyledPanel) | qframe.Sunken) + #valFrame.setContentsMargins(0, 0, 0, 0) valframeLayout = QtGui.QVBoxLayout() + zeros = (0, 0, 0, 0) + valframeLayout.setContentsMargins(*zeros) #dummylabel = QtGui.QLabel('test foo') #valframeLayout.addWidget(dummylabel) @@ -147,12 +152,16 @@ class SelectProviderPage(InlineValidationPage): # check domain def onCheckButtonClicked(self): + print 'check button called....' + self.providerCheckButton.setDisabled(True) + self.valFrame.show() import time time.sleep(1) - self.is_done = True - self.providerCheckButton.setDisabled(True) - self.stepChanged.emit('foo check', 0) + # XXX bug here!... Y U DUPLICATE?!! + self.stepChanged.emit('xxx', 10) + self.stepChanged.emit('end_sentinel', 0) self.valFrame.show() + self.is_done = True self.completeChanged.emit() # cert trust verification -- cgit v1.2.3 From 7dceb11bcd4cf552938ccfa02daaf6f902ef385b Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 21 Nov 2012 05:15:06 +0900 Subject: tango icons for checking/checked/failed check status --- src/leap/gui/firstrun/providerselect.py | 64 +++++++++++++++++++++++++++------ src/leap/gui/firstrun/providersetup.py | 2 +- 2 files changed, 55 insertions(+), 11 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index 3f021ee9..1326ca1d 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -6,13 +6,14 @@ import logging from PyQt4 import QtCore from PyQt4 import QtGui -#from leap.base import exceptions as baseexceptions +from leap.base import exceptions as baseexceptions #from leap.crypto import certs #from leap.eip import exceptions as eipexceptions from leap.gui.constants import APP_LOGO from leap.gui.progress import InlineValidationPage from leap.gui.styles import ErrorLabelStyleSheet +from leap.util.web import get_https_domain_and_port logger = logging.getLogger(__name__) @@ -38,9 +39,6 @@ class SelectProviderPage(InlineValidationPage): self.setupSteps() self.setupUI() - self.stepChanged.connect( - self.onStepStatusChanged) - def setupUI(self): """ initializes the UI @@ -155,16 +153,59 @@ class SelectProviderPage(InlineValidationPage): print 'check button called....' self.providerCheckButton.setDisabled(True) self.valFrame.show() - import time - time.sleep(1) - # XXX bug here!... Y U DUPLICATE?!! - self.stepChanged.emit('xxx', 10) - self.stepChanged.emit('end_sentinel', 0) - self.valFrame.show() + self.do_checks() + + def _do_checks(self, update_signal=None, failed_signal=None): + """ + executes actual checks in a separate thread + """ + finish = lambda: update_signal.emit("end_sentinel", 100) + + wizard = self.wizard() + prevpage = "providerselection" + + full_domain = self.providerNameEdit.text() + + # we check if we have a port in the domain string. + domain, port = get_https_domain_and_port(full_domain) + _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain) + + netchecker = wizard.netchecker() + + #providercertchecker = wizard.providercertchecker() + #eipconfigchecker = wizard.eipconfigchecker(domain=_domain) + + update_signal.emit("head_sentinel", 0) + + ######################## + # 1) try name resolution + ######################## + update_signal.emit("Checking that server is reachable", 20) + logger.debug('checking name resolution') + try: + netchecker.check_name_resolution( + domain) + + except baseexceptions.LeapException as exc: + logger.error(exc.message) + wizard.set_validation_error( + prevpage, exc.usermessage) + failed_signal.emit() + return False + self.is_done = True + finish() + + def _inline_validation_ready(self): + """ + called after _do_checks has finished. + """ + # XXX check if it's really done (catch signal for completed) + #self.done = True self.completeChanged.emit() # cert trust verification + # (disabled for now) def is_insecure_cert_trusted(self): return self.trustProviderCertCheckBox.isChecked() @@ -272,6 +313,9 @@ class SelectProviderPage(InlineValidationPage): self.certinfoGroup.hide() self.is_done = False self.providerCheckButton.setDisabled(True) + self.valFrame.hide() + self.steps.removeAllSteps() + self.clearTable() def validatePage(self): # some cleanup before we leave the page diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index 0f0bdbd0..7c19dc3f 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -54,7 +54,7 @@ class ProviderSetupValidationPage(ValidationPage): # (so we're able to go back an correct) step = "fetch_eipcert" - update_signal.emit('validating credentials', 20) + update_signal.emit('Validating credentials', 20) unamek = 'login_userName' passwk = 'login_userPassword' -- cgit v1.2.3 From 8ad4957531f5279cf65df36b015d83443deded33 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 21 Nov 2012 05:55:23 +0900 Subject: update check status when provider entry changes. disable next button and remove any error message (but remember which was the latest bad string if you are changing providers withouth going to the next page). --- src/leap/gui/firstrun/providerselect.py | 40 ++++++++++++++++++++++++--------- src/leap/gui/firstrun/wizard.py | 5 +++++ 2 files changed, 34 insertions(+), 11 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index 1326ca1d..b6482379 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -22,10 +22,10 @@ class SelectProviderPage(InlineValidationPage): def __init__(self, parent=None, providers=None): super(SelectProviderPage, self).__init__(parent) - self.setTitle("Enter Provider") - self.setSubTitle( + self.setTitle(self.tr("Enter Provider")) + self.setSubTitle(self.tr( "Please enter the domain of the provider you want " - "to use for your connection." + "to use for your connection.") ) self.setPixmap( QtGui.QWizard.LogoPixmap, @@ -72,7 +72,7 @@ class SelectProviderPage(InlineValidationPage): validationMsg = QtGui.QLabel("") validationMsg.setStyleSheet(ErrorLabelStyleSheet) self.validationMsg = validationMsg - providerCheckButton = QtGui.QPushButton("chec&k") + providerCheckButton = QtGui.QPushButton(self.tr("chec&k")) self.providerCheckButton = providerCheckButton # cert info @@ -82,7 +82,8 @@ class SelectProviderPage(InlineValidationPage): # tricky, since the first time came # from the exception message. # should get string from exception too! - self.bad_cert_status = "Server certificate could not be verified." + self.bad_cert_status = self.tr( + "Server certificate could not be verified.") self.certInfo = QtGui.QLabel("") self.certInfo.setWordWrap(True) @@ -120,7 +121,8 @@ class SelectProviderPage(InlineValidationPage): def setupCertInfoGroup(self): # XXX not used now. - certinfoGroup = QtGui.QGroupBox("Certificate validation") + certinfoGroup = QtGui.QGroupBox( + self.tr("Certificate validation")) certinfoLayout = QtGui.QVBoxLayout() certinfoLayout.addWidget(self.certInfo) certinfoLayout.addWidget(self.certWarning) @@ -150,7 +152,6 @@ class SelectProviderPage(InlineValidationPage): # check domain def onCheckButtonClicked(self): - print 'check button called....' self.providerCheckButton.setDisabled(True) self.valFrame.show() self.do_checks() @@ -180,7 +181,7 @@ class SelectProviderPage(InlineValidationPage): ######################## # 1) try name resolution ######################## - update_signal.emit("Checking that server is reachable", 20) + update_signal.emit(self.tr("Can reach provider"), 20) logger.debug('checking name resolution') try: netchecker.check_name_resolution( @@ -191,6 +192,7 @@ class SelectProviderPage(InlineValidationPage): wizard.set_validation_error( prevpage, exc.usermessage) failed_signal.emit() + self.is_done = False return False self.is_done = True @@ -200,8 +202,9 @@ class SelectProviderPage(InlineValidationPage): """ called after _do_checks has finished. """ - # XXX check if it's really done (catch signal for completed) - #self.done = True + self.domain_checked = True + if self.is_done: + self.wizard().clean_validation_error(self.current_page) self.completeChanged.emit() # cert trust verification @@ -232,6 +235,7 @@ class SelectProviderPage(InlineValidationPage): self.certinfoGroup.show() def onProviderChanged(self, text): + self.is_done = False provider = self.providerNameEdit.text() if provider: self.providerCheckButton.setDisabled(False) @@ -242,8 +246,12 @@ class SelectProviderPage(InlineValidationPage): def reset_validation_status(self): """ empty the validation msg + and clean the inline validation widget. """ self.validationMsg.setText('') + self.steps.removeAllSteps() + self.clearTable() + self.domain_checked = False # pagewizard methods @@ -283,10 +291,19 @@ class SelectProviderPage(InlineValidationPage): showerr(errors) else: # not the first time + # XXX hey, this is getting convoluted. + # roll out this. + # but be careful about all the possibilities + # with going back and forth once you + # enter a domain. if cur_str == bad_str: showerr(errors) else: - showerr('') + if not getattr(self, 'domain_checked', None): + showerr('') + else: + self.bad_string = cur_str + showerr(errors) def cleanup_errormsg(self): """ @@ -294,6 +311,7 @@ class SelectProviderPage(InlineValidationPage): should be called before leaving the page """ self.bad_string = None + self.domain_checked = False def paintEvent(self, event): """ diff --git a/src/leap/gui/firstrun/wizard.py b/src/leap/gui/firstrun/wizard.py index 8efa2018..4a72177e 100755 --- a/src/leap/gui/firstrun/wizard.py +++ b/src/leap/gui/firstrun/wizard.py @@ -170,6 +170,11 @@ class FirstRunWizard(QtGui.QWizard): def set_validation_error(self, pagename, error): self.validation_errors[pagename] = error + def clean_validation_error(self, pagename): + vald = self.validation_errors + if pagename in vald: + del vald[pagename] + def get_validation_error(self, pagename): return self.validation_errors.get(pagename, None) -- cgit v1.2.3 From 53c6c92e26970de7de0bddca0034e72af7d0ce48 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 21 Nov 2012 06:15:41 +0900 Subject: add red border to failed field --- src/leap/gui/firstrun/providerselect.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index b6482379..2786c494 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -12,7 +12,7 @@ from leap.base import exceptions as baseexceptions from leap.gui.constants import APP_LOGO from leap.gui.progress import InlineValidationPage -from leap.gui.styles import ErrorLabelStyleSheet +from leap.gui import styles from leap.util.web import get_https_domain_and_port logger = logging.getLogger(__name__) @@ -70,7 +70,7 @@ class SelectProviderPage(InlineValidationPage): #self.registerField('provider_name_index', providerNameSelect) validationMsg = QtGui.QLabel("") - validationMsg.setStyleSheet(ErrorLabelStyleSheet) + validationMsg.setStyleSheet(styles.ErrorLabelStyleSheet) self.validationMsg = validationMsg providerCheckButton = QtGui.QPushButton(self.tr("chec&k")) self.providerCheckButton = providerCheckButton @@ -284,11 +284,16 @@ class SelectProviderPage(InlineValidationPage): bad_str = getattr(self, 'bad_string', None) cur_str = self.providerNameEdit.text() showerr = self.validationMsg.setText + markred = lambda: self.providerNameEdit.setStyleSheet( + styles.ErrorLineEdit) + umarkrd = lambda: self.providerNameEdit.setStyleSheet( + styles.RegularLineEdit) if bad_str is None: # first time we fall here. # save the current bad_string value self.bad_string = cur_str showerr(errors) + markred() else: # not the first time # XXX hey, this is getting convoluted. @@ -298,9 +303,11 @@ class SelectProviderPage(InlineValidationPage): # enter a domain. if cur_str == bad_str: showerr(errors) + markred() else: if not getattr(self, 'domain_checked', None): showerr('') + umarkrd() else: self.bad_string = cur_str showerr(errors) -- cgit v1.2.3 From 7bf4c0aa6db8cbaa1befdb2841f722554a3a0731 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 21 Nov 2012 23:01:06 +0900 Subject: fixed ui freeze using queue for passing status between worker and parent --- src/leap/gui/firstrun/providerinfo.py | 119 +------------------ src/leap/gui/firstrun/providerselect.py | 200 ++++++++++++++++++++++++++++---- 2 files changed, 182 insertions(+), 137 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index c5f39938..48763357 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -98,120 +98,8 @@ class ProviderInfoPage(ValidationPage): """ executes actual checks in a separate thread """ - finish = lambda: update_signal.emit("end_sentinel", 100) - - def pause_and_finish(): - # only for local debug - finish() - pause_for_user() - - wizard = self.wizard() - prevpage = "providerselection" - - full_domain = self.field('provider_domain') - - # we check if we have a port in the domain string. - domain, port = get_https_domain_and_port(full_domain) - _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain) - - netchecker = wizard.netchecker() - providercertchecker = wizard.providercertchecker() - eipconfigchecker = wizard.eipconfigchecker(domain=_domain) - - update_signal.emit("head_sentinel", 0) - pause_for_user() - - ######################## - # 1) try name resolution - ######################## - update_signal.emit("Checking that server is reachable", 20) - logger.debug('checking name resolution') - try: - netchecker.check_name_resolution( - domain) - - except baseexceptions.LeapException as exc: - logger.error(exc.message) - wizard.set_validation_error( - prevpage, exc.usermessage) - pause_and_finish() - return False - - ######################### - # 2) try https connection - ######################### - update_signal.emit("Checking secure connection to provider", 40) - logger.debug('checking https connection') - try: - providercertchecker.is_https_working( - "https://%s" % _domain, - verify=True) - - except eipexceptions.HttpsBadCertError as exc: - logger.debug('exception') - # XXX skipping for now... - ############################################## - # We had this validation logic - # in the provider selection page before - ############################################## - #if self.trustProviderCertCheckBox.isChecked(): - #pass - #else: - wizard.set_validation_error( - prevpage, exc.usermessage) - #fingerprint = certs.get_cert_fingerprint( - #domain=domain, sep=" ") - - # it's ok if we've trusted this fgprt before - #trustedcrts = wizard.trusted_certs - #if trustedcrts and fingerprint.replace(' ', '') in trustedcrts: - #pass - #else: - # let your user face panick :P - #self.add_cert_info(fingerprint) - #self.did_cert_check = True - #self.completeChanged.emit() - #return False - finish() - return False - - except baseexceptions.LeapException as exc: - wizard.set_validation_error( - prevpage, exc.usermessage) - finish() - return False - - ################################## - # 3) try download provider info... - ################################## - - update_signal.emit("Downloading provider info", 70) - try: - # XXX we already set _domain in the initialization - # so it should not be needed here. - eipconfigchecker.fetch_definition(domain=_domain) - wizard.set_providerconfig( - eipconfigchecker.defaultprovider.config) - except requests.exceptions.SSLError: - # XXX we should have catched this before. - # but cert checking is broken. - wizard.set_validation_error( - prevpage, - "Could not get info from provider.") - finish() - return False - except requests.exceptions.ConnectionError: - wizard.set_validation_error( - prevpage, - "Could not download provider info " - "(refused conn.).") - finish() - return False - # XXX catch more errors... - # We're done! self.set_done() - finish() def _do_validation(self): """ @@ -247,7 +135,12 @@ class ProviderInfoPage(ValidationPage): self.completeChanged.emit() def cleanupPage(self): - del self.wizard().providerconfig + wizard = self.wizard() + + # XXX makes sense now? + # this was created on previous... + if hasattr(wizard, 'providerconfig'): + del self.wizard().providerconfig if self.infoWidget: QtCore.QObjectCleanupHandler().add( diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index 2786c494..08e09ee3 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -1,14 +1,17 @@ """ Select Provider Page, used in First Run Wizard """ +from functools import partial import logging +import requests + from PyQt4 import QtCore from PyQt4 import QtGui from leap.base import exceptions as baseexceptions #from leap.crypto import certs -#from leap.eip import exceptions as eipexceptions +from leap.eip import exceptions as eipexceptions from leap.gui.constants import APP_LOGO from leap.gui.progress import InlineValidationPage @@ -17,8 +20,24 @@ from leap.util.web import get_https_domain_and_port logger = logging.getLogger(__name__) +# XXX check newer version in progress... + + +def delay(obj, method_str): + """ + this is a hack to get responsiveness in the ui + """ + QtCore.QTimer().singleShot( + 10, + lambda: QtCore.QMetaObject.invokeMethod( + obj, method_str)) + class SelectProviderPage(InlineValidationPage): + + #disableCheckButton = QtCore.pyqtSignal() + launchChecks = QtCore.pyqtSignal() + def __init__(self, parent=None, providers=None): super(SelectProviderPage, self).__init__(parent) @@ -39,6 +58,11 @@ class SelectProviderPage(InlineValidationPage): self.setupSteps() self.setupUI() + #self.disableCheckButton.connect( + #self.onDisableCheckButton) + self.launchChecks.connect( + self.launch_checks) + def setupUI(self): """ initializes the UI @@ -149,21 +173,41 @@ class SelectProviderPage(InlineValidationPage): valFrame.setLayout(valframeLayout) self.valFrame = valFrame - # check domain - - def onCheckButtonClicked(self): + @QtCore.pyqtSlot() + def onDisableCheckButton(self): + print 'CHECK BUTTON DISABLED!!!' self.providerCheckButton.setDisabled(True) - self.valFrame.show() + + @QtCore.pyqtSlot() + def launch_checks(self): + # trying to delay this... + #timer = QtCore.QTimer() + #timer.singleShot(0, self.do_checks) self.do_checks() - def _do_checks(self, update_signal=None, failed_signal=None): + def onCheckButtonClicked(self): + #self.disableCheckButton.emit() + # XXX trying to get responsiveness. + # UI here is blocking, although I'm using + # threads and signals :( + QtCore.QMetaObject.invokeMethod( + self, "onDisableCheckButton") + + QtCore.QMetaObject.invokeMethod( + self, "showStepsFrame") + + delay(self, "launch_checks") + + print 'ON CHECK BUTTON --- DONE!' + print 'timer.....' + + def _do_checks(self): """ executes actual checks in a separate thread """ - finish = lambda: update_signal.emit("end_sentinel", 100) wizard = self.wizard() - prevpage = "providerselection" + curpage = "providerselection" full_domain = self.providerNameEdit.text() @@ -173,35 +217,143 @@ class SelectProviderPage(InlineValidationPage): netchecker = wizard.netchecker() - #providercertchecker = wizard.providercertchecker() - #eipconfigchecker = wizard.eipconfigchecker(domain=_domain) + providercertchecker = wizard.providercertchecker() + eipconfigchecker = wizard.eipconfigchecker(domain=_domain) + + def fail(): + self.is_done = False + return False - update_signal.emit("head_sentinel", 0) + yield(("head_sentinel", 0), lambda: None) ######################## # 1) try name resolution ######################## - update_signal.emit(self.tr("Can reach provider"), 20) logger.debug('checking name resolution') - try: - netchecker.check_name_resolution( - domain) - - except baseexceptions.LeapException as exc: - logger.error(exc.message) - wizard.set_validation_error( - prevpage, exc.usermessage) - failed_signal.emit() - self.is_done = False - return False + def namecheck(): + try: + netchecker.check_name_resolution( + domain) + + except baseexceptions.LeapException as exc: + logger.error(exc.message) + wizard.set_validation_error( + curpage, exc.usermessage) + return fail() + + except Exception as exc: + wizard.set_validation_error( + curpage, exc.message) + return fail() + + else: + return True + + # XXX catch more exceptions + + yield(("check name", 20), namecheck) + + ######################### + # 2) try https connection + ######################### + + logger.debug('checking https connection') + + def httpscheck(): + try: + providercertchecker.is_https_working( + "https://%s" % _domain, + verify=True) + + except eipexceptions.HttpsBadCertError as exc: + logger.debug('exception') + # XXX skipping for now... + ############################################## + # We had this validation logic + # in the provider selection page before + ############################################## + #if self.trustProviderCertCheckBox.isChecked(): + #pass + #else: + wizard.set_validation_error( + curpage, exc.usermessage) + #fingerprint = certs.get_cert_fingerprint( + #domain=domain, sep=" ") + + # it's ok if we've trusted this fgprt before + #trustedcrts = wizard.trusted_certs + #if trustedcrts and \ + # fingerprint.replace(' ', '') in trustedcrts: + #pass + #else: + # let your user face panick :P + #self.add_cert_info(fingerprint) + #self.did_cert_check = True + #self.completeChanged.emit() + #return False + return fail() + + except baseexceptions.LeapException as exc: + wizard.set_validation_error( + curpage, exc.usermessage) + return fail() + + except Exception as exc: + wizard.set_validation_error( + curpage, exc.message) + return fail() + + else: + return True + + yield(("https check", 40), httpscheck) + + ################################## + # 3) try download provider info... + ################################## + + def fetchinfo(): + try: + # XXX we already set _domain in the initialization + # so it should not be needed here. + eipconfigchecker.fetch_definition(domain=_domain) + wizard.set_providerconfig( + eipconfigchecker.defaultprovider.config) + except requests.exceptions.SSLError: + # XXX we should have catched this before. + # but cert checking is broken. + wizard.set_validation_error( + curpage, + self.tr( + "Could not get info from provider.")) + return fail() + except requests.exceptions.ConnectionError: + wizard.set_validation_error( + curpage, + self.tr( + "Could not download provider info " + "(refused conn.).")) + return fail() + + except Exception as exc: + wizard.set_validation_error( + curpage, exc.message) + return fail() + + else: + return True + yield(("fetch info", 80), fetchinfo) + + # done! self.is_done = True - finish() + yield(("end_sentinel", 100), lambda: None) def _inline_validation_ready(self): """ called after _do_checks has finished. """ + print 'VALIDATION READY ---------------' self.domain_checked = True if self.is_done: self.wizard().clean_validation_error(self.current_page) -- cgit v1.2.3 From f9a3e2cf6c4f7398411788974a2a6a9a53c9a1ab Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 22 Nov 2012 02:46:57 +0900 Subject: info page refactor. --- src/leap/gui/firstrun/providerinfo.py | 86 ++++++--------------------------- src/leap/gui/firstrun/providerselect.py | 40 +++++++-------- src/leap/gui/firstrun/providersetup.py | 6 +-- 3 files changed, 36 insertions(+), 96 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index 48763357..c5b2984c 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -3,43 +3,33 @@ Provider Info Page, used in First run Wizard """ import logging -from PyQt4 import QtCore from PyQt4 import QtGui -import requests - -from leap.base import exceptions as baseexceptions -#from leap.crypto import certs -from leap.eip import exceptions as eipexceptions - -from leap.gui.progress import ValidationPage -from leap.util.web import get_https_domain_and_port - -from leap.gui.constants import APP_LOGO, pause_for_user +from leap.gui.constants import APP_LOGO logger = logging.getLogger(__name__) -class ProviderInfoPage(ValidationPage): +class ProviderInfoPage(QtGui.QWizardPage): + def __init__(self, parent=None): super(ProviderInfoPage, self).__init__(parent) - self.setTitle("Provider Info") - #self.setSubTitle("Available information about chosen provider.") + self.setTitle(self.tr("Provider Info")) + self.setSubTitle(self.tr( + "This is what provider says.")) self.setPixmap( QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) - self.prev_page = "providerselection" - self.infoWidget = None - #self.current_page = "providerinfo" + self.create_info_panel() def create_info_panel(self): # Use stacked widget instead # of reparenting the layout. - self.infoWidget = QtGui.QStackedWidget() + infoWidget = QtGui.QStackedWidget() info = QtGui.QWidget() layout = QtGui.QVBoxLayout() @@ -47,19 +37,24 @@ class ProviderInfoPage(ValidationPage): displayName = QtGui.QLabel("") description = QtGui.QLabel("") enrollment_policy = QtGui.QLabel("") + # XXX set stylesheet... # prettify a little bit. # bigger fonts and so on... + # We could use a QFrame here + layout.addWidget(displayName) layout.addWidget(description) layout.addWidget(enrollment_policy) layout.addStretch(1) info.setLayout(layout) - self.infoWidget.addWidget(info) + infoWidget.addWidget(info) - self.layout.addWidget(self.infoWidget) + pageLayout = QtGui.QVBoxLayout() + pageLayout.addWidget(infoWidget) + self.setLayout(pageLayout) # add refs to self to allow for # updates. @@ -94,59 +89,10 @@ class ProviderInfoPage(ValidationPage): self.enrollment_policy.setText( 'enrollment policy: %s' % enroll) - def _do_checks(self, update_signal=None): - """ - executes actual checks in a separate thread - """ - # We're done! - self.set_done() - - def _do_validation(self): - """ - called after _do_checks has finished - (connected to checker thread finished signal) - """ - print 'validation...' - prevpage = "providerselection" - errors = self.wizard().get_validation_error(prevpage) - - if not errors: - self.hide_progress() - self.create_info_panel() - self.show_provider_info() - - else: - logger.debug('going back with errors') - logger.debug('ERRORS: %s' % errors) - self.go_back() - def nextId(self): wizard = self.wizard() next_ = "providersetupvalidation" return wizard.get_page_index(next_) - #def isComplete(self): - #return self.is_done() - def initializePage(self): - super(ProviderInfoPage, self).initializePage() - self.show_progress() - self.set_undone() - self.completeChanged.emit() - - def cleanupPage(self): - wizard = self.wizard() - - # XXX makes sense now? - # this was created on previous... - if hasattr(wizard, 'providerconfig'): - del self.wizard().providerconfig - - if self.infoWidget: - QtCore.QObjectCleanupHandler().add( - self.infoWidget) - - # refactor this into some kind of destructor - del self.displayName - del self.description - del self.enrollment_policy + self.show_provider_info() diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index 08e09ee3..0250ab8c 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -58,8 +58,6 @@ class SelectProviderPage(InlineValidationPage): self.setupSteps() self.setupUI() - #self.disableCheckButton.connect( - #self.onDisableCheckButton) self.launchChecks.connect( self.launch_checks) @@ -160,15 +158,10 @@ class SelectProviderPage(InlineValidationPage): qframe = QtGui.QFrame valFrame = qframe() valFrame.setFrameStyle(qframe.NoFrame) - # Box | qframe.Plain) - # NoFrame, StyledPanel) | qframe.Sunken) - #valFrame.setContentsMargins(0, 0, 0, 0) valframeLayout = QtGui.QVBoxLayout() zeros = (0, 0, 0, 0) valframeLayout.setContentsMargins(*zeros) - #dummylabel = QtGui.QLabel('test foo') - #valframeLayout.addWidget(dummylabel) valframeLayout.addWidget(self.stepsTableWidget) valFrame.setLayout(valframeLayout) self.valFrame = valFrame @@ -180,16 +173,9 @@ class SelectProviderPage(InlineValidationPage): @QtCore.pyqtSlot() def launch_checks(self): - # trying to delay this... - #timer = QtCore.QTimer() - #timer.singleShot(0, self.do_checks) self.do_checks() def onCheckButtonClicked(self): - #self.disableCheckButton.emit() - # XXX trying to get responsiveness. - # UI here is blocking, although I'm using - # threads and signals :( QtCore.QMetaObject.invokeMethod( self, "onDisableCheckButton") @@ -198,12 +184,10 @@ class SelectProviderPage(InlineValidationPage): delay(self, "launch_checks") - print 'ON CHECK BUTTON --- DONE!' - print 'timer.....' - def _do_checks(self): """ - executes actual checks in a separate thread + generator that yields actual checks + that are executed in a separate thread """ wizard = self.wizard() @@ -229,9 +213,13 @@ class SelectProviderPage(InlineValidationPage): ######################## # 1) try name resolution ######################## - logger.debug('checking name resolution') def namecheck(): + """ + in which we check if + we are able to name resolve + this domain + """ try: netchecker.check_name_resolution( domain) @@ -250,17 +238,21 @@ class SelectProviderPage(InlineValidationPage): else: return True - # XXX catch more exceptions + logger.debug('checking name resolution') yield(("check name", 20), namecheck) ######################### # 2) try https connection ######################### - logger.debug('checking https connection') - def httpscheck(): + """ + in which we check + if the provider + is offering service over + https + """ try: providercertchecker.is_https_working( "https://%s" % _domain, @@ -307,6 +299,7 @@ class SelectProviderPage(InlineValidationPage): else: return True + logger.debug('checking https connection') yield(("https check", 40), httpscheck) ################################## @@ -343,9 +336,11 @@ class SelectProviderPage(InlineValidationPage): else: return True + yield(("fetch info", 80), fetchinfo) # done! + self.is_done = True yield(("end_sentinel", 100), lambda: None) @@ -353,7 +348,6 @@ class SelectProviderPage(InlineValidationPage): """ called after _do_checks has finished. """ - print 'VALIDATION READY ---------------' self.domain_checked = True if self.is_done: self.wizard().clean_validation_error(self.current_page) diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index 7c19dc3f..042d117c 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -20,9 +20,9 @@ class ProviderSetupValidationPage(ValidationPage): is_signup = self.field("is_signup") self.is_signup = is_signup - self.setTitle("Setting up provider") - #self.setSubTitle( - #"auto configuring provider...") + self.setTitle("Provider setup") + self.setSubTitle( + "Doing autoconfig.") self.setPixmap( QtGui.QWizard.LogoPixmap, -- cgit v1.2.3 From 60ae69dd79fc4a17e54e9f898b04c7130d8b9f6e Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 22 Nov 2012 06:26:02 +0900 Subject: fix widgets focus on providerselect page it works with enter, enter, enter :) dedicated to DJ Focus... --- src/leap/gui/firstrun/login.py | 1 + src/leap/gui/firstrun/providerselect.py | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/login.py b/src/leap/gui/firstrun/login.py index 4271c774..004fa7d4 100644 --- a/src/leap/gui/firstrun/login.py +++ b/src/leap/gui/firstrun/login.py @@ -139,6 +139,7 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): def initializePage(self): super(LogInPage, self).initializePage() + # XXX setPlaceholderText instead?! self.userNameLineEdit.setText('username@provider.example.org') self.userNameLineEdit.cursorPositionChanged.connect( self.onUserNameEdit) diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index 0250ab8c..d029b1db 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -61,6 +61,9 @@ class SelectProviderPage(InlineValidationPage): self.launchChecks.connect( self.launch_checks) + self.providerNameEdit.editingFinished.connect( + lambda: self.providerCheckButton.setFocus(True)) + def setupUI(self): """ initializes the UI @@ -94,7 +97,7 @@ class SelectProviderPage(InlineValidationPage): validationMsg = QtGui.QLabel("") validationMsg.setStyleSheet(styles.ErrorLabelStyleSheet) self.validationMsg = validationMsg - providerCheckButton = QtGui.QPushButton(self.tr("chec&k")) + providerCheckButton = QtGui.QPushButton(self.tr("chec&k!")) self.providerCheckButton = providerCheckButton # cert info @@ -238,7 +241,6 @@ class SelectProviderPage(InlineValidationPage): else: return True - logger.debug('checking name resolution') yield(("check name", 20), namecheck) @@ -349,9 +351,14 @@ class SelectProviderPage(InlineValidationPage): called after _do_checks has finished. """ self.domain_checked = True + self.completeChanged.emit() + # let's set focus... if self.is_done: self.wizard().clean_validation_error(self.current_page) - self.completeChanged.emit() + nextbutton = self.wizard().button(QtGui.QWizard.NextButton) + nextbutton.setFocus() + else: + self.providerNameEdit.setFocus() # cert trust verification # (disabled for now) -- cgit v1.2.3 From 7a263b8ee74cc92ba39796cd9ad48395adfa7450 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 23 Nov 2012 05:13:36 +0900 Subject: refactor validation mixin; progress until register page --- src/leap/gui/firstrun/login.py | 67 +++++++++++++- src/leap/gui/firstrun/providerselect.py | 8 +- src/leap/gui/firstrun/providersetup.py | 158 ++++++++++++++++---------------- src/leap/gui/firstrun/register.py | 158 +++++++++++++++++++++++++------- src/leap/gui/firstrun/regvalidation.py | 79 ++-------------- src/leap/gui/firstrun/wizard.py | 1 + 6 files changed, 283 insertions(+), 188 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/login.py b/src/leap/gui/firstrun/login.py index 004fa7d4..3a6ec089 100644 --- a/src/leap/gui/firstrun/login.py +++ b/src/leap/gui/firstrun/login.py @@ -6,14 +6,17 @@ from PyQt4 import QtGui #import requests +from leap.base import auth from leap.gui.firstrun.mixins import UserFormMixIn from leap.gui.constants import APP_LOGO, FULL_USERNAME_REGEX from leap.gui.styles import ErrorLabelStyleSheet -class LogInPage(QtGui.QWizardPage, UserFormMixIn): +class LogInPage(QtGui.QWizardPage, UserFormMixIn): # InlineValidationPage + def __init__(self, parent=None): + super(LogInPage, self).__init__(parent) self.setTitle("Log In") @@ -24,6 +27,9 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) + self.setupUI() + + def setupUI(self): userNameLabel = QtGui.QLabel("User &name:") userNameLineEdit = QtGui.QLineEdit() userNameLineEdit.cursorPositionChanged.connect( @@ -149,6 +155,7 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): #wizard = self.wizard() #eipconfigchecker = wizard.eipconfigchecker() + # XXX should move to _do_checks full_username = self.userNameLineEdit.text() password = self.userPasswordLineEdit.text() if full_username.count('@') != 1: @@ -191,3 +198,61 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): self.cleanup_errormsg() return True + + def _do_checks(self): + # XXX convert this to inline + + full_username = self.userNameLineEdit.text() + password = self.userPasswordLineEdit.text() + username, domain = full_username.split('@') + # We try a call to an authenticated + # page here as a mean to catch + # srp authentication errors while + wizard = self.wizard() + pCertChecker = wizard.providercertchecker( + domain=domain) + + curpage = "login" + + def fail(): + self.is_done = False + return False + + ######################## + # 1) try name resolution + ######################## + # XXX + # bring here from validation above... + + ######################## + # 2) do authentication + ######################## + + unamek = 'login_userName' + passwk = 'login_userPassword' + + username = self.field(unamek) + password = self.field(passwk) + credentials = username, password + + def validate_credentials(): + ################# + # FIXME #BUG #638 + verify = False + + try: + pCertChecker.download_new_client_cert( + credentials=credentials, + verify=verify) + + except auth.SRPAuthenticationError as exc: + wizard.set_validation_error( + curpage, "Authentication error: %s" % exc.usermessage) + return fail() + + except Exception as exc: + wizard.set_validation_error( + curpage, "%s" % exc.message) + return fail() + + yield(('Validating credentials', 20), lambda: None) diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index d029b1db..dffde040 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -1,7 +1,6 @@ """ Select Provider Page, used in First Run Wizard """ -from functools import partial import logging import requests @@ -20,10 +19,9 @@ from leap.util.web import get_https_domain_and_port logger = logging.getLogger(__name__) -# XXX check newer version in progress... - def delay(obj, method_str): + # XXX check newer version in progress.py... """ this is a hack to get responsiveness in the ui """ @@ -40,6 +38,7 @@ class SelectProviderPage(InlineValidationPage): def __init__(self, parent=None, providers=None): super(SelectProviderPage, self).__init__(parent) + self.current_page = 'providerselection' self.setTitle(self.tr("Enter Provider")) self.setSubTitle(self.tr( @@ -51,7 +50,6 @@ class SelectProviderPage(InlineValidationPage): QtGui.QPixmap(APP_LOGO)) self.did_cert_check = False - self.current_page = 'providerselection' self.is_done = False @@ -346,7 +344,7 @@ class SelectProviderPage(InlineValidationPage): self.is_done = True yield(("end_sentinel", 100), lambda: None) - def _inline_validation_ready(self): + def on_checks_validation_ready(self): """ called after _do_checks has finished. """ diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index 042d117c..7904538d 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -6,10 +6,10 @@ import logging from PyQt4 import QtGui -from leap.base import auth +from leap.base import exceptions as baseexceptions from leap.gui.progress import ValidationPage -from leap.gui.constants import APP_LOGO, pause_for_user +from leap.gui.constants import APP_LOGO logger = logging.getLogger(__name__) @@ -20,18 +20,21 @@ class ProviderSetupValidationPage(ValidationPage): is_signup = self.field("is_signup") self.is_signup = is_signup - self.setTitle("Provider setup") + self.setTitle(self.tr("Provider setup")) self.setSubTitle( - "Doing autoconfig.") + self.tr("Doing autoconfig.")) self.setPixmap( QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) - def _do_checks(self, update_signal=None): + def _do_checks(self): """ - executes actual checks in a separate thread + generator that yields actual checks + that are executed in a separate thread """ + curpage = "providersetupvalidation" + full_domain = self.field('provider_domain') wizard = self.wizard() pconfig = wizard.providerconfig @@ -41,68 +44,56 @@ class ProviderSetupValidationPage(ValidationPage): pCertChecker = wizard.providercertchecker( domain=full_domain) - update_signal.emit('head_sentinel', 0) - - ###################################### - if not self.is_signup: - # We come from login page. - # We try a call to an authenticated - # page here as a mean to catch - # srp authentication errors while - # we are still at one page's reach - # of the login credentials input page. - # (so we're able to go back an correct) + def fail(): + self.is_done = False + return False - step = "fetch_eipcert" - update_signal.emit('Validating credentials', 20) + yield(("head_sentinel", 0), lambda: None) - unamek = 'login_userName' - passwk = 'login_userPassword' + ######################## + # 1) fetch ca cert + ######################## - username = self.field(unamek) - password = self.field(passwk) - credentials = username, password - - ################# - # FIXME #BUG #638 - verify = False + def fetchcacert(): + if pconfig: + ca_cert_uri = pconfig.get('ca_cert_uri').geturl() + else: + ca_cert_uri = None + # XXX check scheme == "https" + # XXX passing verify == False because + # we have trusted right before. + # We should check it's the same domain!!! + # (Check with the trusted fingerprints dict + # or something smart) try: - pCertChecker.download_new_client_cert( - credentials=credentials, - verify=verify) + pCertChecker.download_ca_cert( + uri=ca_cert_uri, + verify=False) - except auth.SRPAuthenticationError as exc: - self.set_error( - step, - "Authentication error: %s" % exc.message) - return False + except baseexceptions.LeapException as exc: + logger.error(exc.message) + wizard.set_validation_error( + curpage, exc.usermessage) + return fail() - #pause_for_user() + except Exception as exc: + wizard.set_validation_error( + curpage, exc.message) + return fail() - ####################################### + else: + return True - update_signal.emit('Fetching CA certificate', 30) - #pause_for_user() + yield(('Fetching CA certificate', 30), fetchcacert) - if pconfig: - ca_cert_uri = pconfig.get('ca_cert_uri').geturl() - else: - ca_cert_uri = None + ######################### + # 2) check CA fingerprint + ######################### - # XXX check scheme == "https" - # XXX passing verify == False because - # we have trusted right before. - # We should check it's the same domain!!! - # (Check with the trusted fingerprints dict - # or something smart) - - pCertChecker.download_ca_cert( - uri=ca_cert_uri, - verify=False) - #pause_for_user() - - update_signal.emit('Checking CA fingerprint', 66) + def checkcafingerprint(): + # XXX get the real thing!!! + pass #ca_cert_fingerprint = pconfig.get('ca_cert_fingerprint', None) # XXX get fingerprint dict (types) @@ -115,33 +106,40 @@ class ProviderSetupValidationPage(ValidationPage): # should catch exception #return False - update_signal.emit('Validating api certificate', 90) - - #api_uri = pconfig.get('api_uri', None) - #try: - #api_cert_verified = pCertChecker.verify_api_https(api_uri) - #except requests.exceptions.SSLError as exc: - #logger.error('BUG #638. %s' % exc.message) - # XXX RAISE! See #638 - # bypassing until the hostname is fixed. - # We probably should raise yet-another-warning - # here saying user that the hostname "XX.XX.XX.XX' does not - # match 'foo.bar.baz' - #api_cert_verified = True - - #if not api_cert_verified: - # XXX update validationMsg - # should catch exception - #return False + yield((self.tr("Checking CA fingerprint"), 60), checkcafingerprint) + + ######################### + # 2) check CA fingerprint + ######################### + + def validatecacert(): + pass + #api_uri = pconfig.get('api_uri', None) + #try: + #api_cert_verified = pCertChecker.verify_api_https(api_uri) + #except requests.exceptions.SSLError as exc: + #logger.error('BUG #638. %s' % exc.message) + # XXX RAISE! See #638 + # bypassing until the hostname is fixed. + # We probably should raise yet-another-warning + # here saying user that the hostname "XX.XX.XX.XX' does not + # match 'foo.bar.baz' + #api_cert_verified = True + + #if not api_cert_verified: + # XXX update validationMsg + # should catch exception + #return False + + #??? + #ca_cert_path = checker.ca_cert_path - #pause_for_user() - #ca_cert_path = checker.ca_cert_path + yield((self.tr('Validating api certificate'), 90), validatecacert) self.set_done() - update_signal.emit('end_sentinel', 100) - #pause_for_user() + yield(('end_sentinel', 100), lambda: None) - def _do_validation(self): + def on_checks_validation_ready(self): """ called after _do_checks has finished (connected to checker thread finished signal) diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index f872a127..ddfcd1c5 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -2,7 +2,9 @@ Register User Page, used in First Run Wizard """ import logging +import socket +import requests from PyQt4 import QtCore from PyQt4 import QtGui @@ -11,31 +13,34 @@ from leap.gui.firstrun.mixins import UserFormMixIn logger = logging.getLogger(__name__) +from leap.base import auth from leap.gui.constants import APP_LOGO, BARE_USERNAME_REGEX +from leap.gui.progress import InlineValidationPage from leap.gui.styles import ErrorLabelStyleSheet -class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): +class RegisterUserPage(InlineValidationPage, UserFormMixIn): def __init__(self, parent=None): super(RegisterUserPage, self).__init__(parent) + self.current_page = "signup" - self.setTitle("Sign Up") + self.setTitle(self.tr("Sign Up")) + # subtitle is set in the initializePage self.setPixmap( QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) - self.current_page = "signup" - # commit page means there's no way back after this... # XXX should change the text on the "commit" button... self.setCommitPage(True) - self.initUI() + self.setupSteps() + self.setupUI() - def initUI(self): + def setupUI(self): userNameLabel = QtGui.QLabel("User &name:") userNameLineEdit = QtGui.QLineEdit() userNameLineEdit.cursorPositionChanged.connect( @@ -89,8 +94,18 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): layout.addWidget(self.userPasswordLineEdit, 2, 3) layout.addWidget(self.userPassword2LineEdit, 3, 3) layout.addWidget(rememberPasswordCheckBox, 4, 3, 4, 4) + + # add validation frame + self.setupValidationFrame() + layout.addWidget(self.valFrame, 5, 2, 5, 2) + self.valFrame.hide() + self.setLayout(layout) + # change "commit" button text + self.setButtonText( + QtGui.QWizard.CommitButton, "Sign up!") + # pagewizard methods def populateErrors(self): @@ -138,9 +153,6 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): super(RegisterUserPage, self).paintEvent(event) self.populateErrors() - def set_prevalidation_error(self, error): - self.prevalidation_error = error - def validatePage(self): """ we only pre-validate here password weakness @@ -150,33 +162,117 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): and if any errors are thrown there we come back and re-display the validation label. """ + # calls checks, which after successful + # execution will call on_checks_validation_ready + self.do_checks() + return self.is_done() + + def _do_checks(self): + """ + generator that yields actual checks + that are executed in a separate thread + """ + wizard = self.wizard() + curpage = self.current_page + senderr = lambda err: wizard.set_validation_error(curpage, err) - #username = self.userNameLineEdit.text() + provider = self.field('provider_domain') + username = self.userNameLineEdit.text() password = self.userPasswordLineEdit.text() password2 = self.userPassword2LineEdit.text() - # we better have here - # some call to a password checker... - # to assess strenght and avoid silly stuff. - - if password != password2: - self.set_prevalidation_error('Password does not match.') + def fail(): + self.set_undone() return False - if len(password) < 6: - self.set_prevalidation_error('Password too short.') - return False - - if password == "123456": - # joking, but not too much. - self.set_prevalidation_error('Password too obvious.') - return False - - # some cleanup before we leave the page - self.cleanup_errormsg() - - # go - return True + def checkpass(): + # we better have here + # some call to a password checker... + # to assess strenght and avoid silly stuff. + + if password != password2: + msg = self.tr('Password does not match..') + senderr(msg) + return fail() + + if len(password) < 6: + #self.set_prevalidation_error('Password too short.') + msg = self.tr('Password too short.') + senderr(msg) + return fail() + + if password == "123456": + # joking, but not too much. + #self.set_prevalidation_error('Password too obvious.') + msg = self.tr('Password too obvious.') + senderr(msg) + return fail() + + # go + return True + + yield(("head_sentinel", 0), checkpass) + + # XXX should emit signal for .show the frame! + # XXX HERE! + + ################################################## + # 1) register user + ################################################## + + def register(): + # XXX FIXME! + verify = False + + signup = auth.LeapSRPRegister( + schema="https", + provider=provider, + verify=verify) + try: + ok, req = signup.register_user( + username, password) + + except socket.timeout: + msg = self.tr("Error connecting to provider (timeout)") + senderr(msg) + return fail() + + except requests.exceptions.ConnectionError as exc: + logger.error(exc.message) + msg = self.tr('Error Connecting to provider (connerr).') + senderr(msg) + return fail() + + # XXX check for != OK instead??? + + if req.status_code in (404, 500): + msg = self.tr( + "Error during registration (%s)") % req.status_code + return fail() + + validation_msgs = json.loads(req.content) + errors = validation_msgs.get('errors', None) + logger.debug('validation errors: %s' % validation_msgs) + + if errors and errors.get('login', None): + # XXX this sometimes catch the blank username + # but we're not allowing that (soon) + msg = self.tr('Username not available.') + senderr(msg) + return fail() + + logger.debug('registering user') + yield(("registering with provider", 40), register) + + # set_done?? + self.set_done() + yield(("end_sentinel", 0), lambda: None) + + def on_checks_validation_ready(self): + + if self.is_done(): + self.cleanup_errormsg() + self.go_next() def initializePage(self): """ @@ -184,7 +280,7 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): """ provider = self.field('provider_domain') self.setSubTitle( - "Register a new user with provider %s." % + self.tr("Register a new user with provider %s.") % provider) self.validationMsg.setText('') self.userPassword2LineEdit.setText('') diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index 6db2bf6e..79971944 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -20,7 +20,7 @@ from leap.gui.progress import ValidationPage from leap.util.web import get_https_domain_and_port from leap.base import auth -from leap.gui.constants import APP_LOGO, pause_for_user +from leap.gui.constants import APP_LOGO logger = logging.getLogger(__name__) @@ -77,78 +77,8 @@ class RegisterUserValidationPage(ValidationPage): pCertChecker = wizard.providercertchecker( domain=full_domain) - ########################################### - # only if from signup - # MOVE TO SIGNUP PAGE... - if is_signup: - signup = auth.LeapSRPRegister( - schema="https", - provider=full_domain, - verify=verify) - update_signal.emit("head_sentinel", 0) - ################################################## - # 1) register user - ################################################## - # only if from signup. - # XXX MOVE THIS STEP TO SIGNUP-IN-PLACE VALIDATION - # WIDGET.......................................... - - if is_signup: - - step = "register" - update_signal.emit("checking availability", 20) - update_signal.emit("registering with provider", 40) - logger.debug('registering user') - - try: - ok, req = signup.register_user( - username, password) - - except socket.timeout: - self.set_error( - step, - "Error connecting to provider (timeout)") - #pause_for_user() - return False - - except requests.exceptions.ConnectionError as exc: - logger.error(exc.message) - self.set_error( - step, - "Error connecting to provider " - "(connection error)") - # XXX we should signal a BAD step - #pause_for_user() - update_signal.emit("connection error!", 50) - #pause_for_user() - return False - - # XXX check for != OK instead??? - - if req.status_code in (404, 500): - self.set_error( - step, - "Error during registration (%s)" % req.status_code) - pause_for_user() - return False - - validation_msgs = json.loads(req.content) - errors = validation_msgs.get('errors', None) - logger.debug('validation errors: %s' % validation_msgs) - - if errors and errors.get('login', None): - # XXX this sometimes catch the blank username - # but we're not allowing that (soon) - self.set_error( - step, - 'Username not available.') - #pause_for_user() - return False - - #pause_for_user() - ################################################## # 2) fetching eip service config ################################################## @@ -202,6 +132,13 @@ class RegisterUserValidationPage(ValidationPage): # this should be called CONNECT PAGE AGAIN. self.run_eip_checks_for_provider_and_connect(_domain) + def on_checks_validation_ready(self): + """ + called after _do_checks has finished + (connected to checker thread finished signal) + """ + pass + def run_eip_checks_for_provider_and_connect(self, domain): wizard = self.wizard() conductor = wizard.conductor diff --git a/src/leap/gui/firstrun/wizard.py b/src/leap/gui/firstrun/wizard.py index 4a72177e..2ee1947a 100755 --- a/src/leap/gui/firstrun/wizard.py +++ b/src/leap/gui/firstrun/wizard.py @@ -139,6 +139,7 @@ class FirstRunWizard(QtGui.QWizard): # set options self.setOption(QtGui.QWizard.IndependentPages, on=False) + self.setOption(QtGui.QWizard.NoBackButtonOnStartPage, on=True) self.setWindowTitle("First Run Wizard") -- cgit v1.2.3 From d5136a5f3b2aa8b16e8341f2eb99d05993028acf Mon Sep 17 00:00:00 2001 From: kali Date: Tue, 27 Nov 2012 00:12:22 +0900 Subject: inline validation at register page. inline widget and focus and red marks and whistles. --- src/leap/gui/firstrun/providerselect.py | 58 ++++------- src/leap/gui/firstrun/providersetup.py | 23 ++-- src/leap/gui/firstrun/register.py | 179 +++++++++++++++++++++++--------- src/leap/gui/firstrun/regvalidation.py | 80 +++++++------- src/leap/gui/firstrun/wizard.py | 2 +- 5 files changed, 194 insertions(+), 148 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index dffde040..e59a23a9 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -169,7 +169,7 @@ class SelectProviderPage(InlineValidationPage): @QtCore.pyqtSlot() def onDisableCheckButton(self): - print 'CHECK BUTTON DISABLED!!!' + #print 'CHECK BUTTON DISABLED!!!' self.providerCheckButton.setDisabled(True) @QtCore.pyqtSlot() @@ -183,6 +183,8 @@ class SelectProviderPage(InlineValidationPage): QtCore.QMetaObject.invokeMethod( self, "showStepsFrame") + # is this still needed? + # XXX can I doo delay(self, "do_checks") ? delay(self, "launch_checks") def _do_checks(self): @@ -192,8 +194,6 @@ class SelectProviderPage(InlineValidationPage): """ wizard = self.wizard() - curpage = "providerselection" - full_domain = self.providerNameEdit.text() # we check if we have a port in the domain string. @@ -205,10 +205,6 @@ class SelectProviderPage(InlineValidationPage): providercertchecker = wizard.providercertchecker() eipconfigchecker = wizard.eipconfigchecker(domain=_domain) - def fail(): - self.is_done = False - return False - yield(("head_sentinel", 0), lambda: None) ######################## @@ -227,20 +223,16 @@ class SelectProviderPage(InlineValidationPage): except baseexceptions.LeapException as exc: logger.error(exc.message) - wizard.set_validation_error( - curpage, exc.usermessage) - return fail() + return self.fail(exc.usermessage) except Exception as exc: - wizard.set_validation_error( - curpage, exc.message) - return fail() + return self.fail(exc.message) else: return True logger.debug('checking name resolution') - yield(("check name", 20), namecheck) + yield((self.tr("checking domain name"), 20), namecheck) ######################### # 2) try https connection @@ -260,6 +252,7 @@ class SelectProviderPage(InlineValidationPage): except eipexceptions.HttpsBadCertError as exc: logger.debug('exception') + return self.fail(exc.usermessage) # XXX skipping for now... ############################################## # We had this validation logic @@ -268,8 +261,6 @@ class SelectProviderPage(InlineValidationPage): #if self.trustProviderCertCheckBox.isChecked(): #pass #else: - wizard.set_validation_error( - curpage, exc.usermessage) #fingerprint = certs.get_cert_fingerprint( #domain=domain, sep=" ") @@ -284,23 +275,18 @@ class SelectProviderPage(InlineValidationPage): #self.did_cert_check = True #self.completeChanged.emit() #return False - return fail() except baseexceptions.LeapException as exc: - wizard.set_validation_error( - curpage, exc.usermessage) - return fail() + return self.fail(exc.usermessage) except Exception as exc: - wizard.set_validation_error( - curpage, exc.message) - return fail() + return self.fail(exc.message) else: return True logger.debug('checking https connection') - yield(("https check", 40), httpscheck) + yield((self.tr("checking https connection"), 40), httpscheck) ################################## # 3) try download provider info... @@ -316,28 +302,20 @@ class SelectProviderPage(InlineValidationPage): except requests.exceptions.SSLError: # XXX we should have catched this before. # but cert checking is broken. - wizard.set_validation_error( - curpage, - self.tr( - "Could not get info from provider.")) - return fail() + return self.fail(self.tr( + "Could not get info from provider.")) except requests.exceptions.ConnectionError: - wizard.set_validation_error( - curpage, - self.tr( - "Could not download provider info " - "(refused conn.).")) - return fail() + return self.fail(self.tr( + "Could not download provider info " + "(refused conn.).")) except Exception as exc: - wizard.set_validation_error( - curpage, exc.message) - return fail() - + return self.fail( + self.tr(exc.message)) else: return True - yield(("fetch info", 80), fetchinfo) + yield((self.tr("fetching provider info"), 80), fetchinfo) # done! diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index 7904538d..1a362794 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -17,6 +17,9 @@ logger = logging.getLogger(__name__) class ProviderSetupValidationPage(ValidationPage): def __init__(self, parent=None): super(ProviderSetupValidationPage, self).__init__(parent) + self.current_page = "providersetupvalidation" + + # XXX needed anymore? is_signup = self.field("is_signup") self.is_signup = is_signup @@ -33,7 +36,6 @@ class ProviderSetupValidationPage(ValidationPage): generator that yields actual checks that are executed in a separate thread """ - curpage = "providersetupvalidation" full_domain = self.field('provider_domain') wizard = self.wizard() @@ -44,10 +46,6 @@ class ProviderSetupValidationPage(ValidationPage): pCertChecker = wizard.providercertchecker( domain=full_domain) - def fail(): - self.is_done = False - return False - yield(("head_sentinel", 0), lambda: None) ######################## @@ -73,19 +71,17 @@ class ProviderSetupValidationPage(ValidationPage): except baseexceptions.LeapException as exc: logger.error(exc.message) - wizard.set_validation_error( - curpage, exc.usermessage) - return fail() + # XXX this should be _ method + return self.fail(self.tr(exc.usermessage)) except Exception as exc: - wizard.set_validation_error( - curpage, exc.message) - return fail() + return self.fail(exc.message) else: return True - yield(('Fetching CA certificate', 30), fetchcacert) + yield((self.tr('Fetching CA certificate'), 30), + fetchcacert) ######################### # 2) check CA fingerprint @@ -106,7 +102,8 @@ class ProviderSetupValidationPage(ValidationPage): # should catch exception #return False - yield((self.tr("Checking CA fingerprint"), 60), checkcafingerprint) + yield((self.tr("Checking CA fingerprint"), 60), + checkcafingerprint) ######################### # 2) check CA fingerprint diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index ddfcd1c5..7ce74892 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -1,6 +1,7 @@ """ Register User Page, used in First Run Wizard """ +import json import logging import socket @@ -14,6 +15,7 @@ from leap.gui.firstrun.mixins import UserFormMixIn logger = logging.getLogger(__name__) from leap.base import auth +from leap.gui import styles from leap.gui.constants import APP_LOGO, BARE_USERNAME_REGEX from leap.gui.progress import InlineValidationPage from leap.gui.styles import ErrorLabelStyleSheet @@ -39,6 +41,8 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): self.setupSteps() self.setupUI() + self.do_confirm_next = False + self.focused_field = False def setupUI(self): userNameLabel = QtGui.QLabel("User &name:") @@ -101,23 +105,64 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): self.valFrame.hide() self.setLayout(layout) + self.commitText("Sign up!") + # commit button + + def commitText(self, text): # change "commit" button text self.setButtonText( - QtGui.QWizard.CommitButton, "Sign up!") + QtGui.QWizard.CommitButton, text) - # pagewizard methods + @property + def commitButton(self): + return self.wizard().button(QtGui.QWizard.CommitButton) + + def commitFocus(self): + self.commitButton.setFocus() + + def disableCommitButton(self): + self.commitButton.setDisabled(True) + + def disableFields(self): + for field in (self.userNameLineEdit, + self.userPasswordLineEdit, + self.userPassword2LineEdit): + field.setDisabled(True) + + # error painting + + def markRedAndGetFocus(self, field): + field.setStyleSheet(styles.ErrorLineEdit) + if not self.focused_field: + self.focused_field = True + field.setFocus(QtCore.Qt.OtherFocusReason) + + def markRegular(self, field): + field.setStyleSheet(styles.RegularLineEdit) def populateErrors(self): - # XXX could move this to ValidationMixin - # used in providerselect too + def showerr(text): + self.validationMsg.setText(text) + err_lower = text.lower() + if "username" in err_lower: + self.markRedAndGetFocus( + self.userNameLineEdit) + if "password" in err_lower: + self.markRedAndGetFocus( + self.userPasswordLineEdit) + + def unmarkred(): + for field in (self.userNameLineEdit, + self.userPasswordLineEdit, + self.userPassword2LineEdit): + self.markRegular(field) errors = self.wizard().get_validation_error( self.current_page) if errors: bad_str = getattr(self, 'bad_string', None) cur_str = self.userNameLineEdit.text() - showerr = self.validationMsg.setText prev_er = getattr(self, 'prevalidation_error', None) if bad_str is None: @@ -133,7 +178,13 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): if cur_str == bad_str: showerr(errors) else: + self.focused_field = False showerr('') + unmarkred() + else: + # no errors + self.focused_field = False + unmarkred() def cleanup_errormsg(self): """ @@ -153,60 +204,32 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): super(RegisterUserPage, self).paintEvent(event) self.populateErrors() - def validatePage(self): - """ - we only pre-validate here password weakness - stuff, or any other client side validation - that we think of. - real server validation is made on next page, - and if any errors are thrown there we come back - and re-display the validation label. - """ - # calls checks, which after successful - # execution will call on_checks_validation_ready - self.do_checks() - return self.is_done() - def _do_checks(self): """ generator that yields actual checks that are executed in a separate thread """ - wizard = self.wizard() - curpage = self.current_page - senderr = lambda err: wizard.set_validation_error(curpage, err) - provider = self.field('provider_domain') username = self.userNameLineEdit.text() password = self.userPasswordLineEdit.text() password2 = self.userPassword2LineEdit.text() - def fail(): - self.set_undone() - return False - def checkpass(): # we better have here # some call to a password checker... # to assess strenght and avoid silly stuff. if password != password2: - msg = self.tr('Password does not match..') - senderr(msg) - return fail() + return self.fail(self.tr('Password does not match..')) if len(password) < 6: #self.set_prevalidation_error('Password too short.') - msg = self.tr('Password too short.') - senderr(msg) - return fail() + return self.fail(self.tr('Password too short.')) if password == "123456": # joking, but not too much. #self.set_prevalidation_error('Password too obvious.') - msg = self.tr('Password too obvious.') - senderr(msg) - return fail() + return self.fail(self.tr('Password too obvious.')) # go return True @@ -220,6 +243,10 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): # 1) register user ################################################## + # show the frame before going on... + QtCore.QMetaObject.invokeMethod( + self, "showStepsFrame") + def register(): # XXX FIXME! verify = False @@ -233,22 +260,22 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): username, password) except socket.timeout: - msg = self.tr("Error connecting to provider (timeout)") - senderr(msg) - return fail() + return self.fail( + self.tr("Error connecting to provider (timeout)")) except requests.exceptions.ConnectionError as exc: logger.error(exc.message) - msg = self.tr('Error Connecting to provider (connerr).') - senderr(msg) - return fail() + return self.fail( + self.tr('Error Connecting to provider (connerr).')) + except Exception as exc: + return self.fail(exc.message) # XXX check for != OK instead??? if req.status_code in (404, 500): - msg = self.tr( - "Error during registration (%s)") % req.status_code - return fail() + return self.fail( + self.tr( + "Error during registration (%s)") % req.status_code) validation_msgs = json.loads(req.content) errors = validation_msgs.get('errors', None) @@ -257,9 +284,8 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): if errors and errors.get('login', None): # XXX this sometimes catch the blank username # but we're not allowing that (soon) - msg = self.tr('Username not available.') - senderr(msg) - return fail() + return self.fail( + self.tr('Username not available.')) logger.debug('registering user') yield(("registering with provider", 40), register) @@ -269,10 +295,61 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): yield(("end_sentinel", 0), lambda: None) def on_checks_validation_ready(self): - + """ + after checks + """ if self.is_done(): + # XXX should disable + # all entry forms + self.disableFields() self.cleanup_errormsg() - self.go_next() + self.clean_wizard_errors(self.current_page) + # make the user confirm the transition + # to next page. + self.commitText('Connect!') + self.commitFocus() + self.green_validation_status() + self.do_confirm_next = True + + def green_validation_status(self): + val = self.validationMsg + val.setText(self.tr('Registration succeeded!')) + val.setStyleSheet(styles.GreenLineEdit) + + def reset_validation_status(self): + """ + empty the validation msg + and clean the inline validation widget. + """ + self.validationMsg.setText('') + self.steps.removeAllSteps() + self.clearTable() + + # pagewizard methods + + def validatePage(self): + """ + if not register done, do checks. + if done, wait for click. + """ + self.disableCommitButton() + self.cleanup_errormsg() + self.clean_wizard_errors(self.current_page) + + # After a successful validation + # (ie, success register with server) + # we change the commit button text + # and set this flag to True. + if self.do_confirm_next: + return True + + if not self.is_done(): + # calls checks, which after successful + # execution will call on_checks_validation_ready + self.reset_validation_status() + self.do_checks() + + return self.is_done() def initializePage(self): """ @@ -284,9 +361,11 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): provider) self.validationMsg.setText('') self.userPassword2LineEdit.setText('') + self.valFrame.hide() def nextId(self): wizard = self.wizard() if not wizard: return + # XXX this should be called connect return wizard.get_page_index('signupvalidation') diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index 79971944..0e67834b 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -9,12 +9,12 @@ used in First Run Wizard # the login branch of the wizard. import logging -import json -import socket +#import json +#import socket from PyQt4 import QtGui -import requests +#import requests from leap.gui.progress import ValidationPage from leap.util.web import get_https_domain_and_port @@ -77,67 +77,59 @@ class RegisterUserValidationPage(ValidationPage): pCertChecker = wizard.providercertchecker( domain=full_domain) - update_signal.emit("head_sentinel", 0) + yield(("head_sentinel", 0), lambda: None) ################################################## - # 2) fetching eip service config + # 1) fetching eip service config ################################################## + def fetcheipconf(): + try: + eipconfigchecker.fetch_eip_service_config( + domain=full_domain) - step = "fetch_eipconf" - fetching_eipconf_msg = "Fetching eip service configuration" - update_signal.emit(fetching_eipconf_msg, 60) - try: - eipconfigchecker.fetch_eip_service_config( - domain=full_domain) - - # XXX get specific exception - except: - self.set_error( - step, - 'Could not download eip config.') - #pause_for_user() - return False - #pause_for_user() + # XXX get specific exception + except Exception as exc: + return self.fail(exc.message) + + yield((self.tr("Fetching provider config..."), 40), + fetcheipconf) ################################################## - # 3) getting client certificate + # 2) getting client certificate ################################################## - # XXX maybe only do this if we come from signup - - step = "fetch_eipcert" - fetching_clientcert_msg = "Fetching eip certificate" - update_signal.emit(fetching_clientcert_msg, 80) - try: - pCertChecker.download_new_client_cert( - credentials=credentials, - verify=verify) + def fetcheipcert(): + try: + pCertChecker.download_new_client_cert( + credentials=credentials, + verify=verify) - except auth.SRPAuthenticationError as exc: - self.set_error( - step, - "Authentication error: %s" % exc.message) - return False + except auth.SRPAuthenticationError as exc: + return self.fail(self.tr( + "Authentication error: %s" % exc.message)) + else: + return True - #pause_for_user() + yield((self.tr("Fetching eip certificate"), 80), + fetcheipcert) ################ # end ! ################ - - update_signal.emit("end_sentinel", 100) - #pause_for_user() - - # here we go! :) - # this should be called CONNECT PAGE AGAIN. - self.run_eip_checks_for_provider_and_connect(_domain) + self.set_done() + yield(("end_sentinel", 100), lambda: None) def on_checks_validation_ready(self): """ called after _do_checks has finished (connected to checker thread finished signal) """ - pass + # this should be called CONNECT PAGE AGAIN. + # here we go! :) + full_domain = self.field('provider_domain') + domain, port = get_https_domain_and_port(full_domain) + _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain) + self.run_eip_checks_for_provider_and_connect(_domain) def run_eip_checks_for_provider_and_connect(self, domain): wizard = self.wizard() diff --git a/src/leap/gui/firstrun/wizard.py b/src/leap/gui/firstrun/wizard.py index 2ee1947a..9b77b877 100755 --- a/src/leap/gui/firstrun/wizard.py +++ b/src/leap/gui/firstrun/wizard.py @@ -39,7 +39,7 @@ TODO-ish: [ ] Document signals used / expected. [ ] Separate style from widgets. [ ] Fix TOFU Widget for provider cert. -[ ] Refactor widgets out. +[X] Refactor widgets out. [ ] Follow more MVC style. [ ] Maybe separate "first run wizard" into different wizards that share some of the pages? -- cgit v1.2.3 From 1bb7e85425f2f427401cd02726c55922874a59a0 Mon Sep 17 00:00:00 2001 From: kali Date: Tue, 27 Nov 2012 03:34:08 +0900 Subject: login validation inline --- src/leap/gui/firstrun/last.py | 2 + src/leap/gui/firstrun/login.py | 242 +++++++++++++++++++++----------- src/leap/gui/firstrun/providerselect.py | 4 +- src/leap/gui/firstrun/register.py | 11 +- 4 files changed, 165 insertions(+), 94 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/last.py b/src/leap/gui/firstrun/last.py index 13b2f548..d33d2e77 100644 --- a/src/leap/gui/firstrun/last.py +++ b/src/leap/gui/firstrun/last.py @@ -78,6 +78,8 @@ class LastPage(QtGui.QWizardPage): break except GeneratorExit: pass + except StopIteration: + pass def initializePage(self): wizard = self.wizard() diff --git a/src/leap/gui/firstrun/login.py b/src/leap/gui/firstrun/login.py index 3a6ec089..02bace86 100644 --- a/src/leap/gui/firstrun/login.py +++ b/src/leap/gui/firstrun/login.py @@ -4,20 +4,22 @@ LogIn Page, used inf First Run Wizard from PyQt4 import QtCore from PyQt4 import QtGui -#import requests +import requests from leap.base import auth from leap.gui.firstrun.mixins import UserFormMixIn +from leap.gui.progress import InlineValidationPage +from leap.gui import styles from leap.gui.constants import APP_LOGO, FULL_USERNAME_REGEX -from leap.gui.styles import ErrorLabelStyleSheet -class LogInPage(QtGui.QWizardPage, UserFormMixIn): # InlineValidationPage +class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage def __init__(self, parent=None): super(LogInPage, self).__init__(parent) + self.current_page = "login" self.setTitle("Log In") self.setSubTitle("Log in with your credentials.") @@ -27,8 +29,11 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): # InlineValidationPage QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) + self.setupSteps() self.setupUI() + self.do_confirm_next = False + def setupUI(self): userNameLabel = QtGui.QLabel("User &name:") userNameLineEdit = QtGui.QLineEdit() @@ -40,6 +45,9 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): # InlineValidationPage usernameRe = QtCore.QRegExp(FULL_USERNAME_REGEX) userNameLineEdit.setValidator( QtGui.QRegExpValidator(usernameRe, self)) + + #userNameLineEdit.setPlaceholderText( + #'username@provider.example.org') self.userNameLineEdit = userNameLineEdit userPasswordLabel = QtGui.QLabel("&Password:") @@ -55,7 +63,7 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): # InlineValidationPage layout.setColumnMinimumWidth(0, 20) validationMsg = QtGui.QLabel("") - validationMsg.setStyleSheet(ErrorLabelStyleSheet) + validationMsg.setStyleSheet(styles.ErrorLabelStyleSheet) self.validationMsg = validationMsg layout.addWidget(validationMsg, 0, 3) @@ -64,18 +72,38 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): # InlineValidationPage layout.addWidget(userPasswordLabel, 2, 0) layout.addWidget(self.userPasswordLineEdit, 2, 3) + # add validation frame + self.setupValidationFrame() + layout.addWidget(self.valFrame, 4, 2, 4, 2) + self.valFrame.hide() + + self.nextText("Log in") self.setLayout(layout) #self.registerField('is_login_wizard') + def nextText(self, text): + self.setButtonText( + QtGui.QWizard.NextButton, text) + + def nextFocus(self): + self.wizard().button( + QtGui.QWizard.NextButton).setFocus() + + def disableNextButton(self): + self.wizard().button( + QtGui.QWizard.NextButton).setDisabled(True) + def onUserNameEdit(self, *args): if self.initial_username_sample: self.userNameLineEdit.setText('') + # XXX set regular color self.initial_username_sample = None - # pagewizard methods - - #### begin possible refactor + def disableFields(self): + for field in (self.userNameLineEdit, + self.userPasswordLineEdit): + field.setDisabled(True) def populateErrors(self): # XXX could move this to ValidationMixin @@ -83,13 +111,13 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): # InlineValidationPage errors = self.wizard().get_validation_error( self.current_page) - prev_er = getattr(self, 'prevalidation_error', None) + #prev_er = getattr(self, 'prevalidation_error', None) showerr = self.validationMsg.setText - if not errors and prev_er: - showerr(prev_er) - return - + #if not errors and prev_er: + #showerr(prev_er) + #return +# if errors: bad_str = getattr(self, 'bad_string', None) cur_str = self.userNameLineEdit.text() @@ -100,13 +128,14 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): # InlineValidationPage self.bad_string = cur_str showerr(errors) else: - if prev_er: - showerr(prev_er) - return + #if prev_er: + #showerr(prev_er) + #return # not the first time if cur_str == bad_str: showerr(errors) else: + self.focused_field = False showerr('') def cleanup_errormsg(self): @@ -130,7 +159,7 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): # InlineValidationPage def set_prevalidation_error(self, error): self.prevalidation_error = error - #### end possible refactor + # pagewizard methods def nextId(self): wizard = self.wizard() @@ -145,95 +174,115 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): # InlineValidationPage def initializePage(self): super(LogInPage, self).initializePage() - # XXX setPlaceholderText instead?! - self.userNameLineEdit.setText('username@provider.example.org') - self.userNameLineEdit.cursorPositionChanged.connect( + username = self.userNameLineEdit + username.setText('username@provider.example.org') + username.cursorPositionChanged.connect( self.onUserNameEdit) self.initial_username_sample = True + self.validationMsg.setText('') + self.valFrame.hide() - def validatePage(self): - #wizard = self.wizard() - #eipconfigchecker = wizard.eipconfigchecker() + def reset_validation_status(self): + """ + empty the validation msg + and clean the inline validation widget. + """ + self.validationMsg.setText('') + self.steps.removeAllSteps() + self.clearTable() - # XXX should move to _do_checks - full_username = self.userNameLineEdit.text() - password = self.userPasswordLineEdit.text() - if full_username.count('@') != 1: - self.set_prevalidation_error( - "Username must be in the username@provider form.") - return False + def validatePage(self): + """ + if not register done, do checks. + if done, wait for click. + """ + self.disableNextButton() + self.cleanup_errormsg() + self.clean_wizard_errors(self.current_page) - username, domain = full_username.split('@') - self.setField('provider_domain', domain) - self.setField('login_userName', username) - self.setField('login_userPassword', password) - - #################################################### - # Validation logic: - # move to provider setup page - #################################################### - # Able to contact domain? - # can get definition? - # two-by-one - #try: - #eipconfigchecker.fetch_definition(domain=domain) -# - # we're using requests here for all - # the possible error cases that it catches. - #except requests.exceptions.ConnectionError as exc: - #self.set_validation_status(exc.message[1]) - #return False - #except requests.exceptions.HTTPError as exc: - #self.set_validation_status(exc.message) - #return False - #wizard.set_providerconfig( - #eipconfigchecker.defaultprovider.config) - #################################################### + if self.do_confirm_next: + full_username = self.userNameLineEdit.text() + password = self.userPasswordLineEdit.text() + username, domain = full_username.split('@') + self.setField('provider_domain', domain) + self.setField('login_userName', username) + self.setField('login_userPassword', password) - # XXX I think this is not needed - # since we're also checking for the is_signup field. - self.wizard().from_login = True + return True - # some cleanup before we leave the page - self.cleanup_errormsg() + if not self.is_done(): + self.reset_validation_status() + self.do_checks() - return True + return self.is_done() def _do_checks(self): # XXX convert this to inline full_username = self.userNameLineEdit.text() - password = self.userPasswordLineEdit.text() + ########################### + # 0) check user@domain form + ########################### + + def checkusername(): + if full_username.count('@') != 1: + return self.fail( + self.tr( + "Username must be in the username@provider form.")) + else: + return True + + yield(("head_sentinel", 0), checkusername) + + # XXX I think this is not needed + # since we're also checking for the is_signup field. + #self.wizard().from_login = True + username, domain = full_username.split('@') + password = self.userPasswordLineEdit.text() + # We try a call to an authenticated # page here as a mean to catch # srp authentication errors while wizard = self.wizard() - pCertChecker = wizard.providercertchecker( - domain=domain) - - curpage = "login" - - def fail(): - self.is_done = False - return False + eipconfigchecker = wizard.eipconfigchecker() ######################## # 1) try name resolution ######################## - # XXX - # bring here from validation above... + # show the frame before going on... + QtCore.QMetaObject.invokeMethod( + self, "showStepsFrame") + + # Able to contact domain? + # can get definition? + # two-by-one + def resolvedomain(): + try: + eipconfigchecker.fetch_definition(domain=domain) + + # we're using requests here for all + # the possible error cases that it catches. + except requests.exceptions.ConnectionError as exc: + return self.fail(exc.message[1]) + except requests.exceptions.HTTPError as exc: + return self.fail(exc.message) + except Exception as exc: + # XXX get catchall error msg + return self.fail( + exc.message) + + yield((self.tr("resolving domain name"), 20), resolvedomain) + + wizard.set_providerconfig( + eipconfigchecker.defaultprovider.config) ######################## # 2) do authentication ######################## - - unamek = 'login_userName' - passwk = 'login_userPassword' - - username = self.field(unamek) - password = self.field(passwk) credentials = username, password + pCertChecker = wizard.providercertchecker( + domain=domain) def validate_credentials(): ################# @@ -246,13 +295,36 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): # InlineValidationPage verify=verify) except auth.SRPAuthenticationError as exc: - wizard.set_validation_error( - curpage, "Authentication error: %s" % exc.usermessage) - return fail() + return self.fail( + self.tr("Authentication error: %s" % exc.message)) except Exception as exc: - wizard.set_validation_error( - curpage, "%s" % exc.message) - return fail() + return self.fail(exc.message) - yield(('Validating credentials', 20), lambda: None) + else: + return True + + yield(('Validating credentials', 20), validate_credentials) + + self.set_done() + yield(("end_sentinel", 0), lambda: None) + + def green_validation_status(self): + val = self.validationMsg + val.setText(self.tr('Credentials validated.')) + val.setStyleSheet(styles.GreenLineEdit) + + def on_checks_validation_ready(self): + """ + after checks + """ + if self.is_done(): + self.disableFields() + self.cleanup_errormsg() + self.clean_wizard_errors(self.current_page) + # make the user confirm the transition + # to next page. + self.nextText('&Next') + self.nextFocus() + self.green_validation_status() + self.do_confirm_next = True diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index e59a23a9..3ffc6ff6 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -11,12 +11,12 @@ from PyQt4 import QtGui from leap.base import exceptions as baseexceptions #from leap.crypto import certs from leap.eip import exceptions as eipexceptions - -from leap.gui.constants import APP_LOGO from leap.gui.progress import InlineValidationPage from leap.gui import styles from leap.util.web import get_https_domain_and_port +from leap.gui.constants import APP_LOGO + logger = logging.getLogger(__name__) diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index 7ce74892..e85723cb 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -163,7 +163,7 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): if errors: bad_str = getattr(self, 'bad_string', None) cur_str = self.userNameLineEdit.text() - prev_er = getattr(self, 'prevalidation_error', None) + #prev_er = getattr(self, 'prevalidation_error', None) if bad_str is None: # first time we fall here. @@ -171,9 +171,9 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): self.bad_string = cur_str showerr(errors) else: - if prev_er: - showerr(prev_er) - return + #if prev_er: + #showerr(prev_er) + #return # not the first time if cur_str == bad_str: showerr(errors) @@ -290,7 +290,6 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): logger.debug('registering user') yield(("registering with provider", 40), register) - # set_done?? self.set_done() yield(("end_sentinel", 0), lambda: None) @@ -299,8 +298,6 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): after checks """ if self.is_done(): - # XXX should disable - # all entry forms self.disableFields() self.cleanup_errormsg() self.clean_wizard_errors(self.current_page) -- cgit v1.2.3 From eec567a0a26edddb30b15ea4ef67f042c160d5ba Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 28 Nov 2012 02:03:22 +0900 Subject: move delay function to gui/utils --- src/leap/gui/firstrun/providerselect.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index 3ffc6ff6..a4be51a9 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -13,6 +13,7 @@ from leap.base import exceptions as baseexceptions from leap.eip import exceptions as eipexceptions from leap.gui.progress import InlineValidationPage from leap.gui import styles +from leap.gui.utils import delay from leap.util.web import get_https_domain_and_port from leap.gui.constants import APP_LOGO @@ -20,20 +21,8 @@ from leap.gui.constants import APP_LOGO logger = logging.getLogger(__name__) -def delay(obj, method_str): - # XXX check newer version in progress.py... - """ - this is a hack to get responsiveness in the ui - """ - QtCore.QTimer().singleShot( - 10, - lambda: QtCore.QMetaObject.invokeMethod( - obj, method_str)) - - class SelectProviderPage(InlineValidationPage): - #disableCheckButton = QtCore.pyqtSignal() launchChecks = QtCore.pyqtSignal() def __init__(self, parent=None, providers=None): @@ -183,8 +172,6 @@ class SelectProviderPage(InlineValidationPage): QtCore.QMetaObject.invokeMethod( self, "showStepsFrame") - # is this still needed? - # XXX can I doo delay(self, "do_checks") ? delay(self, "launch_checks") def _do_checks(self): -- cgit v1.2.3 From 490cde9c33039c2c5b16d929d6f8bb8e8f06f430 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 5 Dec 2012 23:50:08 +0900 Subject: tests for firstrun/wizard --- src/leap/gui/firstrun/__init__.py | 2 +- src/leap/gui/firstrun/wizard.py | 56 ++++++++++++++++++++++++++------------- 2 files changed, 38 insertions(+), 20 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/__init__.py b/src/leap/gui/firstrun/__init__.py index 8a70d90e..a2ca704d 100644 --- a/src/leap/gui/firstrun/__init__.py +++ b/src/leap/gui/firstrun/__init__.py @@ -26,4 +26,4 @@ __all__ = [ 'providerselect', 'providersetup', 'register', - 'regvalidation'] + 'regvalidation'] # ,'wizard'] diff --git a/src/leap/gui/firstrun/wizard.py b/src/leap/gui/firstrun/wizard.py index 9b77b877..bd3fe903 100755 --- a/src/leap/gui/firstrun/wizard.py +++ b/src/leap/gui/firstrun/wizard.py @@ -2,8 +2,11 @@ import logging import sip -sip.setapi('QString', 2) -sip.setapi('QVariant', 2) +try: + sip.setapi('QString', 2) + sip.setapi('QVariant', 2) +except ValueError: + pass from PyQt4 import QtCore from PyQt4 import QtGui @@ -146,6 +149,10 @@ class FirstRunWizard(QtGui.QWizard): # TODO: set style for MAC / windows ... #self.setWizardStyle() + # + # setup pages in wizard + # + def add_pages_from_dict(self, pages_dict): """ @param pages_dict: the dictionary with pages, where @@ -168,6 +175,10 @@ class FirstRunWizard(QtGui.QWizard): """ return self.pages_dict.keys().index(page_name) + # + # validation errors + # + def set_validation_error(self, pagename, error): self.validation_errors[pagename] = error @@ -179,20 +190,6 @@ class FirstRunWizard(QtGui.QWizard): def get_validation_error(self, pagename): return self.validation_errors.get(pagename, None) - def set_providerconfig(self, providerconfig): - self.providerconfig = providerconfig - - def setWindowFlags(self, flags): - logger.debug('setting window flags') - QtGui.QWizard.setWindowFlags(self, flags) - - def focusOutEvent(self, event): - # needed ? - self.setFocus(True) - self.activateWindow() - self.raise_() - self.show() - def accept(self): """ final step in the wizard. @@ -246,11 +243,14 @@ class FirstRunWizard(QtGui.QWizard): if cb and callable(cb): self.success_cb() - def get_provider_by_index(self): - provider = self.field('provider_index') - return self.providers[provider] + # misc helpers def get_random_str(self, n): + """ + returns a random string + :param n: the length of the desired string + :rvalue: str + """ from string import (ascii_uppercase, ascii_lowercase, digits) from random import choice return ''.join(choice( @@ -258,6 +258,24 @@ class FirstRunWizard(QtGui.QWizard): ascii_lowercase + digits) for x in range(n)) + def set_providerconfig(self, providerconfig): + """ + sets a providerconfig attribute + used when we fetch and parse a json configuration + """ + self.providerconfig = providerconfig + + def get_provider_by_index(self): # pragma: no cover + """ + returns the value of a provider given its index. + this was used in the select provider page, + in the case where we were preseeding providers in a combobox + """ + # Leaving it here for the moment when we go back at the + # option of preseeding with known provider values. + provider = self.field('provider_index') + return self.providers[provider] + if __name__ == '__main__': # standalone test -- cgit v1.2.3 From f40bfa7b674418f9903e826d20ad943efcc47807 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 7 Dec 2012 02:16:25 +0900 Subject: register tests --- src/leap/gui/firstrun/__init__.py | 2 - src/leap/gui/firstrun/connect.py | 231 -------------------------------- src/leap/gui/firstrun/providerselect.py | 22 +-- src/leap/gui/firstrun/register.py | 82 +++++++----- src/leap/gui/firstrun/wizard.py | 32 +++-- 5 files changed, 81 insertions(+), 288 deletions(-) delete mode 100644 src/leap/gui/firstrun/connect.py (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/__init__.py b/src/leap/gui/firstrun/__init__.py index a2ca704d..d380b75a 100644 --- a/src/leap/gui/firstrun/__init__.py +++ b/src/leap/gui/firstrun/__init__.py @@ -5,7 +5,6 @@ try: except ValueError: pass -import connect import intro import last import login @@ -17,7 +16,6 @@ import register import regvalidation __all__ = [ - 'connect', 'intro', 'last', 'login', diff --git a/src/leap/gui/firstrun/connect.py b/src/leap/gui/firstrun/connect.py deleted file mode 100644 index a0fe021c..00000000 --- a/src/leap/gui/firstrun/connect.py +++ /dev/null @@ -1,231 +0,0 @@ -""" -Connecting Page, used in First Run Wizard -""" -# XXX FIXME -# DEPRECATED. All functionality moved to regvalidation -# This file should be removed after checking that one is ok. -# XXX - -import logging - -from PyQt4 import QtGui - -logger = logging.getLogger(__name__) - -from leap.base import auth - -from leap.gui.constants import APP_LOGO -from leap.gui.styles import ErrorLabelStyleSheet - - -class ConnectingPage(QtGui.QWizardPage): - - # XXX change to a ValidationPage - - def __init__(self, parent=None): - super(ConnectingPage, self).__init__(parent) - - self.setTitle("Connecting") - self.setSubTitle('Connecting to provider.') - - self.setPixmap( - QtGui.QWizard.LogoPixmap, - QtGui.QPixmap(APP_LOGO)) - - self.status = QtGui.QLabel("") - self.status.setWordWrap(True) - self.progress = QtGui.QProgressBar() - self.progress.setMaximum(100) - self.progress.hide() - - # for pre-checks - self.status_line_1 = QtGui.QLabel() - self.status_line_2 = QtGui.QLabel() - self.status_line_3 = QtGui.QLabel() - self.status_line_4 = QtGui.QLabel() - - # for connecting signals... - self.status_line_5 = QtGui.QLabel() - - layout = QtGui.QGridLayout() - layout.addWidget(self.status, 0, 1) - layout.addWidget(self.progress, 5, 1) - layout.addWidget(self.status_line_1, 8, 1) - layout.addWidget(self.status_line_2, 9, 1) - layout.addWidget(self.status_line_3, 10, 1) - layout.addWidget(self.status_line_4, 11, 1) - - # XXX to be used? - #self.validation_status = QtGui.QLabel("") - #self.validation_status.setStyleSheet( - #ErrorLabelStyleSheet) - #self.validation_msg = QtGui.QLabel("") - - self.setLayout(layout) - - self.goto_login_again = False - - def set_status(self, status): - self.status.setText(status) - self.status.setWordWrap(True) - - def set_status_line(self, line, status): - line = getattr(self, 'status_line_%s' % line) - if line: - line.setText(status) - - def set_validation_status(self, status): - # Do not remember if we're using - # status lines > 3 now... - # if we are, move below - self.status_line_3.setStyleSheet( - ErrorLabelStyleSheet) - self.status_line_3.setText(status) - - def set_validation_message(self, message): - self.status_line_4.setText(message) - self.status_line_4.setWordWrap(True) - - def get_donemsg(self, msg): - return "%s ... done" % msg - - def run_eip_checks_for_provider_and_connect(self, domain): - wizard = self.wizard() - conductor = wizard.conductor - start_eip_signal = getattr( - wizard, - 'start_eipconnection_signal', None) - - if conductor: - conductor.set_provider_domain(domain) - conductor.run_checks() - self.conductor = conductor - errors = self.eip_error_check() - if not errors and start_eip_signal: - start_eip_signal.emit() - - else: - logger.warning( - "No conductor found. This means that " - "probably the wizard has been launched " - "in an stand-alone way") - - def eip_error_check(self): - """ - a version of the main app error checker, - but integrated within the connecting page of the wizard. - consumes the conductor error queue. - pops errors, and add those to the wizard page - """ - logger.debug('eip error check from connecting page') - errq = self.conductor.error_queue - # XXX missing! - - def fetch_and_validate(self): - # XXX MOVE TO validate function in register-validation - import time - domain = self.field('provider_domain') - wizard = self.wizard() - #pconfig = wizard.providerconfig - eipconfigchecker = wizard.eipconfigchecker() - pCertChecker = wizard.providercertchecker( - domain=domain) - - # username and password are in different fields - # if they were stored in log_in or sign_up pages. - from_login = self.wizard().from_login - unamek_base = 'userName' - passwk_base = 'userPassword' - unamek = 'login_%s' % unamek_base if from_login else unamek_base - passwk = 'login_%s' % passwk_base if from_login else passwk_base - - username = self.field(unamek) - password = self.field(passwk) - credentials = username, password - - self.progress.show() - - fetching_eip_conf_msg = 'Fetching eip service configuration' - self.set_status(fetching_eip_conf_msg) - self.progress.setValue(30) - - # Fetching eip service - eipconfigchecker.fetch_eip_service_config( - domain=domain) - - self.status_line_1.setText( - self.get_donemsg(fetching_eip_conf_msg)) - - getting_client_cert_msg = 'Getting client certificate' - self.set_status(getting_client_cert_msg) - self.progress.setValue(66) - - # Download cert - try: - pCertChecker.download_new_client_cert( - credentials=credentials, - # FIXME FIXME FIXME - # XXX FIX THIS!!!!! - # BUG #638. remove verify - # FIXME FIXME FIXME - verify=False) - except auth.SRPAuthenticationError as exc: - self.set_validation_status( - "Authentication error: %s" % exc.message) - return False - - time.sleep(2) - self.status_line_2.setText( - self.get_donemsg(getting_client_cert_msg)) - - validating_clientcert_msg = 'Validating client certificate' - self.set_status(validating_clientcert_msg) - self.progress.setValue(90) - time.sleep(2) - self.status_line_3.setText( - self.get_donemsg(validating_clientcert_msg)) - - self.progress.setValue(100) - time.sleep(3) - - # here we go! :) - self.run_eip_checks_for_provider_and_connect(domain) - - #self.validation_block = self.wait_for_validation_block() - - # XXX signal timeout! - return True - - # - # wizardpage methods - # - - def nextId(self): - wizard = self.wizard() - # XXX this does not work because - # page login has already been met - #if self.goto_login_again: - #next_ = "login" - #else: - #next_ = "lastpage" - next_ = "lastpage" - return wizard.get_page_index(next_) - - def initializePage(self): - # XXX if we're coming from signup page - # we could say something like - # 'registration successful!' - self.status.setText( - "We have " - "all we need to connect with the provider.

" - "Click next to continue. ") - self.progress.setValue(0) - self.progress.hide() - self.status_line_1.setText('') - self.status_line_2.setText('') - self.status_line_3.setText('') - - def validatePage(self): - # XXX remove - validated = self.fetch_and_validate() - return validated diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index a4be51a9..fd48f7f9 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -40,7 +40,7 @@ class SelectProviderPage(InlineValidationPage): self.did_cert_check = False - self.is_done = False + self.done = False self.setupSteps() self.setupUI() @@ -131,7 +131,7 @@ class SelectProviderPage(InlineValidationPage): # certinfo - def setupCertInfoGroup(self): + def setupCertInfoGroup(self): # pragma: no cover # XXX not used now. certinfoGroup = QtGui.QGroupBox( self.tr("Certificate validation")) @@ -188,7 +188,6 @@ class SelectProviderPage(InlineValidationPage): _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain) netchecker = wizard.netchecker() - providercertchecker = wizard.providercertchecker() eipconfigchecker = wizard.eipconfigchecker(domain=_domain) @@ -205,6 +204,7 @@ class SelectProviderPage(InlineValidationPage): this domain """ try: + #import ipdb;ipdb.set_trace() netchecker.check_name_resolution( domain) @@ -306,7 +306,7 @@ class SelectProviderPage(InlineValidationPage): # done! - self.is_done = True + self.done = True yield(("end_sentinel", 100), lambda: None) def on_checks_validation_ready(self): @@ -316,7 +316,7 @@ class SelectProviderPage(InlineValidationPage): self.domain_checked = True self.completeChanged.emit() # let's set focus... - if self.is_done: + if self.is_done(): self.wizard().clean_validation_error(self.current_page) nextbutton = self.wizard().button(QtGui.QWizard.NextButton) nextbutton.setFocus() @@ -329,7 +329,7 @@ class SelectProviderPage(InlineValidationPage): def is_insecure_cert_trusted(self): return self.trustProviderCertCheckBox.isChecked() - def onTrustCheckChanged(self, state): + def onTrustCheckChanged(self, state): # pragma: no cover XXX checked = False if state == 2: checked = True @@ -342,7 +342,7 @@ class SelectProviderPage(InlineValidationPage): # trigger signal to redraw next button self.completeChanged.emit() - def add_cert_info(self, certinfo): + def add_cert_info(self, certinfo): # pragma: no cover XXX self.certWarning.setText( "Do you want to trust this provider certificate?") self.certInfo.setText( @@ -351,7 +351,7 @@ class SelectProviderPage(InlineValidationPage): self.certinfoGroup.show() def onProviderChanged(self, text): - self.is_done = False + self.done = False provider = self.providerNameEdit.text() if provider: self.providerCheckButton.setDisabled(False) @@ -374,7 +374,7 @@ class SelectProviderPage(InlineValidationPage): def isComplete(self): provider = self.providerNameEdit.text() - if not self.is_done: + if not self.is_done(): return False if not provider: @@ -383,7 +383,7 @@ class SelectProviderPage(InlineValidationPage): if self.is_insecure_cert_trusted(): return True if not self.did_cert_check: - if self.is_done: + if self.is_done(): # XXX sure? return True return False @@ -452,7 +452,7 @@ class SelectProviderPage(InlineValidationPage): if hasattr(self, 'certinfoGroup'): # XXX remove ? self.certinfoGroup.hide() - self.is_done = False + self.done = False self.providerCheckButton.setDisabled(True) self.valFrame.hide() self.steps.removeAllSteps() diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index e85723cb..7fd5c574 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -131,6 +131,16 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): field.setDisabled(True) # error painting + def paintEvent(self, event): + """ + we hook our populate errors + on paintEvent because we need it to catch + when user enters the page coming from next, + and initializePage does not cover that case. + Maybe there's a better event to hook upon. + """ + super(RegisterUserPage, self).paintEvent(event) + self.populateErrors() def markRedAndGetFocus(self, field): field.setStyleSheet(styles.ErrorLineEdit) @@ -193,16 +203,21 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): """ self.bad_string = None - def paintEvent(self, event): + def green_validation_status(self): + val = self.validationMsg + val.setText(self.tr('Registration succeeded!')) + val.setStyleSheet(styles.GreenLineEdit) + + def reset_validation_status(self): """ - we hook our populate errors - on paintEvent because we need it to catch - when user enters the page coming from next, - and initializePage does not cover that case. - Maybe there's a better event to hook upon. + empty the validation msg + and clean the inline validation widget. """ - super(RegisterUserPage, self).paintEvent(event) - self.populateErrors() + self.validationMsg.setText('') + self.steps.removeAllSteps() + self.clearTable() + + # actual checks def _do_checks(self): """ @@ -255,6 +270,7 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): schema="https", provider=provider, verify=verify) + #import ipdb;ipdb.set_trace() try: ok, req = signup.register_user( username, password) @@ -277,9 +293,15 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): self.tr( "Error during registration (%s)") % req.status_code) - validation_msgs = json.loads(req.content) - errors = validation_msgs.get('errors', None) - logger.debug('validation errors: %s' % validation_msgs) + try: + validation_msgs = json.loads(req.content) + errors = validation_msgs.get('errors', None) + logger.debug('validation errors: %s' % validation_msgs) + except ValueError: + # probably bad json returned + return self.fail( + self.tr( + "Could not register (bad response)")) if errors and errors.get('login', None): # XXX this sometimes catch the blank username @@ -287,11 +309,13 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): return self.fail( self.tr('Username not available.')) + return True + logger.debug('registering user') yield(("registering with provider", 40), register) self.set_done() - yield(("end_sentinel", 0), lambda: None) + yield(("end_sentinel", 100), lambda: None) def on_checks_validation_ready(self): """ @@ -308,20 +332,6 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): self.green_validation_status() self.do_confirm_next = True - def green_validation_status(self): - val = self.validationMsg - val.setText(self.tr('Registration succeeded!')) - val.setStyleSheet(styles.GreenLineEdit) - - def reset_validation_status(self): - """ - empty the validation msg - and clean the inline validation widget. - """ - self.validationMsg.setText('') - self.steps.removeAllSteps() - self.clearTable() - # pagewizard methods def validatePage(self): @@ -352,10 +362,22 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): """ inits wizard page """ - provider = self.field('provider_domain') - self.setSubTitle( - self.tr("Register a new user with provider %s.") % - provider) + provider = unicode(self.field('provider_domain')) + # hack. don't get why I'm getting a QVariant there, + # making segfault in tests. + provider = QtCore.QString(provider) + if provider: + # here we should have provider + # but in tests we might not. + + # XXX this error causes a segfault on free() + # that we might want to get fixed ... + #self.setSubTitle( + #self.tr("Register a new user with provider %s.") % + #provider) + self.setSubTitle( + self.tr("Register a new user with provider %s." % + provider)) self.validationMsg.setText('') self.userPassword2LineEdit.setText('') self.valFrame.hide() diff --git a/src/leap/gui/firstrun/wizard.py b/src/leap/gui/firstrun/wizard.py index bd3fe903..89209401 100755 --- a/src/leap/gui/firstrun/wizard.py +++ b/src/leap/gui/firstrun/wizard.py @@ -49,12 +49,29 @@ TODO-ish: """ +def get_pages_dict(): + return OrderedDict(( + ('intro', firstrun.intro.IntroPage), + ('providerselection', + firstrun.providerselect.SelectProviderPage), + ('login', firstrun.login.LogInPage), + ('providerinfo', firstrun.providerinfo.ProviderInfoPage), + ('providersetupvalidation', + firstrun.providersetup.ProviderSetupValidationPage), + ('signup', firstrun.register.RegisterUserPage), + ('signupvalidation', + firstrun.regvalidation.RegisterUserValidationPage), + ('lastpage', firstrun.last.LastPage) + )) + + class FirstRunWizard(QtGui.QWizard): def __init__( self, conductor_instance, parent=None, + pages_dict=None, eip_username=None, providers=None, success_cb=None, is_provider_setup=False, @@ -115,20 +132,7 @@ class FirstRunWizard(QtGui.QWizard): self.is_previously_registered = bool(self.eip_username) self.from_login = False - pages_dict = OrderedDict(( - ('intro', firstrun.intro.IntroPage), - ('providerselection', - firstrun.providerselect.SelectProviderPage), - ('login', firstrun.login.LogInPage), - ('providerinfo', firstrun.providerinfo.ProviderInfoPage), - ('providersetupvalidation', - firstrun.providersetup.ProviderSetupValidationPage), - ('signup', firstrun.register.RegisterUserPage), - ('signupvalidation', - firstrun.regvalidation.RegisterUserValidationPage), - ('connecting', firstrun.connect.ConnectingPage), - ('lastpage', firstrun.last.LastPage) - )) + pages_dict = pages_dict or get_pages_dict() self.add_pages_from_dict(pages_dict) self.validation_errors = {} -- cgit v1.2.3 From 5a335cd560846fbcfa74f013c170a3bd32c7b85b Mon Sep 17 00:00:00 2001 From: kali Date: Mon, 10 Dec 2012 17:07:12 +0900 Subject: login tests --- src/leap/gui/firstrun/login.py | 247 +++++++++++---------- src/leap/gui/firstrun/register.py | 7 +- .../firstrun/tests/integration/fake_provider.py | 31 ++- 3 files changed, 145 insertions(+), 140 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/login.py b/src/leap/gui/firstrun/login.py index 02bace86..e7afee9f 100644 --- a/src/leap/gui/firstrun/login.py +++ b/src/leap/gui/firstrun/login.py @@ -82,6 +82,120 @@ class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage #self.registerField('is_login_wizard') + # actual checks + + def _do_checks(self): + + full_username = self.userNameLineEdit.text() + ########################### + # 0) check user@domain form + ########################### + + def checkusername(): + if full_username.count('@') != 1: + return self.fail( + self.tr( + "Username must be in the username@provider form.")) + else: + return True + + yield(("head_sentinel", 0), checkusername) + + username, domain = full_username.split('@') + password = self.userPasswordLineEdit.text() + + # We try a call to an authenticated + # page here as a mean to catch + # srp authentication errors while + wizard = self.wizard() + eipconfigchecker = wizard.eipconfigchecker() + + ######################## + # 1) try name resolution + ######################## + # show the frame before going on... + QtCore.QMetaObject.invokeMethod( + self, "showStepsFrame") + + # Able to contact domain? + # can get definition? + # two-by-one + def resolvedomain(): + try: + eipconfigchecker.fetch_definition(domain=domain) + + # we're using requests here for all + # the possible error cases that it catches. + except requests.exceptions.ConnectionError as exc: + return self.fail(exc.message[1]) + except requests.exceptions.HTTPError as exc: + return self.fail(exc.message) + except Exception as exc: + # XXX get catchall error msg + return self.fail( + exc.message) + else: + return True + + yield((self.tr("Resolving domain name"), 20), resolvedomain) + + wizard.set_providerconfig( + eipconfigchecker.defaultprovider.config) + + ######################## + # 2) do authentication + ######################## + credentials = username, password + pCertChecker = wizard.providercertchecker( + domain=domain) + + def validate_credentials(): + ################# + # FIXME #BUG #638 + verify = False + + try: + pCertChecker.download_new_client_cert( + credentials=credentials, + verify=verify) + + except auth.SRPAuthenticationError as exc: + return self.fail( + self.tr("Authentication error: %s" % exc.message)) + + except Exception as exc: + return self.fail(exc.message) + + else: + return True + + yield(('Validating credentials', 60), validate_credentials) + + self.set_done() + yield(("end_sentinel", 100), lambda: None) + + def green_validation_status(self): + val = self.validationMsg + val.setText(self.tr('Credentials validated.')) + val.setStyleSheet(styles.GreenLineEdit) + + def on_checks_validation_ready(self): + """ + after checks + """ + if self.is_done(): + self.disableFields() + self.cleanup_errormsg() + self.clean_wizard_errors(self.current_page) + # make the user confirm the transition + # to next page. + self.nextText('&Next') + self.nextFocus() + self.green_validation_status() + self.do_confirm_next = True + + # ui update + def nextText(self, text): self.setButtonText( QtGui.QWizard.NextButton, text) @@ -94,12 +208,18 @@ class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage self.wizard().button( QtGui.QWizard.NextButton).setDisabled(True) - def onUserNameEdit(self, *args): + def onUserNamePositionChanged(self, *args): if self.initial_username_sample: self.userNameLineEdit.setText('') # XXX set regular color self.initial_username_sample = None + def onUserNameTextChanged(self, *args): + if self.initial_username_sample: + k = args[0][-1] + self.initial_username_sample = None + self.userNameLineEdit.setText(k) + def disableFields(self): for field in (self.userNameLineEdit, self.userPasswordLineEdit): @@ -111,13 +231,8 @@ class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage errors = self.wizard().get_validation_error( self.current_page) - #prev_er = getattr(self, 'prevalidation_error', None) showerr = self.validationMsg.setText - #if not errors and prev_er: - #showerr(prev_er) - #return -# if errors: bad_str = getattr(self, 'bad_string', None) cur_str = self.userNameLineEdit.text() @@ -128,9 +243,6 @@ class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage self.bad_string = cur_str showerr(errors) else: - #if prev_er: - #showerr(prev_er) - #return # not the first time if cur_str == bad_str: showerr(errors) @@ -177,7 +289,9 @@ class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage username = self.userNameLineEdit username.setText('username@provider.example.org') username.cursorPositionChanged.connect( - self.onUserNameEdit) + self.onUserNamePositionChanged) + username.textChanged.connect( + self.onUserNameTextChanged) self.initial_username_sample = True self.validationMsg.setText('') self.valFrame.hide() @@ -215,116 +329,3 @@ class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage self.do_checks() return self.is_done() - - def _do_checks(self): - # XXX convert this to inline - - full_username = self.userNameLineEdit.text() - ########################### - # 0) check user@domain form - ########################### - - def checkusername(): - if full_username.count('@') != 1: - return self.fail( - self.tr( - "Username must be in the username@provider form.")) - else: - return True - - yield(("head_sentinel", 0), checkusername) - - # XXX I think this is not needed - # since we're also checking for the is_signup field. - #self.wizard().from_login = True - - username, domain = full_username.split('@') - password = self.userPasswordLineEdit.text() - - # We try a call to an authenticated - # page here as a mean to catch - # srp authentication errors while - wizard = self.wizard() - eipconfigchecker = wizard.eipconfigchecker() - - ######################## - # 1) try name resolution - ######################## - # show the frame before going on... - QtCore.QMetaObject.invokeMethod( - self, "showStepsFrame") - - # Able to contact domain? - # can get definition? - # two-by-one - def resolvedomain(): - try: - eipconfigchecker.fetch_definition(domain=domain) - - # we're using requests here for all - # the possible error cases that it catches. - except requests.exceptions.ConnectionError as exc: - return self.fail(exc.message[1]) - except requests.exceptions.HTTPError as exc: - return self.fail(exc.message) - except Exception as exc: - # XXX get catchall error msg - return self.fail( - exc.message) - - yield((self.tr("resolving domain name"), 20), resolvedomain) - - wizard.set_providerconfig( - eipconfigchecker.defaultprovider.config) - - ######################## - # 2) do authentication - ######################## - credentials = username, password - pCertChecker = wizard.providercertchecker( - domain=domain) - - def validate_credentials(): - ################# - # FIXME #BUG #638 - verify = False - - try: - pCertChecker.download_new_client_cert( - credentials=credentials, - verify=verify) - - except auth.SRPAuthenticationError as exc: - return self.fail( - self.tr("Authentication error: %s" % exc.message)) - - except Exception as exc: - return self.fail(exc.message) - - else: - return True - - yield(('Validating credentials', 20), validate_credentials) - - self.set_done() - yield(("end_sentinel", 0), lambda: None) - - def green_validation_status(self): - val = self.validationMsg - val.setText(self.tr('Credentials validated.')) - val.setStyleSheet(styles.GreenLineEdit) - - def on_checks_validation_ready(self): - """ - after checks - """ - if self.is_done(): - self.disableFields() - self.cleanup_errormsg() - self.clean_wizard_errors(self.current_page) - # make the user confirm the transition - # to next page. - self.nextText('&Next') - self.nextFocus() - self.green_validation_status() - self.do_confirm_next = True diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index 7fd5c574..4c811093 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -363,9 +363,6 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): inits wizard page """ provider = unicode(self.field('provider_domain')) - # hack. don't get why I'm getting a QVariant there, - # making segfault in tests. - provider = QtCore.QString(provider) if provider: # here we should have provider # but in tests we might not. @@ -384,7 +381,7 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): def nextId(self): wizard = self.wizard() - if not wizard: - return + #if not wizard: + #return # XXX this should be called connect return wizard.get_page_index('signupvalidation') diff --git a/src/leap/gui/firstrun/tests/integration/fake_provider.py b/src/leap/gui/firstrun/tests/integration/fake_provider.py index 33ee0ee6..445b4487 100755 --- a/src/leap/gui/firstrun/tests/integration/fake_provider.py +++ b/src/leap/gui/firstrun/tests/integration/fake_provider.py @@ -40,6 +40,8 @@ from twisted.web.static import File from twisted.web.resource import Resource from twisted.internet import reactor +from leap.testing.https_server import where + # See # http://twistedmatrix.com/documents/current/web/howto/web-in-60/index.htmln # for more examples @@ -229,14 +231,13 @@ def get_certs_path(): def get_TLS_credentials(): # XXX this is giving errors # XXX REview! We want to use gnutls! - certs_path = get_certs_path() cert = crypto.X509Certificate( - open(certs_path + '/leaptestscert.pem').read()) + open(where('leaptestscert.pem')).read()) key = crypto.X509PrivateKey( - open(certs_path + '/leaptestskey.pem').read()) + open(where('leaptestskey.pem')).read()) ca = crypto.X509Certificate( - open(certs_path + '/cacert.pem').read()) + open(where('cacert.pem')).read()) #crl = crypto.X509CRL(open(certs_path + '/crl.pem').read()) #cred = crypto.X509Credentials(cert, key, [ca], [crl]) cred = X509Credentials(cert, key, [ca]) @@ -253,19 +254,17 @@ class OpenSSLServerContextFactory: """Create an SSL context. This is a sample implementation that loads a certificate from a file called 'server.pem'.""" - certs_path = get_certs_path() ctx = SSL.Context(SSL.SSLv23_METHOD) - ctx.use_certificate_file(certs_path + '/leaptestscert.pem') - ctx.use_privatekey_file(certs_path + '/leaptestskey.pem') + #certs_path = get_certs_path() + #ctx.use_certificate_file(certs_path + '/leaptestscert.pem') + #ctx.use_privatekey_file(certs_path + '/leaptestskey.pem') + ctx.use_certificate_file(where('leaptestscert.pem')) + ctx.use_privatekey_file(where('leaptestskey.pem')) return ctx -if __name__ == "__main__": - - from twisted.python import log - log.startLogging(sys.stdout) - +def serve_fake_provider(): root = Resource() root.putChild("provider.json", File("./provider.json")) config = Resource() @@ -293,3 +292,11 @@ if __name__ == "__main__": reactor.listenSSL(8443, factory, OpenSSLServerContextFactory()) reactor.run() + + +if __name__ == "__main__": + + from twisted.python import log + log.startLogging(sys.stdout) + + serve_fake_provider() -- cgit v1.2.3 From b36b39fc25341902027d32a3a669abd390be9bbc Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 12 Dec 2012 09:17:38 +0900 Subject: progress to connection only if no errors --- src/leap/gui/firstrun/regvalidation.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index 0e67834b..aeb98204 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -100,9 +100,12 @@ class RegisterUserValidationPage(ValidationPage): def fetcheipcert(): try: - pCertChecker.download_new_client_cert( + downloaded = pCertChecker.download_new_client_cert( credentials=credentials, verify=verify) + if not downloaded: + logger.error('Could not download client cert.') + return False except auth.SRPAuthenticationError as exc: return self.fail(self.tr( @@ -126,10 +129,11 @@ class RegisterUserValidationPage(ValidationPage): """ # this should be called CONNECT PAGE AGAIN. # here we go! :) - full_domain = self.field('provider_domain') - domain, port = get_https_domain_and_port(full_domain) - _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain) - self.run_eip_checks_for_provider_and_connect(_domain) + if self.is_done(): + full_domain = self.field('provider_domain') + domain, port = get_https_domain_and_port(full_domain) + _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain) + self.run_eip_checks_for_provider_and_connect(_domain) def run_eip_checks_for_provider_and_connect(self, domain): wizard = self.wizard() -- cgit v1.2.3 From 89694babd14a9b2ba76095911b6884e359a12282 Mon Sep 17 00:00:00 2001 From: kali Date: Mon, 17 Dec 2012 05:05:37 +0900 Subject: network checker launched by signal fixes problem with provider domain not being defined during first run. --- src/leap/gui/firstrun/last.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/last.py b/src/leap/gui/firstrun/last.py index d33d2e77..1d8caca4 100644 --- a/src/leap/gui/firstrun/last.py +++ b/src/leap/gui/firstrun/last.py @@ -58,6 +58,8 @@ class LastPage(QtGui.QWizardPage): self.label.setText( "Click '%s' to end the wizard and " "save your settings." % finishText) + # XXX init network checker + # trigger signal @coroutine def eip_status_handler(self): -- cgit v1.2.3 From 9d2869d9b9abdcf4e63705e659fa4369137a428e Mon Sep 17 00:00:00 2001 From: kali Date: Tue, 18 Dec 2012 06:12:52 +0900 Subject: added current_page --- src/leap/gui/firstrun/regvalidation.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index aeb98204..b86583e0 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -29,6 +29,7 @@ class RegisterUserValidationPage(ValidationPage): def __init__(self, parent=None): super(RegisterUserValidationPage, self).__init__(parent) + self.current_page = "signupvalidation" title = "Connecting..." # XXX uh... really? @@ -132,7 +133,8 @@ class RegisterUserValidationPage(ValidationPage): if self.is_done(): full_domain = self.field('provider_domain') domain, port = get_https_domain_and_port(full_domain) - _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain) + _domain = u"%s:%s" % ( + domain, port) if port != 443 else unicode(domain) self.run_eip_checks_for_provider_and_connect(_domain) def run_eip_checks_for_provider_and_connect(self, domain): -- cgit v1.2.3 From d04c93134ad3daaee0ca280824ab3288bfc5029c Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 16 Nov 2012 22:59:16 +0900 Subject: initial translation example. --- src/leap/gui/firstrun/intro.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/intro.py b/src/leap/gui/firstrun/intro.py index 4bb008c7..0a7484e2 100644 --- a/src/leap/gui/firstrun/intro.py +++ b/src/leap/gui/firstrun/intro.py @@ -11,7 +11,7 @@ class IntroPage(QtGui.QWizardPage): def __init__(self, parent=None): super(IntroPage, self).__init__(parent) - self.setTitle("First run wizard.") + self.setTitle(self.tr("First run wizard.")) #self.setPixmap( #QtGui.QWizard.WatermarkPixmap, @@ -21,7 +21,7 @@ class IntroPage(QtGui.QWizardPage): QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) - label = QtGui.QLabel( + label = QtGui.QLabel(self.tr( "Now we will guide you through " "some configuration that is needed before you " "can connect for the first time.

" @@ -29,16 +29,16 @@ class IntroPage(QtGui.QWizardPage): "you can find the wizard in the 'Settings' menu from the " "main window.

" "Do you want to sign up for a new account, or log " - "in with an already existing username?
") + "in with an already existing username?
")) label.setWordWrap(True) radiobuttonGroup = QtGui.QGroupBox() self.sign_up = QtGui.QRadioButton( - "Sign up for a new account.") + self.tr("Sign up for a new account.")) self.sign_up.setChecked(True) self.log_in = QtGui.QRadioButton( - "Log In with my credentials.") + self.tr("Log In with my credentials.")) radiobLayout = QtGui.QVBoxLayout() radiobLayout.addWidget(self.sign_up) -- cgit v1.2.3 From f82f81b6766905269d51e08632b42ed2e92c249b Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 9 Jan 2013 00:00:42 +0900 Subject: rename username var --- src/leap/gui/firstrun/wizard.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/wizard.py b/src/leap/gui/firstrun/wizard.py index 89209401..408d4597 100755 --- a/src/leap/gui/firstrun/wizard.py +++ b/src/leap/gui/firstrun/wizard.py @@ -72,7 +72,7 @@ class FirstRunWizard(QtGui.QWizard): conductor_instance, parent=None, pages_dict=None, - eip_username=None, + username=None, providers=None, success_cb=None, is_provider_setup=False, trusted_certs=None, @@ -92,7 +92,7 @@ class FirstRunWizard(QtGui.QWizard): # in the connection page, before the wizard has ended. self.conductor = conductor_instance - self.eip_username = eip_username + self.username = username self.providers = providers # success callback @@ -129,7 +129,7 @@ class FirstRunWizard(QtGui.QWizard): # by setting 1st page?? #self.is_previously_registered = is_previously_registered # XXX ??? ^v - self.is_previously_registered = bool(self.eip_username) + self.is_previously_registered = bool(self.username) self.from_login = False pages_dict = pages_dict or get_pages_dict() @@ -233,7 +233,7 @@ class FirstRunWizard(QtGui.QWizard): settings.setValue("remember_user_and_pass", remember_pass) if remember_pass: - settings.setValue("eip_username", full_username) + settings.setValue("username", full_username) seed = self.get_random_str(10) settings.setValue("%s_seed" % provider, seed) -- cgit v1.2.3 From 8fb39dd87db76bd4450e0137f34d7d0ee66de935 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 9 Jan 2013 00:17:32 +0900 Subject: fix provider domain regex --- src/leap/gui/firstrun/providerselect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index fd48f7f9..62742181 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -64,7 +64,7 @@ class SelectProviderPage(InlineValidationPage): providerNameLabel.setBuddy(providerNameEdit) # add regex validator - providerDomainRe = QtCore.QRegExp(r"^[a-z\d_-.]+$") + providerDomainRe = QtCore.QRegExp(r"^[a-z1-9_\-\.]+$") providerNameEdit.setValidator( QtGui.QRegExpValidator(providerDomainRe, self)) self.providerNameEdit = providerNameEdit -- cgit v1.2.3 From fe794fbf9248fcf9d097eded799248ef265e24ad Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 9 Jan 2013 00:44:21 +0900 Subject: wrap provider info --- src/leap/gui/firstrun/providerinfo.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index c5b2984c..248267ff 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -62,6 +62,7 @@ class ProviderInfoPage(QtGui.QWizardPage): # this should be better handled with signals !! self.displayName = displayName self.description = description + self.description.setWordWrap(True) self.enrollment_policy = enrollment_policy def show_provider_info(self): @@ -72,7 +73,7 @@ class ProviderInfoPage(QtGui.QWizardPage): lang = "en" pconfig = self.wizard().providerconfig - dn = pconfig.get('display_name') + dn = pconfig.get('name') display_name = dn[lang] if dn else '' domain_name = self.field('provider_domain') -- cgit v1.2.3 From 93d5a8cd1ec55c725d5931d86989ea11ac2db844 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 9 Jan 2013 04:20:15 +0900 Subject: fix provider label translation --- src/leap/gui/firstrun/providerinfo.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index 248267ff..357378df 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -6,6 +6,7 @@ import logging from PyQt4 import QtGui from leap.gui.constants import APP_LOGO +from leap.util.translations import translate logger = logging.getLogger(__name__) @@ -81,7 +82,10 @@ class ProviderInfoPage(QtGui.QWizardPage): "%s https://%s" % (display_name, domain_name)) desc = pconfig.get('description') - description_text = desc[lang] if desc else '' + + #description_text = desc[lang] if desc else '' + description_text = translate(desc) if desc else '' + self.description.setText( "%s" % description_text) -- cgit v1.2.3 From 460dd7c20408958dda1ca8e77050e9af334b558f Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 9 Jan 2013 05:02:21 +0900 Subject: fix from_login --- src/leap/gui/firstrun/login.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/login.py b/src/leap/gui/firstrun/login.py index e7afee9f..6bf0605d 100644 --- a/src/leap/gui/firstrun/login.py +++ b/src/leap/gui/firstrun/login.py @@ -108,7 +108,7 @@ class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage # page here as a mean to catch # srp authentication errors while wizard = self.wizard() - eipconfigchecker = wizard.eipconfigchecker() + eipconfigchecker = wizard.eipconfigchecker(domain=domain) ######################## # 1) try name resolution @@ -321,6 +321,7 @@ class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage self.setField('provider_domain', domain) self.setField('login_userName', username) self.setField('login_userPassword', password) + self.wizard().from_login = True return True -- cgit v1.2.3 From 8e6a15e2f2d35c606aa0c1a2102c28ceccc23b78 Mon Sep 17 00:00:00 2001 From: antialias Date: Mon, 7 Jan 2013 16:50:52 -0400 Subject: this should be the complete list of userfacing strings. see #665. --- src/leap/gui/firstrun/last.py | 8 ++++---- src/leap/gui/firstrun/login.py | 10 +++++----- src/leap/gui/firstrun/providerselect.py | 7 ++++--- src/leap/gui/firstrun/register.py | 8 ++++---- src/leap/gui/firstrun/regvalidation.py | 4 ++-- 5 files changed, 19 insertions(+), 18 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/last.py b/src/leap/gui/firstrun/last.py index 1d8caca4..e097b2ae 100644 --- a/src/leap/gui/firstrun/last.py +++ b/src/leap/gui/firstrun/last.py @@ -15,7 +15,7 @@ class LastPage(QtGui.QWizardPage): def __init__(self, parent=None): super(LastPage, self).__init__(parent) - self.setTitle("Connecting to Encrypted Internet Proxy service...") + self.setTitle(self.tr("Connecting to Encrypted Internet Proxy service...")) self.setPixmap( QtGui.QWizard.LogoPixmap, @@ -51,13 +51,13 @@ class LastPage(QtGui.QWizardPage): statusline.setText(status) def set_finished_status(self): - self.setTitle('You are now using an encrypted connection!') + self.setTitle(self.tr('You are now using an encrypted connection!')) finishText = self.wizard().buttonText( QtGui.QWizard.FinishButton) finishText = finishText.replace('&', '') - self.label.setText( + self.label.setText(self.tr( "Click '%s' to end the wizard and " - "save your settings." % finishText) + "save your settings." % finishText)) # XXX init network checker # trigger signal diff --git a/src/leap/gui/firstrun/login.py b/src/leap/gui/firstrun/login.py index 6bf0605d..e39eecc0 100644 --- a/src/leap/gui/firstrun/login.py +++ b/src/leap/gui/firstrun/login.py @@ -21,8 +21,8 @@ class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage super(LogInPage, self).__init__(parent) self.current_page = "login" - self.setTitle("Log In") - self.setSubTitle("Log in with your credentials.") + self.setTitle(self.tr("Log In")) + self.setSubTitle(self.tr("Log in with your credentials.")) self.current_page = "login" self.setPixmap( @@ -35,7 +35,7 @@ class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage self.do_confirm_next = False def setupUI(self): - userNameLabel = QtGui.QLabel("User &name:") + userNameLabel = QtGui.QLabel(self.tr("User &name:")) userNameLineEdit = QtGui.QLineEdit() userNameLineEdit.cursorPositionChanged.connect( self.reset_validation_status) @@ -50,7 +50,7 @@ class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage #'username@provider.example.org') self.userNameLineEdit = userNameLineEdit - userPasswordLabel = QtGui.QLabel("&Password:") + userPasswordLabel = QtGui.QLabel(self.tr("&Password:")) self.userPasswordLineEdit = QtGui.QLineEdit() self.userPasswordLineEdit.setEchoMode( QtGui.QLineEdit.Password) @@ -77,7 +77,7 @@ class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage layout.addWidget(self.valFrame, 4, 2, 4, 2) self.valFrame.hide() - self.nextText("Log in") + self.nextText(self.tr("Log in")) self.setLayout(layout) #self.registerField('is_login_wizard') diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index 62742181..28fb829c 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -101,7 +101,7 @@ class SelectProviderPage(InlineValidationPage): self.certInfo.setWordWrap(True) self.certWarning = QtGui.QLabel("") self.trustProviderCertCheckBox = QtGui.QCheckBox( - "&Trust this provider certificate.") + self.tr("&Trust this provider certificate.")) self.trustProviderCertCheckBox.stateChanged.connect( self.onTrustCheckChanged) @@ -344,9 +344,10 @@ class SelectProviderPage(InlineValidationPage): def add_cert_info(self, certinfo): # pragma: no cover XXX self.certWarning.setText( - "Do you want to trust this provider certificate?") + self.tr("Do you want to trust this provider certificate?")) + # XXX Check if this needs to abstracted to remove certinfo self.certInfo.setText( - 'SHA-256 fingerprint: %s
' % certinfo) + self.tr('SHA-256 fingerprint: %s
' % certinfo)) self.certInfo.setWordWrap(True) self.certinfoGroup.show() diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index 4c811093..b04638e0 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -45,7 +45,7 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): self.focused_field = False def setupUI(self): - userNameLabel = QtGui.QLabel("User &name:") + userNameLabel = QtGui.QLabel(self.tr("User &name:")) userNameLineEdit = QtGui.QLineEdit() userNameLineEdit.cursorPositionChanged.connect( self.reset_validation_status) @@ -57,20 +57,20 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): QtGui.QRegExpValidator(usernameRe, self)) self.userNameLineEdit = userNameLineEdit - userPasswordLabel = QtGui.QLabel("&Password:") + userPasswordLabel = QtGui.QLabel(self.tr("&Password:")) self.userPasswordLineEdit = QtGui.QLineEdit() self.userPasswordLineEdit.setEchoMode( QtGui.QLineEdit.Password) userPasswordLabel.setBuddy(self.userPasswordLineEdit) - userPassword2Label = QtGui.QLabel("Password (again):") + userPassword2Label = QtGui.QLabel(self.tr("Password (again):")) self.userPassword2LineEdit = QtGui.QLineEdit() self.userPassword2LineEdit.setEchoMode( QtGui.QLineEdit.Password) userPassword2Label.setBuddy(self.userPassword2LineEdit) rememberPasswordCheckBox = QtGui.QCheckBox( - "&Remember username and password.") + self.tr("&Remember username and password.")) rememberPasswordCheckBox.setChecked(True) self.registerField('userName*', self.userNameLineEdit) diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py index b86583e0..6135a290 100644 --- a/src/leap/gui/firstrun/regvalidation.py +++ b/src/leap/gui/firstrun/regvalidation.py @@ -31,9 +31,9 @@ class RegisterUserValidationPage(ValidationPage): super(RegisterUserValidationPage, self).__init__(parent) self.current_page = "signupvalidation" - title = "Connecting..." + title = self.tr("Connecting...") # XXX uh... really? - subtitle = "Checking connection with provider." + subtitle = self.tr("Checking connection with provider.") self.setTitle(title) self.setSubTitle(subtitle) -- cgit v1.2.3 From f55dcd717a946651492142ed198853b1c667254b Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 10 Jan 2013 02:00:21 +0900 Subject: renamed connection page --- src/leap/gui/firstrun/__init__.py | 5 +- src/leap/gui/firstrun/connect.py | 200 +++++++++++++++++++++++++++++++ src/leap/gui/firstrun/intro.py | 2 +- src/leap/gui/firstrun/providersetup.py | 14 +-- src/leap/gui/firstrun/regvalidation.py | 210 --------------------------------- src/leap/gui/firstrun/wizard.py | 4 +- 6 files changed, 212 insertions(+), 223 deletions(-) create mode 100644 src/leap/gui/firstrun/connect.py delete mode 100644 src/leap/gui/firstrun/regvalidation.py (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/__init__.py b/src/leap/gui/firstrun/__init__.py index d380b75a..2a523d6a 100644 --- a/src/leap/gui/firstrun/__init__.py +++ b/src/leap/gui/firstrun/__init__.py @@ -6,6 +6,7 @@ except ValueError: pass import intro +import connect import last import login import mixins @@ -13,10 +14,10 @@ import providerinfo import providerselect import providersetup import register -import regvalidation __all__ = [ 'intro', + 'connect', 'last', 'login', 'mixins', @@ -24,4 +25,4 @@ __all__ = [ 'providerselect', 'providersetup', 'register', - 'regvalidation'] # ,'wizard'] + ] # ,'wizard'] diff --git a/src/leap/gui/firstrun/connect.py b/src/leap/gui/firstrun/connect.py new file mode 100644 index 00000000..920ada50 --- /dev/null +++ b/src/leap/gui/firstrun/connect.py @@ -0,0 +1,200 @@ +""" +Provider Setup Validation Page, +used in First Run Wizard +""" +import logging + +from PyQt4 import QtGui + +#import requests + +from leap.gui.progress import ValidationPage +from leap.util.web import get_https_domain_and_port + +from leap.base import auth +from leap.gui.constants import APP_LOGO + +logger = logging.getLogger(__name__) + + +class ConnectionPage(ValidationPage): + + def __init__(self, parent=None): + super(ConnectionPage, self).__init__(parent) + self.current_page = "connect" + + title = self.tr("Connecting...") + # XXX uh... really? + subtitle = self.tr("Checking connection with provider.") + + self.setTitle(title) + self.setSubTitle(subtitle) + + self.setPixmap( + QtGui.QWizard.LogoPixmap, + QtGui.QPixmap(APP_LOGO)) + + def _do_checks(self, update_signal=None): + """ + executes actual checks in a separate thread + + we initialize the srp protocol register + and try to register user. + """ + wizard = self.wizard() + full_domain = self.field('provider_domain') + domain, port = get_https_domain_and_port(full_domain) + _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain) + + verify = True + + ########################################### + # Set Credentials. + # username and password are in different fields + # if they were stored in log_in or sign_up pages. + from_login = wizard.from_login + + unamek_base = 'userName' + passwk_base = 'userPassword' + unamek = 'login_%s' % unamek_base if from_login else unamek_base + passwk = 'login_%s' % passwk_base if from_login else passwk_base + + username = self.field(unamek) + password = self.field(passwk) + credentials = username, password + + eipconfigchecker = wizard.eipconfigchecker(domain=_domain) + #XXX change for _domain (sanitized) + pCertChecker = wizard.providercertchecker( + domain=full_domain) + + yield(("head_sentinel", 0), lambda: None) + + ################################################## + # 1) fetching eip service config + ################################################## + def fetcheipconf(): + try: + eipconfigchecker.fetch_eip_service_config( + domain=full_domain) + + # XXX get specific exception + except Exception as exc: + return self.fail(exc.message) + + yield((self.tr("Fetching provider config..."), 40), + fetcheipconf) + + ################################################## + # 2) getting client certificate + ################################################## + + def fetcheipcert(): + try: + downloaded = pCertChecker.download_new_client_cert( + credentials=credentials, + verify=verify) + if not downloaded: + logger.error('Could not download client cert.') + return False + + except auth.SRPAuthenticationError as exc: + return self.fail(self.tr( + "Authentication error: %s" % exc.message)) + else: + return True + + yield((self.tr("Fetching eip certificate"), 80), + fetcheipcert) + + ################ + # end ! + ################ + self.set_done() + yield(("end_sentinel", 100), lambda: None) + + def on_checks_validation_ready(self): + """ + called after _do_checks has finished + (connected to checker thread finished signal) + """ + # this should be called CONNECT PAGE AGAIN. + # here we go! :) + if self.is_done(): + full_domain = self.field('provider_domain') + domain, port = get_https_domain_and_port(full_domain) + _domain = u"%s:%s" % ( + domain, port) if port != 443 else unicode(domain) + self.run_eip_checks_for_provider_and_connect(_domain) + + def run_eip_checks_for_provider_and_connect(self, domain): + wizard = self.wizard() + conductor = wizard.conductor + start_eip_signal = getattr( + wizard, + 'start_eipconnection_signal', None) + + if conductor: + conductor.set_provider_domain(domain) + conductor.run_checks() + self.conductor = conductor + errors = self.eip_error_check() + if not errors and start_eip_signal: + start_eip_signal.emit() + + else: + logger.warning( + "No conductor found. This means that " + "probably the wizard has been launched " + "in an stand-alone way.") + + # XXX look for a better place to signal + # we are done. + # We could probably have a fake validatePage + # that checks if the domain transfer has been + # done to conductor object, triggers the start_signal + # and does the go_next() + self.set_done() + + def eip_error_check(self): + """ + a version of the main app error checker, + but integrated within the connecting page of the wizard. + consumes the conductor error queue. + pops errors, and add those to the wizard page + """ + logger.debug('eip error check from connecting page') + errq = self.conductor.error_queue + # XXX missing! + + def _do_validation(self): + """ + called after _do_checks has finished + (connected to checker thread finished signal) + """ + from_login = self.wizard().from_login + prevpage = "login" if from_login else "signup" + + wizard = self.wizard() + if self.errors: + logger.debug('going back with errors') + logger.error(self.errors) + name, first_error = self.pop_first_error() + wizard.set_validation_error( + prevpage, + first_error) + self.go_back() + else: + logger.debug('should go next, wait for user to click next') + #self.go_next() + + def nextId(self): + wizard = self.wizard() + #if not wizard: + #return + return wizard.get_page_index('lastpage') + + def initializePage(self): + super(ConnectionPage, self).initializePage() + self.set_undone() + self.completeChanged.emit() diff --git a/src/leap/gui/firstrun/intro.py b/src/leap/gui/firstrun/intro.py index 0a7484e2..0425b764 100644 --- a/src/leap/gui/firstrun/intro.py +++ b/src/leap/gui/firstrun/intro.py @@ -50,7 +50,7 @@ class IntroPage(QtGui.QWizardPage): layout.addWidget(radiobuttonGroup) self.setLayout(layout) - self.registerField('is_signup', self.sign_up) + #self.registerField('is_signup', self.sign_up) def validatePage(self): return True diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index 1a362794..48a89091 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -20,8 +20,8 @@ class ProviderSetupValidationPage(ValidationPage): self.current_page = "providersetupvalidation" # XXX needed anymore? - is_signup = self.field("is_signup") - self.is_signup = is_signup + #is_signup = self.field("is_signup") + #self.is_signup = is_signup self.setTitle(self.tr("Provider setup")) self.setSubTitle( @@ -158,14 +158,12 @@ class ProviderSetupValidationPage(ValidationPage): def nextId(self): wizard = self.wizard() - if not wizard: - return - is_signup = self.field('is_signup') - if is_signup is True: - next_ = 'signup' - if is_signup is False: + from_login = wizard.from_login + if from_login: # XXX bad name. change to connect again. next_ = 'signupvalidation' + else: + next_ = 'signup' return wizard.get_page_index(next_) def initializePage(self): diff --git a/src/leap/gui/firstrun/regvalidation.py b/src/leap/gui/firstrun/regvalidation.py deleted file mode 100644 index 6135a290..00000000 --- a/src/leap/gui/firstrun/regvalidation.py +++ /dev/null @@ -1,210 +0,0 @@ -""" -Provider Setup Validation Page, -used in First Run Wizard -""" -# XXX This page is called regvalidation -# but it's implementing functionality in the former -# connect page. -# We should remame it to connect again, when we integrate -# the login branch of the wizard. - -import logging -#import json -#import socket - -from PyQt4 import QtGui - -#import requests - -from leap.gui.progress import ValidationPage -from leap.util.web import get_https_domain_and_port - -from leap.base import auth -from leap.gui.constants import APP_LOGO - -logger = logging.getLogger(__name__) - - -class RegisterUserValidationPage(ValidationPage): - - def __init__(self, parent=None): - super(RegisterUserValidationPage, self).__init__(parent) - self.current_page = "signupvalidation" - - title = self.tr("Connecting...") - # XXX uh... really? - subtitle = self.tr("Checking connection with provider.") - - self.setTitle(title) - self.setSubTitle(subtitle) - - self.setPixmap( - QtGui.QWizard.LogoPixmap, - QtGui.QPixmap(APP_LOGO)) - - def _do_checks(self, update_signal=None): - """ - executes actual checks in a separate thread - - we initialize the srp protocol register - and try to register user. - """ - wizard = self.wizard() - full_domain = self.field('provider_domain') - domain, port = get_https_domain_and_port(full_domain) - _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain) - - # FIXME #BUG 638 FIXME FIXME FIXME - verify = False # !!!!!!!!!!!!!!!! - # FIXME #BUG 638 FIXME FIXME FIXME - - ########################################### - # Set Credentials. - # username and password are in different fields - # if they were stored in log_in or sign_up pages. - is_signup = self.field("is_signup") - - unamek_base = 'userName' - passwk_base = 'userPassword' - unamek = 'login_%s' % unamek_base if not is_signup else unamek_base - passwk = 'login_%s' % passwk_base if not is_signup else passwk_base - - username = self.field(unamek) - password = self.field(passwk) - credentials = username, password - - eipconfigchecker = wizard.eipconfigchecker(domain=_domain) - #XXX change for _domain (sanitized) - pCertChecker = wizard.providercertchecker( - domain=full_domain) - - yield(("head_sentinel", 0), lambda: None) - - ################################################## - # 1) fetching eip service config - ################################################## - def fetcheipconf(): - try: - eipconfigchecker.fetch_eip_service_config( - domain=full_domain) - - # XXX get specific exception - except Exception as exc: - return self.fail(exc.message) - - yield((self.tr("Fetching provider config..."), 40), - fetcheipconf) - - ################################################## - # 2) getting client certificate - ################################################## - - def fetcheipcert(): - try: - downloaded = pCertChecker.download_new_client_cert( - credentials=credentials, - verify=verify) - if not downloaded: - logger.error('Could not download client cert.') - return False - - except auth.SRPAuthenticationError as exc: - return self.fail(self.tr( - "Authentication error: %s" % exc.message)) - else: - return True - - yield((self.tr("Fetching eip certificate"), 80), - fetcheipcert) - - ################ - # end ! - ################ - self.set_done() - yield(("end_sentinel", 100), lambda: None) - - def on_checks_validation_ready(self): - """ - called after _do_checks has finished - (connected to checker thread finished signal) - """ - # this should be called CONNECT PAGE AGAIN. - # here we go! :) - if self.is_done(): - full_domain = self.field('provider_domain') - domain, port = get_https_domain_and_port(full_domain) - _domain = u"%s:%s" % ( - domain, port) if port != 443 else unicode(domain) - self.run_eip_checks_for_provider_and_connect(_domain) - - def run_eip_checks_for_provider_and_connect(self, domain): - wizard = self.wizard() - conductor = wizard.conductor - start_eip_signal = getattr( - wizard, - 'start_eipconnection_signal', None) - - if conductor: - conductor.set_provider_domain(domain) - conductor.run_checks() - self.conductor = conductor - errors = self.eip_error_check() - if not errors and start_eip_signal: - start_eip_signal.emit() - - else: - logger.warning( - "No conductor found. This means that " - "probably the wizard has been launched " - "in an stand-alone way.") - - # XXX look for a better place to signal - # we are done. - # We could probably have a fake validatePage - # that checks if the domain transfer has been - # done to conductor object, triggers the start_signal - # and does the go_next() - self.set_done() - - def eip_error_check(self): - """ - a version of the main app error checker, - but integrated within the connecting page of the wizard. - consumes the conductor error queue. - pops errors, and add those to the wizard page - """ - logger.debug('eip error check from connecting page') - errq = self.conductor.error_queue - # XXX missing! - - def _do_validation(self): - """ - called after _do_checks has finished - (connected to checker thread finished signal) - """ - is_signup = self.field("is_signup") - prevpage = "signup" if is_signup else "login" - - wizard = self.wizard() - if self.errors: - logger.debug('going back with errors') - logger.error(self.errors) - name, first_error = self.pop_first_error() - wizard.set_validation_error( - prevpage, - first_error) - self.go_back() - else: - logger.debug('should go next, wait for user to click next') - #self.go_next() - - def nextId(self): - wizard = self.wizard() - if not wizard: - return - return wizard.get_page_index('lastpage') - - def initializePage(self): - super(RegisterUserValidationPage, self).initializePage() - self.set_undone() - self.completeChanged.emit() diff --git a/src/leap/gui/firstrun/wizard.py b/src/leap/gui/firstrun/wizard.py index 408d4597..427f9df8 100755 --- a/src/leap/gui/firstrun/wizard.py +++ b/src/leap/gui/firstrun/wizard.py @@ -59,8 +59,8 @@ def get_pages_dict(): ('providersetupvalidation', firstrun.providersetup.ProviderSetupValidationPage), ('signup', firstrun.register.RegisterUserPage), - ('signupvalidation', - firstrun.regvalidation.RegisterUserValidationPage), + ('connect', + firstrun.connect.ConnectionPage), ('lastpage', firstrun.last.LastPage) )) -- cgit v1.2.3 From 6d85c97ddcc8a151b157919e9a7322fba151a551 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 11 Jan 2013 03:00:41 +0900 Subject: all calls except the first one are made to api uri we also parse the port number --- src/leap/gui/firstrun/connect.py | 24 +++++++++++++----------- src/leap/gui/firstrun/providersetup.py | 33 ++++++++++++--------------------- src/leap/gui/firstrun/register.py | 18 +++++++++--------- 3 files changed, 34 insertions(+), 41 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/connect.py b/src/leap/gui/firstrun/connect.py index 920ada50..b7688380 100644 --- a/src/leap/gui/firstrun/connect.py +++ b/src/leap/gui/firstrun/connect.py @@ -44,9 +44,15 @@ class ConnectionPage(ValidationPage): wizard = self.wizard() full_domain = self.field('provider_domain') domain, port = get_https_domain_and_port(full_domain) - _domain = u"%s:%s" % (domain, port) if port != 443 else unicode(domain) - verify = True + pconfig = wizard.eipconfigchecker(domain=domain) + # this should be persisted... + pconfig.defaultprovider.load() + pconfig.set_api_domain() + + pCertChecker = wizard.providercertchecker( + domain=domain) + pCertChecker.set_api_domain(pconfig.apidomain) ########################################### # Set Credentials. @@ -63,11 +69,6 @@ class ConnectionPage(ValidationPage): password = self.field(passwk) credentials = username, password - eipconfigchecker = wizard.eipconfigchecker(domain=_domain) - #XXX change for _domain (sanitized) - pCertChecker = wizard.providercertchecker( - domain=full_domain) - yield(("head_sentinel", 0), lambda: None) ################################################## @@ -75,8 +76,7 @@ class ConnectionPage(ValidationPage): ################################################## def fetcheipconf(): try: - eipconfigchecker.fetch_eip_service_config( - domain=full_domain) + pconfig.fetch_eip_service_config() # XXX get specific exception except Exception as exc: @@ -92,8 +92,7 @@ class ConnectionPage(ValidationPage): def fetcheipcert(): try: downloaded = pCertChecker.download_new_client_cert( - credentials=credentials, - verify=verify) + credentials=credentials) if not downloaded: logger.error('Could not download client cert.') return False @@ -101,6 +100,9 @@ class ConnectionPage(ValidationPage): except auth.SRPAuthenticationError as exc: return self.fail(self.tr( "Authentication error: %s" % exc.message)) + + except Exception as exc: + return self.fail(exc.message) else: return True diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index 48a89091..981e3214 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -4,6 +4,8 @@ used if First Run Wizard """ import logging +import requests + from PyQt4 import QtGui from leap.base import exceptions as baseexceptions @@ -110,26 +112,15 @@ class ProviderSetupValidationPage(ValidationPage): ######################### def validatecacert(): - pass - #api_uri = pconfig.get('api_uri', None) - #try: - #api_cert_verified = pCertChecker.verify_api_https(api_uri) - #except requests.exceptions.SSLError as exc: - #logger.error('BUG #638. %s' % exc.message) - # XXX RAISE! See #638 - # bypassing until the hostname is fixed. - # We probably should raise yet-another-warning - # here saying user that the hostname "XX.XX.XX.XX' does not - # match 'foo.bar.baz' - #api_cert_verified = True - - #if not api_cert_verified: - # XXX update validationMsg - # should catch exception - #return False - - #??? - #ca_cert_path = checker.ca_cert_path + api_uri = pconfig.get('api_uri', None) + try: + pCertChecker.verify_api_https(api_uri) + except requests.exceptions.SSLError as exc: + return self.fail("Validation Error") + except Exception as exc: + return self.fail(exc.msg) + else: + return True yield((self.tr('Validating api certificate'), 90), validatecacert) @@ -141,8 +132,8 @@ class ProviderSetupValidationPage(ValidationPage): called after _do_checks has finished (connected to checker thread finished signal) """ - prevpage = "providerselection" if self.is_signup else "login" wizard = self.wizard() + prevpage = "login" if wizard.from_login else "providerselection" if self.errors: logger.debug('going back with errors') diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index b04638e0..741b9267 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -224,11 +224,17 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): generator that yields actual checks that are executed in a separate thread """ + wizard = self.wizard() + provider = self.field('provider_domain') username = self.userNameLineEdit.text() password = self.userPasswordLineEdit.text() password2 = self.userPassword2LineEdit.text() + pconfig = wizard.eipconfigchecker(domain=provider) + pconfig.defaultprovider.load() + pconfig.set_api_domain() + def checkpass(): # we better have here # some call to a password checker... @@ -263,14 +269,11 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): self, "showStepsFrame") def register(): - # XXX FIXME! - verify = False signup = auth.LeapSRPRegister( schema="https", - provider=provider, - verify=verify) - #import ipdb;ipdb.set_trace() + provider=pconfig.apidomain, + verify=pconfig.cacert) try: ok, req = signup.register_user( username, password) @@ -381,7 +384,4 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): def nextId(self): wizard = self.wizard() - #if not wizard: - #return - # XXX this should be called connect - return wizard.get_page_index('signupvalidation') + return wizard.get_page_index('connect') -- cgit v1.2.3 From ade0eded09176fd687d1ee30724468c048d15065 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 11 Jan 2013 09:16:49 +0900 Subject: fix for missing cacert bundle frozen app cannot find requests cacert bundle. added to Resources to get us going. --- src/leap/gui/firstrun/providerselect.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index 28fb829c..ccecd519 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -287,8 +287,6 @@ class SelectProviderPage(InlineValidationPage): wizard.set_providerconfig( eipconfigchecker.defaultprovider.config) except requests.exceptions.SSLError: - # XXX we should have catched this before. - # but cert checking is broken. return self.fail(self.tr( "Could not get info from provider.")) except requests.exceptions.ConnectionError: -- cgit v1.2.3 From 407b030bb7d27b797fb27254710a358c9c69f8be Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 24 Jan 2013 01:57:28 +0900 Subject: catch missing messages on last page of wizard --- src/leap/gui/firstrun/connect.py | 51 +++++++++++++++++++++------------- src/leap/gui/firstrun/last.py | 27 ++++++++++++++---- src/leap/gui/firstrun/providersetup.py | 8 +----- src/leap/gui/firstrun/wizard.py | 1 + 4 files changed, 55 insertions(+), 32 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/connect.py b/src/leap/gui/firstrun/connect.py index b7688380..9d89b7ab 100644 --- a/src/leap/gui/firstrun/connect.py +++ b/src/leap/gui/firstrun/connect.py @@ -120,9 +120,11 @@ class ConnectionPage(ValidationPage): called after _do_checks has finished (connected to checker thread finished signal) """ - # this should be called CONNECT PAGE AGAIN. # here we go! :) if self.is_done(): + nextbutton = self.wizard().button(QtGui.QWizard.NextButton) + nextbutton.setFocus() + full_domain = self.field('provider_domain') domain, port = get_https_domain_and_port(full_domain) _domain = u"%s:%s" % ( @@ -138,10 +140,15 @@ class ConnectionPage(ValidationPage): if conductor: conductor.set_provider_domain(domain) - conductor.run_checks() - self.conductor = conductor - errors = self.eip_error_check() - if not errors and start_eip_signal: + # we could run some of the checks to be + # sure everything is in order, but + # I see no point in doing it, we assume + # we've gone thru all checks during the wizard. + #conductor.run_checks() + #self.conductor = conductor + #errors = self.eip_error_check() + #if not errors and start_eip_signal: + if start_eip_signal: start_eip_signal.emit() else: @@ -150,12 +157,6 @@ class ConnectionPage(ValidationPage): "probably the wizard has been launched " "in an stand-alone way.") - # XXX look for a better place to signal - # we are done. - # We could probably have a fake validatePage - # that checks if the domain transfer has been - # done to conductor object, triggers the start_signal - # and does the go_next() self.set_done() def eip_error_check(self): @@ -165,9 +166,13 @@ class ConnectionPage(ValidationPage): consumes the conductor error queue. pops errors, and add those to the wizard page """ - logger.debug('eip error check from connecting page') - errq = self.conductor.error_queue - # XXX missing! + # TODO handle errors. + # We should redirect them to the log viewer + # with a brief message. + # XXX move to LAST PAGE instead. + #logger.debug('eip error check from connecting page') + #errq = self.conductor.error_queue + pass def _do_validation(self): """ @@ -186,17 +191,25 @@ class ConnectionPage(ValidationPage): prevpage, first_error) self.go_back() - else: - logger.debug('should go next, wait for user to click next') - #self.go_next() def nextId(self): wizard = self.wizard() - #if not wizard: - #return return wizard.get_page_index('lastpage') def initializePage(self): super(ConnectionPage, self).initializePage() self.set_undone() + cancelbutton = self.wizard().button(QtGui.QWizard.CancelButton) + cancelbutton.hide() self.completeChanged.emit() + + wizard = self.wizard() + eip_statuschange_signal = wizard.eip_statuschange_signal + if eip_statuschange_signal: + eip_statuschange_signal.connect( + lambda status: self.send_status( + status)) + + def send_status(self, status): + wizard = self.wizard() + wizard.openvpn_status.append(status) diff --git a/src/leap/gui/firstrun/last.py b/src/leap/gui/firstrun/last.py index e097b2ae..32d98acc 100644 --- a/src/leap/gui/firstrun/last.py +++ b/src/leap/gui/firstrun/last.py @@ -15,7 +15,8 @@ class LastPage(QtGui.QWizardPage): def __init__(self, parent=None): super(LastPage, self).__init__(parent) - self.setTitle(self.tr("Connecting to Encrypted Internet Proxy service...")) + self.setTitle(self.tr( + "Connecting to Encrypted Internet Proxy service...")) self.setPixmap( QtGui.QWizard.LogoPixmap, @@ -33,6 +34,7 @@ class LastPage(QtGui.QWizardPage): self.status_line_2 = QtGui.QLabel() self.status_line_3 = QtGui.QLabel() self.status_line_4 = QtGui.QLabel() + self.status_line_5 = QtGui.QLabel() layout = QtGui.QVBoxLayout() layout.addWidget(self.label) @@ -42,6 +44,7 @@ class LastPage(QtGui.QWizardPage): layout.addWidget(self.status_line_2) layout.addWidget(self.status_line_3) layout.addWidget(self.status_line_4) + layout.addWidget(self.status_line_5) self.setLayout(layout) @@ -67,7 +70,7 @@ class LastPage(QtGui.QWizardPage): # signals. See progress.py logger.debug('logging status in last page') self.validation_done = False - status_count = 0 + status_count = 1 try: while True: status = (yield) @@ -84,11 +87,23 @@ class LastPage(QtGui.QWizardPage): pass def initializePage(self): + super(LastPage, self).initializePage() wizard = self.wizard() - if not wizard: - return - eip_status_handler = self.eip_status_handler() + handler = self.eip_status_handler() + + # get statuses done in prev page + for st in wizard.openvpn_status: + self.send_status(handler.send, st) + + # bind signal for events yet to come eip_statuschange_signal = wizard.eip_statuschange_signal if eip_statuschange_signal: eip_statuschange_signal.connect( - lambda status: eip_status_handler.send(status)) + lambda status: self.send_status( + handler.send, status)) + + def send_status(self, cb, status): + try: + cb(status) + except StopIteration: + pass diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index 981e3214..6017e4d3 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -141,18 +141,12 @@ class ProviderSetupValidationPage(ValidationPage): wizard.set_validation_error( prevpage, first_error) - # XXX don't go back, signal error - #self.go_back() - else: - logger.debug('should be going next, wait on user') - #self.go_next() def nextId(self): wizard = self.wizard() from_login = wizard.from_login if from_login: - # XXX bad name. change to connect again. - next_ = 'signupvalidation' + next_ = 'connect' else: next_ = 'signup' return wizard.get_page_index(next_) diff --git a/src/leap/gui/firstrun/wizard.py b/src/leap/gui/firstrun/wizard.py index 427f9df8..f198dca0 100755 --- a/src/leap/gui/firstrun/wizard.py +++ b/src/leap/gui/firstrun/wizard.py @@ -136,6 +136,7 @@ class FirstRunWizard(QtGui.QWizard): self.add_pages_from_dict(pages_dict) self.validation_errors = {} + self.openvpn_status = [] self.setPixmap( QtGui.QWizard.BannerPixmap, -- cgit v1.2.3 From ff59da55ef9a176b36cef19d67e7ec363bf5d739 Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 24 Jan 2013 02:30:00 +0900 Subject: wizard rephrasing & punctuation --- src/leap/gui/firstrun/connect.py | 59 ++++++++++++++++----------------- src/leap/gui/firstrun/intro.py | 6 ++-- src/leap/gui/firstrun/login.py | 2 +- src/leap/gui/firstrun/providerinfo.py | 9 +++-- src/leap/gui/firstrun/providerselect.py | 8 ++--- src/leap/gui/firstrun/providersetup.py | 2 +- src/leap/gui/firstrun/register.py | 4 +-- 7 files changed, 46 insertions(+), 44 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/connect.py b/src/leap/gui/firstrun/connect.py index 9d89b7ab..ad7bb13a 100644 --- a/src/leap/gui/firstrun/connect.py +++ b/src/leap/gui/firstrun/connect.py @@ -24,8 +24,8 @@ class ConnectionPage(ValidationPage): self.current_page = "connect" title = self.tr("Connecting...") - # XXX uh... really? - subtitle = self.tr("Checking connection with provider.") + subtitle = self.tr("Setting up a encrypted " + "connection with the provider") self.setTitle(title) self.setSubTitle(subtitle) @@ -82,7 +82,7 @@ class ConnectionPage(ValidationPage): except Exception as exc: return self.fail(exc.message) - yield((self.tr("Fetching provider config..."), 40), + yield((self.tr("Getting EIP configuration files"), 40), fetcheipconf) ################################################## @@ -94,7 +94,7 @@ class ConnectionPage(ValidationPage): downloaded = pCertChecker.download_new_client_cert( credentials=credentials) if not downloaded: - logger.error('Could not download client cert.') + logger.error('Could not download client cert') return False except auth.SRPAuthenticationError as exc: @@ -106,7 +106,7 @@ class ConnectionPage(ValidationPage): else: return True - yield((self.tr("Fetching eip certificate"), 80), + yield((self.tr("Getting EIP certificate"), 80), fetcheipcert) ################ @@ -159,38 +159,37 @@ class ConnectionPage(ValidationPage): self.set_done() - def eip_error_check(self): - """ - a version of the main app error checker, - but integrated within the connecting page of the wizard. - consumes the conductor error queue. - pops errors, and add those to the wizard page - """ + #def eip_error_check(self): + #""" + #a version of the main app error checker, + #but integrated within the connecting page of the wizard. + #consumes the conductor error queue. + #pops errors, and add those to the wizard page + #""" # TODO handle errors. # We should redirect them to the log viewer # with a brief message. # XXX move to LAST PAGE instead. #logger.debug('eip error check from connecting page') #errq = self.conductor.error_queue - pass - - def _do_validation(self): - """ - called after _do_checks has finished - (connected to checker thread finished signal) - """ - from_login = self.wizard().from_login - prevpage = "login" if from_login else "signup" - wizard = self.wizard() - if self.errors: - logger.debug('going back with errors') - logger.error(self.errors) - name, first_error = self.pop_first_error() - wizard.set_validation_error( - prevpage, - first_error) - self.go_back() + #def _do_validation(self): + #""" + #called after _do_checks has finished + #(connected to checker thread finished signal) + #""" + #from_login = self.wizard().from_login + #prevpage = "login" if from_login else "signup" + + #wizard = self.wizard() + #if self.errors: + #logger.debug('going back with errors') + #logger.error(self.errors) + #name, first_error = self.pop_first_error() + #wizard.set_validation_error( + #prevpage, + #first_error) + #self.go_back() def nextId(self): wizard = self.wizard() diff --git a/src/leap/gui/firstrun/intro.py b/src/leap/gui/firstrun/intro.py index 0425b764..b519362f 100644 --- a/src/leap/gui/firstrun/intro.py +++ b/src/leap/gui/firstrun/intro.py @@ -11,7 +11,7 @@ class IntroPage(QtGui.QWizardPage): def __init__(self, parent=None): super(IntroPage, self).__init__(parent) - self.setTitle(self.tr("First run wizard.")) + self.setTitle(self.tr("First run wizard")) #self.setPixmap( #QtGui.QWizard.WatermarkPixmap, @@ -35,10 +35,10 @@ class IntroPage(QtGui.QWizardPage): radiobuttonGroup = QtGui.QGroupBox() self.sign_up = QtGui.QRadioButton( - self.tr("Sign up for a new account.")) + self.tr("Sign up for a new account")) self.sign_up.setChecked(True) self.log_in = QtGui.QRadioButton( - self.tr("Log In with my credentials.")) + self.tr("Log In with my credentials")) radiobLayout = QtGui.QVBoxLayout() radiobLayout.addWidget(self.sign_up) diff --git a/src/leap/gui/firstrun/login.py b/src/leap/gui/firstrun/login.py index e39eecc0..3707d3ff 100644 --- a/src/leap/gui/firstrun/login.py +++ b/src/leap/gui/firstrun/login.py @@ -22,7 +22,7 @@ class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage self.current_page = "login" self.setTitle(self.tr("Log In")) - self.setSubTitle(self.tr("Log in with your credentials.")) + self.setSubTitle(self.tr("Log in with your credentials")) self.current_page = "login" self.setPixmap( diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index 357378df..cff4caca 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -16,9 +16,9 @@ class ProviderInfoPage(QtGui.QWizardPage): def __init__(self, parent=None): super(ProviderInfoPage, self).__init__(parent) - self.setTitle(self.tr("Provider Info")) + self.setTitle(self.tr("Provider Information")) self.setSubTitle(self.tr( - "This is what provider says.")) + "Services offered by this provider")) self.setPixmap( QtGui.QWizard.LogoPixmap, @@ -89,10 +89,13 @@ class ProviderInfoPage(QtGui.QWizardPage): self.description.setText( "%s" % description_text) + # XXX should translate this... enroll = pconfig.get('enrollment_policy') if enroll: self.enrollment_policy.setText( - 'enrollment policy: %s' % enroll) + '%s: %s' % ( + self.tr('enrollment policy'), + enroll)) def nextId(self): wizard = self.wizard() diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index ccecd519..917b16fd 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -32,7 +32,7 @@ class SelectProviderPage(InlineValidationPage): self.setTitle(self.tr("Enter Provider")) self.setSubTitle(self.tr( "Please enter the domain of the provider you want " - "to use for your connection.") + "to use for your connection") ) self.setPixmap( QtGui.QWizard.LogoPixmap, @@ -219,7 +219,7 @@ class SelectProviderPage(InlineValidationPage): return True logger.debug('checking name resolution') - yield((self.tr("checking domain name"), 20), namecheck) + yield((self.tr("Checking if it is a valid provider"), 20), namecheck) ######################### # 2) try https connection @@ -273,7 +273,7 @@ class SelectProviderPage(InlineValidationPage): return True logger.debug('checking https connection') - yield((self.tr("checking https connection"), 40), httpscheck) + yield((self.tr("Checking for a secure connection"), 40), httpscheck) ################################## # 3) try download provider info... @@ -300,7 +300,7 @@ class SelectProviderPage(InlineValidationPage): else: return True - yield((self.tr("fetching provider info"), 80), fetchinfo) + yield((self.tr("Getting info from the provider"), 80), fetchinfo) # done! diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index 6017e4d3..47060f6e 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -27,7 +27,7 @@ class ProviderSetupValidationPage(ValidationPage): self.setTitle(self.tr("Provider setup")) self.setSubTitle( - self.tr("Doing autoconfig.")) + self.tr("Gathering configuration options for this provider")) self.setPixmap( QtGui.QWizard.LogoPixmap, diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index 741b9267..15278330 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -315,7 +315,7 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): return True logger.debug('registering user') - yield(("registering with provider", 40), register) + yield(("Registering username", 40), register) self.set_done() yield(("end_sentinel", 100), lambda: None) @@ -376,7 +376,7 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): #self.tr("Register a new user with provider %s.") % #provider) self.setSubTitle( - self.tr("Register a new user with provider %s." % + self.tr("Register a new user with provider %s" % provider)) self.validationMsg.setText('') self.userPassword2LineEdit.setText('') -- cgit v1.2.3 From 19da34c598ce6db172c1e1a8978bf031fc6db89b Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 24 Jan 2013 20:07:06 +0900 Subject: check cert time_boundaries uses pyOpenSSL I had missed this one while deprecating gnutls --- src/leap/gui/firstrun/tests/integration/fake_provider.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/tests/integration/fake_provider.py b/src/leap/gui/firstrun/tests/integration/fake_provider.py index 445b4487..668db5d1 100755 --- a/src/leap/gui/firstrun/tests/integration/fake_provider.py +++ b/src/leap/gui/firstrun/tests/integration/fake_provider.py @@ -25,9 +25,9 @@ import sys import srp # GnuTLS Example -- is not working as expected -from gnutls import crypto -from gnutls.constants import COMP_LZO, COMP_DEFLATE, COMP_NULL -from gnutls.interfaces.twisted import X509Credentials +#from gnutls import crypto +#from gnutls.constants import COMP_LZO, COMP_DEFLATE, COMP_NULL +#from gnutls.interfaces.twisted import X509Credentials # Going with OpenSSL as a workaround instead # But we DO NOT want to introduce this dependency. -- cgit v1.2.3 From 71cd4575a2641272f966cdb47a4f9504f31668a5 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 25 Jan 2013 18:13:15 +0900 Subject: disable finish button until connected --- src/leap/gui/firstrun/last.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/last.py b/src/leap/gui/firstrun/last.py index 32d98acc..f3e467db 100644 --- a/src/leap/gui/firstrun/last.py +++ b/src/leap/gui/firstrun/last.py @@ -29,6 +29,8 @@ class LastPage(QtGui.QWizardPage): self.label = QtGui.QLabel() self.label.setWordWrap(True) + self.wizard_done = False + # XXX REFACTOR to a Validating Page... self.status_line_1 = QtGui.QLabel() self.status_line_2 = QtGui.QLabel() @@ -48,6 +50,9 @@ class LastPage(QtGui.QWizardPage): self.setLayout(layout) + def isComplete(self): + return self.wizard_done + def set_status_line(self, line, status): statusline = getattr(self, 'status_line_%s' % line) if statusline: @@ -61,8 +66,8 @@ class LastPage(QtGui.QWizardPage): self.label.setText(self.tr( "Click '%s' to end the wizard and " "save your settings." % finishText)) - # XXX init network checker - # trigger signal + self.wizard_done = True + self.completeChanged.emit() @coroutine def eip_status_handler(self): @@ -80,7 +85,9 @@ class LastPage(QtGui.QWizardPage): self.set_status_line(status_count, status) if status == "connected": self.set_finished_status() + self.completeChanged.emit() break + self.completeChanged.emit() except GeneratorExit: pass except StopIteration: @@ -89,6 +96,8 @@ class LastPage(QtGui.QWizardPage): def initializePage(self): super(LastPage, self).initializePage() wizard = self.wizard() + wizard.button(QtGui.QWizard.FinishButton).setDisabled(True) + handler = self.eip_status_handler() # get statuses done in prev page @@ -101,6 +110,7 @@ class LastPage(QtGui.QWizardPage): eip_statuschange_signal.connect( lambda status: self.send_status( handler.send, status)) + self.completeChanged.emit() def send_status(self, cb, status): try: -- cgit v1.2.3 From 1e9ba29d0f1e12b95536099e29396a1f35908381 Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 31 Jan 2013 05:47:45 +0900 Subject: pep8 --- src/leap/gui/firstrun/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/__init__.py b/src/leap/gui/firstrun/__init__.py index 2a523d6a..d802fa1f 100644 --- a/src/leap/gui/firstrun/__init__.py +++ b/src/leap/gui/firstrun/__init__.py @@ -25,4 +25,4 @@ __all__ = [ 'providerselect', 'providersetup', 'register', - ] # ,'wizard'] +] # ,'wizard'] -- cgit v1.2.3 From 8ace73da712bd020146e80c8a3821f79dd53384a Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 31 Jan 2013 23:59:57 +0900 Subject: fix exception message attribute --- src/leap/gui/firstrun/providersetup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index 47060f6e..157a5183 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -118,7 +118,7 @@ class ProviderSetupValidationPage(ValidationPage): except requests.exceptions.SSLError as exc: return self.fail("Validation Error") except Exception as exc: - return self.fail(exc.msg) + return self.fail(exc.message) else: return True -- cgit v1.2.3 From 0f9a1d4bc85def69dae0621eb7daaf5a0ee48004 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 1 Feb 2013 00:49:10 +0900 Subject: add watermark image to wizard --- src/leap/gui/firstrun/connect.py | 6 +++++- src/leap/gui/firstrun/intro.py | 8 ++++---- src/leap/gui/firstrun/last.py | 10 +++++----- src/leap/gui/firstrun/login.py | 6 +++++- src/leap/gui/firstrun/providerinfo.py | 6 +++++- src/leap/gui/firstrun/providerselect.py | 6 +++++- src/leap/gui/firstrun/providersetup.py | 6 +++++- src/leap/gui/firstrun/register.py | 6 +++++- 8 files changed, 39 insertions(+), 15 deletions(-) (limited to 'src/leap/gui/firstrun') diff --git a/src/leap/gui/firstrun/connect.py b/src/leap/gui/firstrun/connect.py index ad7bb13a..209174a1 100644 --- a/src/leap/gui/firstrun/connect.py +++ b/src/leap/gui/firstrun/connect.py @@ -12,7 +12,7 @@ from leap.gui.progress import ValidationPage from leap.util.web import get_https_domain_and_port from leap.base import auth -from leap.gui.constants import APP_LOGO +from leap.gui.constants import APP_LOGO, APP_WATERMARK logger = logging.getLogger(__name__) @@ -30,6 +30,10 @@ class ConnectionPage(ValidationPage): self.setTitle(title) self.setSubTitle(subtitle) + self.setPixmap( + QtGui.QWizard.WatermarkPixmap, + QtGui.QPixmap(APP_WATERMARK)) + self.setPixmap( QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) diff --git a/src/leap/gui/firstrun/intro.py b/src/leap/gui/firstrun/intro.py index b519362f..8e5014e6 100644 --- a/src/leap/gui/firstrun/intro.py +++ b/src/leap/gui/firstrun/intro.py @@ -4,7 +4,7 @@ Intro page used in first run wizard from PyQt4 import QtGui -from leap.gui.constants import APP_LOGO +from leap.gui.constants import APP_LOGO, APP_WATERMARK class IntroPage(QtGui.QWizardPage): @@ -13,9 +13,9 @@ class IntroPage(QtGui.QWizardPage): self.setTitle(self.tr("First run wizard")) - #self.setPixmap( - #QtGui.QWizard.WatermarkPixmap, - #QtGui.QPixmap(':/images/watermark1.png')) + self.setPixmap( + QtGui.QWizard.WatermarkPixmap, + QtGui.QPixmap(APP_WATERMARK)) self.setPixmap( QtGui.QWizard.LogoPixmap, diff --git a/src/leap/gui/firstrun/last.py b/src/leap/gui/firstrun/last.py index f3e467db..6a01ba34 100644 --- a/src/leap/gui/firstrun/last.py +++ b/src/leap/gui/firstrun/last.py @@ -6,7 +6,7 @@ import logging from PyQt4 import QtGui from leap.util.coroutines import coroutine -from leap.gui.constants import APP_LOGO +from leap.gui.constants import APP_LOGO, APP_WATERMARK logger = logging.getLogger(__name__) @@ -18,14 +18,14 @@ class LastPage(QtGui.QWizardPage): self.setTitle(self.tr( "Connecting to Encrypted Internet Proxy service...")) + self.setPixmap( + QtGui.QWizard.WatermarkPixmap, + QtGui.QPixmap(APP_WATERMARK)) + self.setPixmap( QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) - #self.setPixmap( - #QtGui.QWizard.WatermarkPixmap, - #QtGui.QPixmap(':/images/watermark2.png')) - self.label = QtGui.QLabel() self.label.setWordWrap(True) diff --git a/src/leap/gui/firstrun/login.py b/src/leap/gui/firstrun/login.py index 3707d3ff..1efceaa9 100644 --- a/src/leap/gui/firstrun/login.py +++ b/src/leap/gui/firstrun/login.py @@ -11,7 +11,7 @@ from leap.gui.firstrun.mixins import UserFormMixIn from leap.gui.progress import InlineValidationPage from leap.gui import styles -from leap.gui.constants import APP_LOGO, FULL_USERNAME_REGEX +from leap.gui.constants import APP_LOGO, APP_WATERMARK, FULL_USERNAME_REGEX class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage @@ -25,6 +25,10 @@ class LogInPage(InlineValidationPage, UserFormMixIn): # InlineValidationPage self.setSubTitle(self.tr("Log in with your credentials")) self.current_page = "login" + self.setPixmap( + QtGui.QWizard.WatermarkPixmap, + QtGui.QPixmap(APP_WATERMARK)) + self.setPixmap( QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) diff --git a/src/leap/gui/firstrun/providerinfo.py b/src/leap/gui/firstrun/providerinfo.py index cff4caca..3385e9e7 100644 --- a/src/leap/gui/firstrun/providerinfo.py +++ b/src/leap/gui/firstrun/providerinfo.py @@ -5,7 +5,7 @@ import logging from PyQt4 import QtGui -from leap.gui.constants import APP_LOGO +from leap.gui.constants import APP_LOGO, APP_WATERMARK from leap.util.translations import translate logger = logging.getLogger(__name__) @@ -20,6 +20,10 @@ class ProviderInfoPage(QtGui.QWizardPage): self.setSubTitle(self.tr( "Services offered by this provider")) + self.setPixmap( + QtGui.QWizard.WatermarkPixmap, + QtGui.QPixmap(APP_WATERMARK)) + self.setPixmap( QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) diff --git a/src/leap/gui/firstrun/providerselect.py b/src/leap/gui/firstrun/providerselect.py index 917b16fd..36bb4510 100644 --- a/src/leap/gui/firstrun/providerselect.py +++ b/src/leap/gui/firstrun/providerselect.py @@ -16,7 +16,7 @@ from leap.gui import styles from leap.gui.utils import delay from leap.util.web import get_https_domain_and_port -from leap.gui.constants import APP_LOGO +from leap.gui.constants import APP_LOGO, APP_WATERMARK logger = logging.getLogger(__name__) @@ -34,6 +34,10 @@ class SelectProviderPage(InlineValidationPage): "Please enter the domain of the provider you want " "to use for your connection") ) + self.setPixmap( + QtGui.QWizard.WatermarkPixmap, + QtGui.QPixmap(APP_WATERMARK)) + self.setPixmap( QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) diff --git a/src/leap/gui/firstrun/providersetup.py b/src/leap/gui/firstrun/providersetup.py index 157a5183..40a14048 100644 --- a/src/leap/gui/firstrun/providersetup.py +++ b/src/leap/gui/firstrun/providersetup.py @@ -11,7 +11,7 @@ from PyQt4 import QtGui from leap.base import exceptions as baseexceptions from leap.gui.progress import ValidationPage -from leap.gui.constants import APP_LOGO +from leap.gui.constants import APP_LOGO, APP_WATERMARK logger = logging.getLogger(__name__) @@ -29,6 +29,10 @@ class ProviderSetupValidationPage(ValidationPage): self.setSubTitle( self.tr("Gathering configuration options for this provider")) + self.setPixmap( + QtGui.QWizard.WatermarkPixmap, + QtGui.QPixmap(APP_WATERMARK)) + self.setPixmap( QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) diff --git a/src/leap/gui/firstrun/register.py b/src/leap/gui/firstrun/register.py index 15278330..2ae926d1 100644 --- a/src/leap/gui/firstrun/register.py +++ b/src/leap/gui/firstrun/register.py @@ -16,7 +16,7 @@ logger = logging.getLogger(__name__) from leap.base import auth from leap.gui import styles -from leap.gui.constants import APP_LOGO, BARE_USERNAME_REGEX +from leap.gui.constants import APP_LOGO, APP_WATERMARK, BARE_USERNAME_REGEX from leap.gui.progress import InlineValidationPage from leap.gui.styles import ErrorLabelStyleSheet @@ -31,6 +31,10 @@ class RegisterUserPage(InlineValidationPage, UserFormMixIn): self.setTitle(self.tr("Sign Up")) # subtitle is set in the initializePage + self.setPixmap( + QtGui.QWizard.WatermarkPixmap, + QtGui.QPixmap(APP_WATERMARK)) + self.setPixmap( QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) -- cgit v1.2.3