From c7eaaf710d0963396bd1658bebe7fc36a0deb80b Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 17 Oct 2012 05:35:43 +0900 Subject: added skeleton for generic client wizard flow --- src/leap/gui/firstrunwizard.py | 347 +++++++++++++++++++++++++++++++++-------- 1 file changed, 280 insertions(+), 67 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index a76865fd..0cf46956 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -13,7 +13,16 @@ from PyQt4 import QtGui from leap.crypto import leapkeyring 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 + +# XXX DEBUG +logging.basicConfig() logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) APP_LOGO = ':/images/leap-color-small.png' @@ -77,7 +86,7 @@ class LeapSRPRegister(object): def register_user(self, username, password, keep=False): """ @rtype: tuple - @rvalue: (ok, request) + @rparam: (ok, request) """ salt, vkey = self.srp.create_salted_verification_key( username, @@ -116,7 +125,7 @@ class FirstRunWizard(QtGui.QWizard): def __init__( self, parent=None, providers=None, - success_cb=None): + success_cb=None, is_provider_setup=False): super(FirstRunWizard, self).__init__( parent, QtCore.Qt.WindowStaysOnTopHint) @@ -129,12 +138,30 @@ class FirstRunWizard(QtGui.QWizard): # success callback self.success_cb = success_cb - self.addPage(IntroPage()) - self.addPage(SelectProviderPage(providers=providers)) - - self.addPage(RegisterUserPage(wizard=self)) - #self.addPage(GlobalEIPSettings()) - self.addPage(LastPage()) + # is provider setup? + self.is_provider_setup = is_provider_setup + + # FIXME remove kwargs, we can access + # wizard as self.wizard() + + # FIXME add param for previously_registered + # should start at login page. + + pages_dict = OrderedDict(( + # (name, (WizardPage, **kwargs)) + ('intro', (IntroPage, {})), + ('providerselection', ( + SelectProviderPage, + {'providers': providers})), + ('login', (LogInPage, {})), + ('providerinfo', (ProviderInfoPage, {})), + ('providersetup', (ProviderSetupPage, {})), + ('signup', ( + RegisterUserPage, {})), + ('connecting', (ConnectingPage, {})), + ('lastpage', (LastPage, {})) + )) + self.add_pages_from_dict(pages_dict) self.setPixmap( QtGui.QWizard.BannerPixmap, @@ -148,6 +175,41 @@ class FirstRunWizard(QtGui.QWizard): # 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, page_args) in pages_dict.items(): + self.addPage(page(**page_args)) + 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 get_page(self, page_name): + #""" + #returns a wizard page doing a lookup for + #the page_name in the pages dictionary + #@param page_name: the page name to lookup + #@type page_name: str + #""" + #logger.debug('getting page %s' % page_name) + #page_tuple = self.pages_dict.get(page_name, None) + #if not page_tuple: + #return None + #wizard_page, args = page_tuple + #logger.debug('wizard page %s', wizard_page) + #return wizard_page + def setWindowFlags(self, flags): logger.debug('setting window flags') QtGui.QWizard.setWindowFlags(self, flags) @@ -224,14 +286,40 @@ class IntroPage(QtGui.QWizardPage): "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 of the Leap App.") - + "main window.

" + "Do you want to sign up for a new account, or log " + "in with an already existing username?
") label.setWordWrap(True) + 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.") + layout = QtGui.QVBoxLayout() layout.addWidget(label) + layout.addWidget(self.sign_up) + layout.addWidget(self.log_in) 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_) + class SelectProviderPage(QtGui.QWizardPage): def __init__(self, parent=None, providers=None): @@ -263,74 +351,54 @@ class SelectProviderPage(QtGui.QWizardPage): layout.addWidget(providerNameSelect, 0, 1) self.setLayout(layout) + def validatePage(self): + # XXX just DEBUGGING ..>! + wizard = self.wizard() + if bool(wizard): + logger.debug('current: %s', wizard.currentPage()) + return True -class RegisterUserPage(QtGui.QWizardPage): - setSigningUpStatus = QtCore.pyqtSignal([]) - - def __init__(self, parent=None, wizard=None): - super(RegisterUserPage, self).__init__(parent) - - # bind wizard page signals - self.setSigningUpStatus.connect( - self.set_status_validating) - - # XXX check for no wizard pased - # getting provider from previous step - provider = wizard.get_provider() - - self.setTitle("User registration") - self.setSubTitle( - "Register a new user with provider %s." % - provider) - self.setPixmap( - QtGui.QWizard.LogoPixmap, - QtGui.QPixmap(APP_LOGO)) - - rememberPasswordCheckBox = QtGui.QCheckBox( - "&Remember password.") - rememberPasswordCheckBox.setChecked(True) - - userNameLabel = QtGui.QLabel("User &name:") - userNameLineEdit = QtGui.QLineEdit() - userNameLineEdit.cursorPositionChanged.connect( - self.reset_validation_status) - userNameLabel.setBuddy(userNameLineEdit) - - # add regex validator - usernameRe = QtCore.QRegExp(r"^[A-Za-z\d_]+$") - userNameLineEdit.setValidator( - QtGui.QRegExpValidator(usernameRe, self)) - self.userNameLineEdit = userNameLineEdit + def nextId(self): + wizard = self.wizard() + if not wizard: + return + return wizard.get_page_index('providerinfo') - userPasswordLabel = QtGui.QLabel("&Password:") - self.userPasswordLineEdit = QtGui.QLineEdit() - self.userPasswordLineEdit.setEchoMode( - QtGui.QLineEdit.Password) - userPasswordLabel.setBuddy(self.userPasswordLineEdit) +class ProviderInfoPage(QtGui.QWizardPage): + def __init__(self, parent=None): + super(ProviderInfoPage, self).__init__(parent) - self.registerField('userName', self.userNameLineEdit) - self.registerField('userPassword', self.userPasswordLineEdit) - self.registerField('rememberPassword', rememberPasswordCheckBox) + self.setTitle("Provider Info") + self.setSubTitle("Available information about chosen provider.") - layout = QtGui.QGridLayout() - layout.setColumnMinimumWidth(0, 20) + def nextId(self): + wizard = self.wizard() + if not wizard: + return + return wizard.get_page_index('providersetup') - validationMsg = QtGui.QLabel("") - validationMsg.setStyleSheet(ErrorLabelStyleSheet) - self.validationMsg = validationMsg +class ProviderSetupPage(QtGui.QWizardPage): + def __init__(self, parent=None): + super(ProviderSetupPage, self).__init__(parent) - layout.addWidget(validationMsg, 0, 3) + self.setTitle("Provider Setup") + self.setSubTitle("Setting up provider.") - layout.addWidget(userNameLabel, 1, 0) - layout.addWidget(self.userNameLineEdit, 1, 3) + 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_) - layout.addWidget(userPasswordLabel, 2, 0) - layout.addWidget(self.userPasswordLineEdit, 2, 3) - layout.addWidget(rememberPasswordCheckBox, 3, 3, 3, 4) - self.setLayout(layout) +class UserFormMixIn(object): def reset_validation_status(self): """ @@ -352,6 +420,8 @@ class RegisterUserPage(QtGui.QWizardPage): self.validationMsg.setText('registering...') # need to call update somehow??? + # XXX refactor set_status_foo + def set_status_invalid_username(self): """ set validation msg to @@ -389,6 +459,130 @@ class RegisterUserPage(QtGui.QWizardPage): """ self.validationMsg.setText("Error during signup") + +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.") + + userNameLabel = QtGui.QLabel("User &name:") + userNameLineEdit = QtGui.QLineEdit() + userNameLineEdit.cursorPositionChanged.connect( + self.reset_validation_status) + userNameLabel.setBuddy(userNameLineEdit) + + # add regex validator + usernameRe = QtCore.QRegExp(r"^[A-Za-z\d_]+$") + 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('log_in_userName*', self.userNameLineEdit) + self.registerField('log_in_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) + + 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_) + + +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( + self.set_status_validating) + + wizard = self.wizard() + provider = wizard.get_provider() if wizard else None + + self.setTitle("User registration") + self.setSubTitle( + "Register a new user with provider %s." % + provider) + 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) + + # add regex validator + usernameRe = QtCore.QRegExp(r"^[A-Za-z\d_]+$") + 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) + + rememberPasswordCheckBox = QtGui.QCheckBox( + "&Remember username and password.") + rememberPasswordCheckBox.setChecked(True) + + self.registerField('userName*', self.userNameLineEdit) + self.registerField('userPassword*', self.userPasswordLineEdit) + 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(self.userPasswordLineEdit, 2, 3) + + layout.addWidget(rememberPasswordCheckBox, 3, 3, 3, 4) + self.setLayout(layout) + # overwritten methods def initializePage(self): @@ -456,17 +650,36 @@ class RegisterUserPage(QtGui.QWizardPage): 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_status_invalid_username() else: self.set_status_unknown_error() return False + def nextId(self): + wizard = self.wizard() + if not wizard: + return + return wizard.get_page_index('connecting') + class GlobalEIPSettings(QtGui.QWizardPage): + """ + not in use right now + """ def __init__(self, parent=None): super(GlobalEIPSettings, self).__init__(parent) +class ConnectingPage(QtGui.QWizardPage): + def __init__(self, parent=None): + super(ConnectingPage, self).__init__(parent) + + self.setTitle("Connecting") + self.setSubTitle('Connecting to provider.') + + class LastPage(QtGui.QWizardPage): def __init__(self, parent=None): super(LastPage, self).__init__(parent) -- cgit v1.2.3 From 28dcbfbc6e3a61d47c2a1218bce5d2693c77d04d Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 17 Oct 2012 06:14:57 +0900 Subject: moved srp registration to base and some minor changes in wizard, like textentry for provider. --- src/leap/gui/firstrunwizard.py | 206 +++++++++++++++-------------------------- 1 file changed, 77 insertions(+), 129 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index 0cf46956..bc36a35f 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -10,6 +10,7 @@ sip.setapi('QVariant', 2) from PyQt4 import QtCore from PyQt4 import QtGui +from leap.base.auth import LeapSRPRegister from leap.crypto import leapkeyring from leap.gui import mainwindow_rc @@ -26,94 +27,6 @@ logger.setLevel(logging.DEBUG) APP_LOGO = ':/images/leap-color-small.png' -# registration ###################### -# move to base/ -import binascii - -import requests -import srp - -from leap.base import constants as baseconstants - -SIGNUP_TIMEOUT = getattr(baseconstants, 'SIGNUP_TIMEOUT', 5) - - -class LeapSRPRegister(object): - - def __init__(self, - schema="https", - provider=None, - port=None, - register_path="1/users.json", - method="POST", - fetcher=requests, - srp=srp, - hashfun=srp.SHA256, - ng_constant=srp.NG_1024): - - self.schema = schema - self.provider = provider - self.port = port - self.register_path = register_path - self.method = method - self.fetcher = fetcher - self.srp = srp - self.HASHFUN = hashfun - self.NG = ng_constant - - self.init_session() - - def init_session(self): - self.session = self.fetcher.session() - - def get_registration_uri(self): - # XXX assert is https! - # use urlparse - if self.port: - uri = "%s://%s:%s/%s" % ( - self.schema, - self.provider, - self.port, - self.register_path) - else: - uri = "%s://%s/%s" % ( - self.schema, - self.provider, - self.register_path) - - return uri - - def register_user(self, username, password, keep=False): - """ - @rtype: tuple - @rparam: (ok, request) - """ - salt, vkey = self.srp.create_salted_verification_key( - username, - password, - self.HASHFUN, - self.NG) - - user_data = { - 'user[login]': username, - 'user[password_verifier]': binascii.hexlify(vkey), - 'user[password_salt]': binascii.hexlify(salt)} - - uri = self.get_registration_uri() - logger.debug('post to uri: %s' % uri) - - # XXX get self.method - req = self.session.post( - uri, data=user_data, - timeout=SIGNUP_TIMEOUT) - logger.debug(req) - logger.debug('user_data: %s', user_data) - #logger.debug('response: %s', req.text) - # we catch it in the form - #req.raise_for_status() - return (req.ok, req) - -###################################### ErrorLabelStyleSheet = """ QLabel { color: red; @@ -125,14 +38,15 @@ class FirstRunWizard(QtGui.QWizard): def __init__( self, parent=None, providers=None, - success_cb=None, is_provider_setup=False): + success_cb=None, is_provider_setup=False, + is_previously_registered=False): super(FirstRunWizard, self).__init__( parent, QtCore.Qt.WindowStaysOnTopHint) # XXX hardcoded for tests - if not providers: - providers = ('springbok',) + #if not providers: + #providers = ('springbok',) self.providers = providers # success callback @@ -141,6 +55,10 @@ class FirstRunWizard(QtGui.QWizard): # is provider setup? self.is_provider_setup = is_provider_setup + # previously registered + # if True, jumps to LogIn page. + self.is_previously_registered = is_previously_registered + # FIXME remove kwargs, we can access # wizard as self.wizard() @@ -182,6 +100,8 @@ class FirstRunWizard(QtGui.QWizard): @type pages_dict: dict """ for name, (page, page_args) in pages_dict.items(): + # XXX check for is_previously registered + # and skip adding the signup branch if so self.addPage(page(**page_args)) self.pages_dict = pages_dict @@ -195,21 +115,6 @@ class FirstRunWizard(QtGui.QWizard): """ return self.pages_dict.keys().index(page_name) - #def get_page(self, page_name): - #""" - #returns a wizard page doing a lookup for - #the page_name in the pages dictionary - #@param page_name: the page name to lookup - #@type page_name: str - #""" - #logger.debug('getting page %s' % page_name) - #page_tuple = self.pages_dict.get(page_name, None) - #if not page_tuple: - #return None - #wizard_page, args = page_tuple - #logger.debug('wizard page %s', wizard_page) - #return wizard_page - def setWindowFlags(self, flags): logger.debug('setting window flags') QtGui.QWizard.setWindowFlags(self, flags) @@ -257,7 +162,7 @@ class FirstRunWizard(QtGui.QWizard): if cb and callable(cb): self.success_cb() - def get_provider(self): + def get_provider_by_index(self): provider = self.field('provider_index') return self.providers[provider] @@ -280,6 +185,10 @@ class IntroPage(QtGui.QWizardPage): #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 " @@ -327,7 +236,7 @@ class SelectProviderPage(QtGui.QWizardPage): self.setTitle("Select Provider") self.setSubTitle( - "Please select which provider do you want " + "Please enter the domain of the provider you want " "to use for your connection." ) self.setPixmap( @@ -335,27 +244,47 @@ class SelectProviderPage(QtGui.QWizardPage): QtGui.QPixmap(APP_LOGO)) providerNameLabel = QtGui.QLabel("&Provider:") + 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 - providercombo = QtGui.QComboBox() - if providers: - for provider in providers: - providercombo.addItem(provider) - providerNameSelect = providercombo + # Eventually we will seed a list of + # well known providers here. - providerNameLabel.setBuddy(providerNameSelect) + #providercombo = QtGui.QComboBox() + #if providers: + #for provider in providers: + #providercombo.addItem(provider) + #providerNameSelect = providercombo - self.registerField('provider_index', providerNameSelect) + self.registerField('provider_domain*', self.providerNameEdit) + #self.registerField('provider_name_index', providerNameSelect) + + validationMsg = QtGui.QLabel("") + validationMsg.setStyleSheet(ErrorLabelStyleSheet) + + self.validationMsg = validationMsg layout = QtGui.QGridLayout() - layout.addWidget(providerNameLabel, 0, 0) - layout.addWidget(providerNameSelect, 0, 1) + layout.addWidget(validationMsg, 0, 0) + layout.addWidget(providerNameLabel, 0, 1) + layout.addWidget(providerNameEdit, 0, 2) self.setLayout(layout) + def reset_validation_status(self): + """ + empty the validation msg + """ + self.validationMsg.setText('') + def validatePage(self): - # XXX just DEBUGGING ..>! - wizard = self.wizard() - if bool(wizard): - logger.debug('current: %s', wizard.currentPage()) return True def nextId(self): @@ -372,6 +301,10 @@ class ProviderInfoPage(QtGui.QWizardPage): self.setTitle("Provider Info") self.setSubTitle("Available information about chosen provider.") + self.setPixmap( + QtGui.QWizard.LogoPixmap, + QtGui.QPixmap(APP_LOGO)) + def nextId(self): wizard = self.wizard() if not wizard: @@ -386,6 +319,10 @@ class ProviderSetupPage(QtGui.QWizardPage): self.setTitle("Provider Setup") self.setSubTitle("Setting up provider.") + self.setPixmap( + QtGui.QWizard.LogoPixmap, + QtGui.QPixmap(APP_LOGO)) + def nextId(self): wizard = self.wizard() if not wizard: @@ -457,7 +394,7 @@ class UserFormMixIn(object): set validation msg to unknown error """ - self.validationMsg.setText("Error during signup") + self.validationMsg.setText("Error during sign up") class LogInPage(QtGui.QWizardPage, UserFormMixIn): @@ -467,6 +404,10 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): 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( @@ -527,13 +468,8 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): self.setSigningUpStatus.connect( self.set_status_validating) - wizard = self.wizard() - provider = wizard.get_provider() if wizard else None + self.setTitle("Sign Up") - self.setTitle("User registration") - self.setSubTitle( - "Register a new user with provider %s." % - provider) self.setPixmap( QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) @@ -589,6 +525,10 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): """ inits wizard page """ + provider = self.field('provider_domain') + self.setSubTitle( + "Register a new user with provider %s." % + provider) self.validationMsg.setText('') def validatePage(self): @@ -679,6 +619,10 @@ class ConnectingPage(QtGui.QWizardPage): self.setTitle("Connecting") self.setSubTitle('Connecting to provider.') + self.setPixmap( + QtGui.QWizard.LogoPixmap, + QtGui.QPixmap(APP_LOGO)) + class LastPage(QtGui.QWizardPage): def __init__(self, parent=None): @@ -686,6 +630,10 @@ class LastPage(QtGui.QWizardPage): self.setTitle("Ready to go!") + self.setPixmap( + QtGui.QWizard.LogoPixmap, + QtGui.QPixmap(APP_LOGO)) + #self.setPixmap( #QtGui.QWizard.WatermarkPixmap, #QtGui.QPixmap(':/images/watermark2.png')) @@ -715,6 +663,6 @@ if __name__ == '__main__': logger.setLevel(logging.DEBUG) app = QtGui.QApplication(sys.argv) - wizard = FirstRunWizard() + wizard = FirstRunWizard(providers=('springbok',)) wizard.show() sys.exit(app.exec_()) -- cgit v1.2.3 From e1dbfc454180a77ebb38ecae6244ac4abe6d0ac5 Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 18 Oct 2012 09:30:53 +0900 Subject: catch cert verification errors and ask user for trust with a little helper function using gnutls --- src/leap/gui/firstrunwizard.py | 128 +++++++++++++++++++++++++++++++++-------- 1 file changed, 105 insertions(+), 23 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index bc36a35f..53e551ac 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -11,7 +11,12 @@ from PyQt4 import QtCore from PyQt4 import QtGui from leap.base.auth import LeapSRPRegister +from leap.base import checks as basechecks +from leap.base import exceptions as baseexceptions +from leap.crypto import certs from leap.crypto import leapkeyring +from leap.eip import checks as eipchecks +from leap.eip import exceptions as eipexceptions from leap.gui import mainwindow_rc try: @@ -39,7 +44,10 @@ class FirstRunWizard(QtGui.QWizard): def __init__( self, parent=None, providers=None, success_cb=None, is_provider_setup=False, - is_previously_registered=False): + is_previously_registered=False, + netchecker=basechecks.LeapNetworkChecker, + providercertchecker=eipchecks.ProviderCertChecker, + eipconfigchecker=eipchecks.EIPConfigChecker): super(FirstRunWizard, self).__init__( parent, QtCore.Qt.WindowStaysOnTopHint) @@ -59,25 +67,25 @@ class FirstRunWizard(QtGui.QWizard): # if True, jumps to LogIn page. self.is_previously_registered = is_previously_registered - # FIXME remove kwargs, we can access - # wizard as self.wizard() + # Checkers + self.netchecker = netchecker + self.providercertchecker = providercertchecker + self.eipconfigchecker = eipconfigchecker # FIXME add param for previously_registered # should start at login page. pages_dict = OrderedDict(( - # (name, (WizardPage, **kwargs)) - ('intro', (IntroPage, {})), - ('providerselection', ( - SelectProviderPage, - {'providers': providers})), - ('login', (LogInPage, {})), - ('providerinfo', (ProviderInfoPage, {})), - ('providersetup', (ProviderSetupPage, {})), - ('signup', ( - RegisterUserPage, {})), - ('connecting', (ConnectingPage, {})), - ('lastpage', (LastPage, {})) + # (name, WizardPage) + ('intro', IntroPage), + ('providerselection', + SelectProviderPage), + ('login', LogInPage), + ('providerinfo', ProviderInfoPage), + ('providersetup', ProviderSetupPage), + ('signup', RegisterUserPage), + ('connecting', ConnectingPage), + ('lastpage', LastPage) )) self.add_pages_from_dict(pages_dict) @@ -99,10 +107,10 @@ class FirstRunWizard(QtGui.QWizard): values are a tuple of InstanceofWizardPage, kwargs. @type pages_dict: dict """ - for name, (page, page_args) in pages_dict.items(): + for name, page in pages_dict.items(): # XXX check for is_previously registered # and skip adding the signup branch if so - self.addPage(page(**page_args)) + self.addPage(page()) self.pages_dict = pages_dict def get_page_index(self, page_name): @@ -234,7 +242,7 @@ class SelectProviderPage(QtGui.QWizardPage): def __init__(self, parent=None, providers=None): super(SelectProviderPage, self).__init__(parent) - self.setTitle("Select Provider") + self.setTitle("Enter Provider") self.setSubTitle( "Please enter the domain of the provider you want " "to use for your connection." @@ -243,7 +251,9 @@ class SelectProviderPage(QtGui.QWizardPage): QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) - providerNameLabel = QtGui.QLabel("&Provider:") + 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) @@ -269,13 +279,28 @@ class SelectProviderPage(QtGui.QWizardPage): validationMsg = QtGui.QLabel("") validationMsg.setStyleSheet(ErrorLabelStyleSheet) - self.validationMsg = validationMsg + # XXX cert info + self.certInfo = QtGui.QLabel("") + self.certInfo.setWordWrap(True) + self.certWarning = QtGui.QLabel("") + self.trustProviderCertCheckBox = QtGui.QCheckBox( + "&Trust this provider certificate.") + layout = QtGui.QGridLayout() - layout.addWidget(validationMsg, 0, 0) - layout.addWidget(providerNameLabel, 0, 1) - layout.addWidget(providerNameEdit, 0, 2) + layout.addWidget(validationMsg, 0, 2) + layout.addWidget(providerNameLabel, 1, 1) + layout.addWidget(providerNameEdit, 1, 2) + + # XXX get a groupbox or something.... + layout.addWidget(self.certInfo, 4, 1, 4, 2) + layout.addWidget(self.certWarning, 6, 1, 6, 2) + layout.addWidget( + self.trustProviderCertCheckBox, + 8, 1, 8, 2) + self.trustProviderCertCheckBox.hide() + self.setLayout(layout) def reset_validation_status(self): @@ -284,7 +309,64 @@ 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( + 'Certificate sha1: %s
' % certinfo) + self.trustProviderCertCheckBox.show() + # XXX when checkbox is marked, remove + # the red warning. + # XXX also, disable the next button! + + def initializePage(self): + self.certWarning.setText('') + self.certInfo.setText('') + self.trustProviderCertCheckBox.hide() + def validatePage(self): + wizard = self.wizard() + netchecker = wizard.netchecker() + providercertchecker = wizard.providercertchecker() + + 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_https_cert_fingerprint( + domain) + self.add_cert_info(fingerprint) + return False + + except baseexceptions.LeapException as exc: + self.set_validation_status(exc.usermessage) + return False + + # try download provider info... + # TODO ... + + # all ok, go on... return True def nextId(self): -- cgit v1.2.3 From bc775969e2db31b892526b65a5037470a86b3882 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 19 Oct 2012 06:12:14 +0900 Subject: logic for cert validation widgets in wizard --- src/leap/gui/firstrunwizard.py | 177 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 161 insertions(+), 16 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index 53e551ac..f3356b70 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -72,6 +72,8 @@ class FirstRunWizard(QtGui.QWizard): self.providercertchecker = providercertchecker self.eipconfigchecker = eipconfigchecker + self.providerconfig = None + # FIXME add param for previously_registered # should start at login page. @@ -123,6 +125,9 @@ class FirstRunWizard(QtGui.QWizard): """ return self.pages_dict.keys().index(page_name) + def set_providerconfig(self, providerconfig): + self.providerconfig = providerconfig + def setWindowFlags(self, flags): logger.debug('setting window flags') QtGui.QWizard.setWindowFlags(self, flags) @@ -140,7 +145,7 @@ class FirstRunWizard(QtGui.QWizard): gather the info, update settings and call the success callback. """ - provider = self.get_provider() + provider = self.field('provider_domain') username = self.field('userName') #password = self.field('userPassword') remember_pass = self.field('rememberPassword') @@ -208,16 +213,22 @@ class IntroPage(QtGui.QWizardPage): "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(self.sign_up) - layout.addWidget(self.log_in) + layout.addWidget(radiobuttonGroup) self.setLayout(layout) self.registerField('is_signup', self.sign_up) @@ -251,6 +262,8 @@ class SelectProviderPage(QtGui.QWizardPage): 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 @@ -281,28 +294,66 @@ class SelectProviderPage(QtGui.QWizardPage): validationMsg.setStyleSheet(ErrorLabelStyleSheet) self.validationMsg = validationMsg - # XXX cert info + # 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.... - layout.addWidget(self.certInfo, 4, 1, 4, 2) - layout.addWidget(self.certWarning, 6, 1, 6, 2) - layout.addWidget( - self.trustProviderCertCheckBox, - 8, 1, 8, 2) - self.trustProviderCertCheckBox.hide() - + 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() + + #layout.addWidget(self.certInfo, 4, 1, 4, 2) + #layout.addWidget(self.certWarning, 6, 1, 6, 2) + #layout.addWidget( + #self.trustProviderCertCheckBox, + #8, 1, 8, 2) + + #self.trustProviderCertCheckBox.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 @@ -314,23 +365,34 @@ class SelectProviderPage(QtGui.QWizardPage): def add_cert_info(self, certinfo): self.certWarning.setText( - "Do you want to trust this provider certificate?") + "Do you want to trust this provider certificate?") self.certInfo.setText( - 'Certificate sha1: %s
' % certinfo) - self.trustProviderCertCheckBox.show() + 'Sha1 fingerprint: %s
' % certinfo) + #self.trustProviderCertCheckBox.show() + self.certinfoGroup.show() # XXX when checkbox is marked, remove # the red warning. # XXX also, disable the next button! + # 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.certWarning.setText('') self.certInfo.setText('') - self.trustProviderCertCheckBox.hide() + #self.trustProviderCertCheckBox.hide() def validatePage(self): wizard = self.wizard() netchecker = wizard.netchecker() providercertchecker = wizard.providercertchecker() + eipconfigchecker = wizard.eipconfigchecker() domain = self.providerNameEdit.text() @@ -357,6 +419,8 @@ class SelectProviderPage(QtGui.QWizardPage): fingerprint = certs.get_https_cert_fingerprint( domain) self.add_cert_info(fingerprint) + self.did_cert_check = True + self.completeChanged.emit() return False except baseexceptions.LeapException as exc: @@ -364,7 +428,9 @@ class SelectProviderPage(QtGui.QWizardPage): return False # try download provider info... - # TODO ... + eipconfigchecker.fetch_definition(domain=domain) + wizard.set_providerconfig( + eipconfigchecker.defaultprovider.config) # all ok, go on... return True @@ -387,6 +453,43 @@ class ProviderInfoPage(QtGui.QWizardPage): QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) + displayName = QtGui.QLabel("") + description = QtGui.QLabel("") + enrollment_policy = QtGui.QLabel("") + # stylesheet... + 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 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() if not wizard: @@ -405,6 +508,48 @@ class ProviderSetupPage(QtGui.QWizardPage): QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) + self.status = QtGui.QLabel("") + self.progress = QtGui.QProgressBar() + self.progress.setMaximum(100) + self.progress.hide() + + layout = QtGui.QGridLayout() + layout.addWidget(self.status, 0, 1) + layout.addWidget(self.progress, 5, 1) + + self.setLayout(layout) + + def set_status(self, status): + self.status.setText(status) + + def initializePage(self): + self.set_status('') + self.progress.setValue(0) + self.progress.hide() + + def validatePage(self): + import time + self.progress.show() + + self.set_status('fetching cert...') + self.progress.setValue(20) + time.sleep(2) + + self.set_status('fetching cert another time...') + self.progress.setValue(40) + time.sleep(2) + + self.set_status('validating cert') + self.progress.setValue(60) + time.sleep(2) + + self.set_status('validating CA cert...') + self.progress.setValue(80) + time.sleep(2) + + self.progress.setValue(100) + return True + def nextId(self): wizard = self.wizard() if not wizard: -- cgit v1.2.3 From 2a01c969e0f8dff575007043996c3b0489e20e75 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 19 Oct 2012 08:18:34 +0900 Subject: download ca cert from provider --- src/leap/gui/firstrunwizard.py | 80 +++++++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 25 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index f3356b70..e4293cf6 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -367,12 +367,9 @@ class SelectProviderPage(QtGui.QWizardPage): self.certWarning.setText( "Do you want to trust this provider certificate?") self.certInfo.setText( - 'Sha1 fingerprint: %s
' % certinfo) - #self.trustProviderCertCheckBox.show() + 'SHA-256 fingerprint: %s
' % certinfo) + self.certInfo.setWordWrap(True) self.certinfoGroup.show() - # XXX when checkbox is marked, remove - # the red warning. - # XXX also, disable the next button! # pagewizard methods @@ -384,9 +381,7 @@ class SelectProviderPage(QtGui.QWizardPage): return False def initializePage(self): - self.certWarning.setText('') - self.certInfo.setText('') - #self.trustProviderCertCheckBox.hide() + self.certinfoGroup.hide() def validatePage(self): wizard = self.wizard() @@ -417,7 +412,7 @@ class SelectProviderPage(QtGui.QWizardPage): else: self.set_validation_status(exc.usermessage) fingerprint = certs.get_https_cert_fingerprint( - domain) + domain, sep=" ") self.add_cert_info(fingerprint) self.did_cert_check = True self.completeChanged.emit() @@ -456,7 +451,9 @@ class ProviderInfoPage(QtGui.QWizardPage): displayName = QtGui.QLabel("") description = QtGui.QLabel("") enrollment_policy = QtGui.QLabel("") - # stylesheet... + # XXX set stylesheet... + # prettify a little bit. + # bigger fonts and so on... self.displayName = displayName self.description = description self.enrollment_policy = enrollment_policy @@ -521,33 +518,66 @@ class ProviderSetupPage(QtGui.QWizardPage): def set_status(self, status): self.status.setText(status) + self.status.setWordWrap(True) - def initializePage(self): - self.set_status('') - self.progress.setValue(0) - self.progress.hide() - - def validatePage(self): + def fetch_and_validate(self): + # Fake... till you make it... import time - self.progress.show() - - self.set_status('fetching cert...') - self.progress.setValue(20) - time.sleep(2) - - self.set_status('fetching cert another time...') + domain = self.field('provider_domain') + wizard = self.wizard() + pconfig = wizard.providerconfig + pCertChecker = wizard.providercertchecker + certchecker = pCertChecker(domain=domain) + + self.set_status('Fetching CA certificate') + self.progress.setValue(30) + ca_cert_uri = pconfig.get('ca_cert_uri').geturl() + + # 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) + + self.set_status('Checking CA fingerprint') self.progress.setValue(40) + ca_cert_fingerprint = pconfig.get('ca_cert_fingerprint') + + # XXX get fingerprint dict (types) + certchecker.check_ca_cert_fingerprint( + fingerprint=ca_cert_fingerprint) time.sleep(2) - self.set_status('validating cert') + self.set_status('Fetching api https certificate') self.progress.setValue(60) time.sleep(2) - self.set_status('validating CA cert...') + self.set_status('Validating api certificate') self.progress.setValue(80) time.sleep(2) + #ca_cert_path = checker.ca_cert_path self.progress.setValue(100) + + # pagewizard methods + + def initializePage(self): + self.set_status( + 'We are going to contact the provider to get ' + 'the certificates that will be used to stablish ' + 'a secure connection.

Click next to continue.') + self.progress.setValue(0) + self.progress.hide() + + def validatePage(self): + self.progress.show() + self.fetch_and_validate() + return True def nextId(self): -- cgit v1.2.3 From 634030e5bba3fe7c2ea3632fff252a60b471487a Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 19 Oct 2012 09:05:14 +0900 Subject: ca cert fingerprint check + api cert verification --- src/leap/gui/firstrunwizard.py | 48 ++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 13 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index e4293cf6..55338090 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -3,6 +3,8 @@ import logging import json import socket +import requests + import sip sip.setapi('QString', 2) sip.setapi('QVariant', 2) @@ -411,8 +413,8 @@ class SelectProviderPage(QtGui.QWizardPage): pass else: self.set_validation_status(exc.usermessage) - fingerprint = certs.get_https_cert_fingerprint( - domain, sep=" ") + fingerprint = certs.get_cert_fingerprint( + domain=domain, sep=" ") self.add_cert_info(fingerprint) self.did_cert_check = True self.completeChanged.emit() @@ -545,24 +547,44 @@ class ProviderSetupPage(QtGui.QWizardPage): verify=False) self.set_status('Checking CA fingerprint') - self.progress.setValue(40) - ca_cert_fingerprint = pconfig.get('ca_cert_fingerprint') + self.progress.setValue(66) + ca_cert_fingerprint = pconfig.get('ca_cert_fingerprint', None) # XXX get fingerprint dict (types) - certchecker.check_ca_cert_fingerprint( - fingerprint=ca_cert_fingerprint) - time.sleep(2) - - self.set_status('Fetching api https certificate') - self.progress.setValue(60) - time.sleep(2) + 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 self.set_status('Validating api certificate') - self.progress.setValue(80) - time.sleep(2) + 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) + time.sleep(0.2) # pagewizard methods -- cgit v1.2.3 From b0be517ed8b2fb9dd0a38dad5b5c06741b6b9b09 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 19 Oct 2012 11:02:44 +0900 Subject: add bug number in log for #638 cases (domain name mismatch) --- src/leap/gui/firstrunwizard.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index 55338090..8bb40cdc 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -713,14 +713,11 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): 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) @@ -788,13 +785,10 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): 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) - layout.addWidget(rememberPasswordCheckBox, 3, 3, 3, 4) self.setLayout(layout) @@ -834,9 +828,11 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): # XXX enforce https # and pass a verify value + domain = self.field('provider_domain') + signup = LeapSRPRegister( schema="http", - provider="springbok", + provider=domain, # debug ----- #provider="localhost", @@ -942,6 +938,6 @@ if __name__ == '__main__': logger.setLevel(logging.DEBUG) app = QtGui.QApplication(sys.argv) - wizard = FirstRunWizard(providers=('springbok',)) + wizard = FirstRunWizard() # providers=('springbok',)) wizard.show() sys.exit(app.exec_()) -- cgit v1.2.3 From f791a83ce57cef7010da819d61e7f5132fa4611e Mon Sep 17 00:00:00 2001 From: kali Date: Sat, 20 Oct 2012 06:30:16 +0900 Subject: connecting page and changes to functions having to do with the default path to certs. --- src/leap/gui/firstrunwizard.py | 110 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 2 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index 8bb40cdc..68cd4253 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -584,7 +584,7 @@ class ProviderSetupPage(QtGui.QWizardPage): #ca_cert_path = checker.ca_cert_path self.progress.setValue(100) - time.sleep(0.2) + time.sleep(1) # pagewizard methods @@ -634,7 +634,6 @@ class UserFormMixIn(object): # I guess it is because there is no delay... logger.debug('registering........') self.validationMsg.setText('registering...') - # need to call update somehow??? # XXX refactor set_status_foo @@ -774,6 +773,10 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): self.registerField('userName*', self.userNameLineEdit) self.registerField('userPassword*', self.userPasswordLineEdit) + + # XXX missing password confirmation + # XXX validator! + self.registerField('rememberPassword', rememberPasswordCheckBox) layout = QtGui.QGridLayout() @@ -898,6 +901,109 @@ class ConnectingPage(QtGui.QWizardPage): 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() + + 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.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) + + self.setLayout(layout) + + def set_status(self, status): + self.status.setText(status) + self.status.setWordWrap(True) + + def get_donemsg(self, msg): + return "%s ... done" % msg + + def fetch_and_validate(self): + # Fake... till you make it... + import time + domain = self.field('provider_domain') + wizard = self.wizard() + #pconfig = wizard.providerconfig + eipconfigchecker = wizard.eipconfigchecker() + pCertChecker = wizard.providercertchecker( + domain=domain) + + # XXX get from log_in page if we came that way + # instead + + username = self.field('userName') + password = self.field('userPassword') + + 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 + pCertChecker.download_new_client_cert( + credentials=credentials) + + 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) + + return True + + # pagewizard methods + + 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): + validated = self.fetch_and_validate() + return validated + class LastPage(QtGui.QWizardPage): def __init__(self, parent=None): -- cgit v1.2.3 From a85e488ed323ba35b9d12c5cc344bf06337a9a00 Mon Sep 17 00:00:00 2001 From: kali Date: Sat, 20 Oct 2012 07:13:22 +0900 Subject: add bypass for already trusted fingerprints --- src/leap/gui/firstrunwizard.py | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index 68cd4253..287332cd 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -47,6 +47,7 @@ class FirstRunWizard(QtGui.QWizard): self, parent=None, providers=None, success_cb=None, is_provider_setup=False, is_previously_registered=False, + trusted_certs=None, netchecker=basechecks.LeapNetworkChecker, providercertchecker=eipchecks.ProviderCertChecker, eipconfigchecker=eipchecks.EIPConfigChecker): @@ -69,6 +70,10 @@ class FirstRunWizard(QtGui.QWizard): # if True, jumps to LogIn page. self.is_previously_registered = is_previously_registered + # a dict with trusted fingerprints + # in the form {'nospacesfingerprint': ['host1', 'host2']} + self.trusted_certs = trusted_certs + # Checkers self.netchecker = netchecker self.providercertchecker = providercertchecker @@ -415,10 +420,17 @@ class SelectProviderPage(QtGui.QWizardPage): self.set_validation_status(exc.usermessage) fingerprint = certs.get_cert_fingerprint( domain=domain, sep=" ") - self.add_cert_info(fingerprint) - self.did_cert_check = True - self.completeChanged.emit() - return False + + # 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) @@ -1044,6 +1056,13 @@ if __name__ == '__main__': logger.setLevel(logging.DEBUG) app = QtGui.QApplication(sys.argv) - wizard = FirstRunWizard() # providers=('springbok',)) + + trusted_certs = { + "3DF83F316BFA0186" + "0A11A5C9C7FC24B9" + "18C62B941192CC1A" + "49AE62218B2A4B7C": ['springbok']} + + wizard = FirstRunWizard(trusted_certs=trusted_certs) wizard.show() sys.exit(app.exec_()) -- cgit v1.2.3 From 5126ffe2d8f468dfba9376b450cc243ea62219e6 Mon Sep 17 00:00:00 2001 From: kali Date: Sat, 20 Oct 2012 07:37:19 +0900 Subject: password confirmation --- src/leap/gui/firstrunwizard.py | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index 287332cd..d9e33f7e 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -634,6 +634,14 @@ class UserFormMixIn(object): """ self.validationMsg.setText('') + def set_validation_status(self, msg): + """ + set generic validation status + """ + self.validationMsg.setText(msg) + + # XXX Refactor all these validation msgs!!! + def set_status_validating(self): """ set validation msg to 'registering...' @@ -644,11 +652,8 @@ class UserFormMixIn(object): # not show until the validate function # returns. # I guess it is because there is no delay... - logger.debug('registering........') self.validationMsg.setText('registering...') - # XXX refactor set_status_foo - def set_status_invalid_username(self): """ set validation msg to @@ -779,6 +784,12 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): 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) @@ -803,8 +814,10 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): 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(rememberPasswordCheckBox, 3, 3, 3, 4) + layout.addWidget(self.userPassword2LineEdit, 3, 3) + layout.addWidget(rememberPasswordCheckBox, 4, 3, 4, 4) self.setLayout(layout) # overwritten methods @@ -837,6 +850,22 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): 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": + # XD + self.set_validation_status('Password too obvious.') + return False # XXX TODO -- remove debug info # XXX get from provider info -- cgit v1.2.3 From 0060d3c74adce19fab7215b3788c5197cc05a9ae Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 24 Oct 2012 04:05:19 +0900 Subject: sign up branch ends by triggering eip connection still need to bind signals properly, and block on the validation process until we receive the "connected" signal. but the basic flow is working again, i.e, user should be able to remove the .config/leap folder and get all the needed info from the provider. --- src/leap/gui/firstrunwizard.py | 82 ++++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 19 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index d9e33f7e..c7531d16 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -44,20 +44,28 @@ QLabel { color: red; class FirstRunWizard(QtGui.QWizard): def __init__( - self, parent=None, providers=None, + self, + conductor_instance, + parent=None, + eip_username=None, + providers=None, success_cb=None, is_provider_setup=False, is_previously_registered=False, trusted_certs=None, netchecker=basechecks.LeapNetworkChecker, providercertchecker=eipchecks.ProviderCertChecker, - eipconfigchecker=eipchecks.EIPConfigChecker): + eipconfigchecker=eipchecks.EIPConfigChecker, + start_eipconnection_signal=None): super(FirstRunWizard, self).__init__( parent, QtCore.Qt.WindowStaysOnTopHint) - # XXX hardcoded for tests - #if not providers: - #providers = ('springbok',) + # 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 @@ -79,10 +87,13 @@ class FirstRunWizard(QtGui.QWizard): self.providercertchecker = providercertchecker self.eipconfigchecker = eipconfigchecker + # signal for starting eip connection + # will be emitted in connecting page + self.start_eipconnection_signal = start_eipconnection_signal + self.providerconfig = None - # FIXME add param for previously_registered - # should start at login page. + is_previously_registered = bool(self.eip_username) pages_dict = OrderedDict(( # (name, WizardPage) @@ -150,11 +161,11 @@ class FirstRunWizard(QtGui.QWizard): """ final step in the wizard. gather the info, update settings - and call the success callback. + and call the success callback if any has been passed. """ provider = self.field('provider_domain') username = self.field('userName') - #password = self.field('userPassword') + password = self.field('userPassword') remember_pass = self.field('rememberPassword') logger.debug('chosen provider: %s', provider) @@ -163,19 +174,25 @@ class FirstRunWizard(QtGui.QWizard): super(FirstRunWizard, self).accept() settings = QtCore.QSettings() + # 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.setValue("FirstRunWizardDone", True) - settings.setValue( - "eip_%s_username" % provider, - username) - settings.setValue("%s_remember_pass" % provider, remember_pass) + settings.setValue("provider_domain", provider) + full_username = "%s@%s" % (username, provider) + + settings.setValue("eip_username", full_username) + settings.setValue("remember_user_and_pass", remember_pass) seed = self.get_random_str(10) settings.setValue("%s_seed" % provider, seed) - # Commenting out for 0.2.0 release - # since we did not fix #744 on time. - - #leapkeyring.leap_set_password(username, password, seed=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 @@ -863,7 +880,7 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): return False if password == "123456": - # XD + # joking self.set_validation_status('Password too obvious.') return False @@ -970,6 +987,30 @@ class ConnectingPage(QtGui.QWizardPage): def get_donemsg(self, msg): return "%s ... done" % msg + def run_eip_checks_for_provider(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): # Fake... till you make it... import time @@ -1023,6 +1064,9 @@ class ConnectingPage(QtGui.QWizardPage): self.progress.setValue(100) time.sleep(3) + # here we go! :) + self.run_eip_checks_for_provider(domain) + return True # pagewizard methods @@ -1092,6 +1136,6 @@ if __name__ == '__main__': "18C62B941192CC1A" "49AE62218B2A4B7C": ['springbok']} - wizard = FirstRunWizard(trusted_certs=trusted_certs) + wizard = FirstRunWizard(None, trusted_certs=trusted_certs) wizard.show() sys.exit(app.exec_()) -- cgit v1.2.3 From ff02a21ed6ef879c054b01134744068bdfeda664 Mon Sep 17 00:00:00 2001 From: kali Date: Wed, 24 Oct 2012 06:49:51 +0900 Subject: last page of wizard displays the connection steps --- src/leap/gui/firstrunwizard.py | 89 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 8 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index c7531d16..52f00be8 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -20,6 +20,7 @@ from leap.crypto import leapkeyring from leap.eip import checks as eipchecks from leap.eip import exceptions as eipexceptions from leap.gui import mainwindow_rc +from leap.util.coroutines import coroutine try: from collections import OrderedDict @@ -55,7 +56,8 @@ class FirstRunWizard(QtGui.QWizard): netchecker=basechecks.LeapNetworkChecker, providercertchecker=eipchecks.ProviderCertChecker, eipconfigchecker=eipchecks.EIPConfigChecker, - start_eipconnection_signal=None): + start_eipconnection_signal=None, + eip_statuschange_signal=None): super(FirstRunWizard, self).__init__( parent, QtCore.Qt.WindowStaysOnTopHint) @@ -87,9 +89,11 @@ class FirstRunWizard(QtGui.QWizard): self.providercertchecker = providercertchecker self.eipconfigchecker = eipconfigchecker - # signal for starting eip connection + # Signals # will be emitted in connecting page self.start_eipconnection_signal = start_eipconnection_signal + self.eip_statuschange_signal = eip_statuschange_signal + self.providerconfig = None @@ -965,11 +969,15 @@ class ConnectingPage(QtGui.QWizardPage): 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) @@ -984,15 +992,21 @@ class ConnectingPage(QtGui.QWizardPage): 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 get_donemsg(self, msg): return "%s ... done" % msg - def run_eip_checks_for_provider(self, 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) + conductor.set_provider_domain(domain) conductor.run_checks() self.conductor = conductor @@ -1011,6 +1025,15 @@ class ConnectingPage(QtGui.QWizardPage): errq = self.conductor.error_queue # XXX missing! + #@coroutine + #def wait_for_validation_block(self): + #try: + #while True: + #(yield) + #break + #except GeneratorExit: + #pass +# def fetch_and_validate(self): # Fake... till you make it... import time @@ -1065,11 +1088,16 @@ class ConnectingPage(QtGui.QWizardPage): time.sleep(3) # here we go! :) - self.run_eip_checks_for_provider(domain) + self.run_eip_checks_for_provider_and_connect(domain) + + #self.validation_block = self.wait_for_validation_block() + # XXX signal timeout! return True + # # pagewizard methods + # def initializePage(self): # XXX if we're coming from signup page @@ -1094,7 +1122,7 @@ class LastPage(QtGui.QWizardPage): def __init__(self, parent=None): super(LastPage, self).__init__(parent) - self.setTitle("Ready to go!") + self.setTitle("Connecting...") self.setPixmap( QtGui.QWizard.LogoPixmap, @@ -1107,17 +1135,62 @@ class LastPage(QtGui.QWizardPage): 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 initializePage(self): + 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 using an encrypted connection!') finishText = self.wizard().buttonText( QtGui.QWizard.FinishButton) finishText = finishText.replace('&', '') self.label.setText( - "Click '%s' to end the wizard and start " - "encrypting your connection." % finishText) + "Click '%s' to end the wizard and " + "save your settings." % finishText) + + @coroutine + def eip_status_handler(self): + 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 + eip_statuschange_signal.connect( + lambda status: eip_status_handler.send(status)) if __name__ == '__main__': -- cgit v1.2.3 From a0fc20884a02ccffe1f9a83440b5e2212853289a Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 25 Oct 2012 07:12:34 +0900 Subject: login branch in wizard --- src/leap/gui/firstrunwizard.py | 281 +++++++++++++++++++++++++++-------------- 1 file changed, 185 insertions(+), 96 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index 52f00be8..78f8afb5 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -12,7 +12,7 @@ sip.setapi('QVariant', 2) from PyQt4 import QtCore from PyQt4 import QtGui -from leap.base.auth import LeapSRPRegister +from leap.base import auth from leap.base import checks as basechecks from leap.base import exceptions as baseexceptions from leap.crypto import certs @@ -35,6 +35,13 @@ logger.setLevel(logging.DEBUG) APP_LOGO = ':/images/leap-color-small.png' +# bare is the username portion of a JID +# full includes the "at" and some extra chars +# that can be allowed for fqdn + +BARE_USERNAME_REGEX = r"^[A-Za-z\d_]+$" +FULL_USERNAME_REGEX = r"^[A-Za-z\d_@.-]+$" + ErrorLabelStyleSheet = """ QLabel { color: red; @@ -51,7 +58,6 @@ class FirstRunWizard(QtGui.QWizard): eip_username=None, providers=None, success_cb=None, is_provider_setup=False, - is_previously_registered=False, trusted_certs=None, netchecker=basechecks.LeapNetworkChecker, providercertchecker=eipchecks.ProviderCertChecker, @@ -76,10 +82,6 @@ class FirstRunWizard(QtGui.QWizard): # is provider setup? self.is_provider_setup = is_provider_setup - # previously registered - # if True, jumps to LogIn page. - self.is_previously_registered = is_previously_registered - # a dict with trusted fingerprints # in the form {'nospacesfingerprint': ['host1', 'host2']} self.trusted_certs = trusted_certs @@ -94,10 +96,15 @@ class FirstRunWizard(QtGui.QWizard): self.start_eipconnection_signal = start_eipconnection_signal self.eip_statuschange_signal = eip_statuschange_signal - self.providerconfig = None - - is_previously_registered = bool(self.eip_username) + # 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 + #self.allow_revisit = None pages_dict = OrderedDict(( # (name, WizardPage) @@ -147,6 +154,26 @@ class FirstRunWizard(QtGui.QWizard): """ return self.pages_dict.keys().index(page_name) + # XXX was trying to allow temporary + # a revisit. this does not work cause visitedPages + # is not called internally. + + #def allow_page_revisit(self, page_name): + #self.allow_revisit = self.get_page_index(page_name) +# + #def visitedPages(self): + #""" + #reimplementation of visitedPages + #that temporary allows to revisit a page + #if allow_revisit is set + #""" + #visited = super(FirstRunWizard, self).visitedPages() + #allow = self.allow_revisit + #if allow: + #visited.remove(allow) + #self.allow_revisit = None + #return visited + def set_providerconfig(self, providerconfig): self.providerconfig = providerconfig @@ -561,12 +588,17 @@ class ProviderSetupPage(QtGui.QWizardPage): domain = self.field('provider_domain') wizard = self.wizard() pconfig = wizard.providerconfig + pCertChecker = wizard.providercertchecker certchecker = pCertChecker(domain=domain) self.set_status('Fetching CA certificate') self.progress.setValue(30) - ca_cert_uri = pconfig.get('ca_cert_uri').geturl() + + 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 @@ -629,6 +661,9 @@ class ProviderSetupPage(QtGui.QWizardPage): self.progress.setValue(0) self.progress.hide() + # XXX use a call to "next" instead? + #self.wizard().next() + def validatePage(self): self.progress.show() self.fetch_and_validate() @@ -661,57 +696,6 @@ class UserFormMixIn(object): """ self.validationMsg.setText(msg) - # XXX Refactor all these validation msgs!!! - - def set_status_validating(self): - """ - set validation msg to 'registering...' - """ - # XXX this is NOT WORKING. - # My guess is that, even if we are using - # signals to trigger this, it does - # not show until the validate function - # returns. - # I guess it is because there is no delay... - self.validationMsg.setText('registering...') - - def set_status_invalid_username(self): - """ - set validation msg to - not available user - """ - self.validationMsg.setText('Username not available.') - - def set_status_server_500(self): - """ - set validation msg to - internal server error - """ - self.validationMsg.setText("Error during registration (500)") - - def set_status_timeout(self): - """ - set validation msg to - timeout - """ - self.validationMsg.setText("Error connecting to provider (timeout)") - - def set_status_connerror(self): - """ - set validation msg to - connection refused - """ - self.validationMsg.setText( - "Error connecting to provider " - "(connection error)") - - def set_status_unknown_error(self): - """ - set validation msg to - unknown error - """ - self.validationMsg.setText("Error during sign up") - class LogInPage(QtGui.QWizardPage, UserFormMixIn): def __init__(self, parent=None): @@ -730,8 +714,8 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): self.reset_validation_status) userNameLabel.setBuddy(userNameLineEdit) - # add regex validator - usernameRe = QtCore.QRegExp(r"^[A-Za-z\d_]+$") + # let's add regex validator + usernameRe = QtCore.QRegExp(FULL_USERNAME_REGEX) userNameLineEdit.setValidator( QtGui.QRegExpValidator(usernameRe, self)) self.userNameLineEdit = userNameLineEdit @@ -742,8 +726,8 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): QtGui.QLineEdit.Password) userPasswordLabel.setBuddy(self.userPasswordLineEdit) - self.registerField('log_in_userName*', self.userNameLineEdit) - self.registerField('log_in_userPassword*', self.userPasswordLineEdit) + self.registerField('login_userName*', self.userNameLineEdit) + self.registerField('login_userPassword*', self.userPasswordLineEdit) layout = QtGui.QGridLayout() layout.setColumnMinimumWidth(0, 20) @@ -760,6 +744,15 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): 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: @@ -770,6 +763,59 @@ class LogInPage(QtGui.QWizardPage, UserFormMixIn): 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 + class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): setSigningUpStatus = QtCore.pyqtSignal([]) @@ -779,7 +825,8 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): # bind wizard page signals self.setSigningUpStatus.connect( - self.set_status_validating) + lambda: self.set_validation_status( + 'validating')) self.setTitle("Sign Up") @@ -793,8 +840,8 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): self.reset_validation_status) userNameLabel.setBuddy(userNameLineEdit) - # add regex validator - usernameRe = QtCore.QRegExp(r"^[A-Za-z\d_]+$") + # let's add regex validator + usernameRe = QtCore.QRegExp(BARE_USERNAME_REGEX) userNameLineEdit.setValidator( QtGui.QRegExpValidator(usernameRe, self)) self.userNameLineEdit = userNameLineEdit @@ -888,14 +935,14 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): self.set_validation_status('Password too obvious.') return False + domain = self.field('provider_domain') + # XXX TODO -- remove debug info # XXX get from provider info # XXX enforce https # and pass a verify value - domain = self.field('provider_domain') - - signup = LeapSRPRegister( + signup = auth.LeapSRPRegister( schema="http", provider=domain, @@ -907,12 +954,15 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): try: ok, req = signup.register_user(username, password) except socket.timeout: - self.set_status_timeout() + self.set_validation_status( + "Error connecting to provider (timeout)") return False except requests.exceptions.ConnectionError as exc: logger.error(exc) - self.set_status_connerror() + self.set_validation_status( + "Error connecting to provider " + "(connection error)") return False if ok: @@ -923,7 +973,8 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): # get timeout # ... if req.status_code == 500: - self.set_status_server_500() + self.set_validation_status( + "Error during registration (500)") return False validation_msgs = json.loads(req.content) @@ -932,9 +983,11 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): if errors and errors.get('login', None): # XXX this sometimes catch the blank username # but we're not allowing that (soon) - self.set_status_invalid_username() + self.set_validation_status( + 'Username not available.') else: - self.set_status_unknown_error() + self.set_validation_status( + "Error during sign up") return False def nextId(self): @@ -986,8 +1039,16 @@ class ConnectingPage(QtGui.QWizardPage): 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) @@ -997,6 +1058,18 @@ class ConnectingPage(QtGui.QWizardPage): 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 @@ -1025,17 +1098,7 @@ class ConnectingPage(QtGui.QWizardPage): errq = self.conductor.error_queue # XXX missing! - #@coroutine - #def wait_for_validation_block(self): - #try: - #while True: - #(yield) - #break - #except GeneratorExit: - #pass -# def fetch_and_validate(self): - # Fake... till you make it... import time domain = self.field('provider_domain') wizard = self.wizard() @@ -1044,12 +1107,16 @@ class ConnectingPage(QtGui.QWizardPage): pCertChecker = wizard.providercertchecker( domain=domain) - # XXX get from log_in page if we came that way - # instead - - username = self.field('userName') - password = self.field('userPassword') + # 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() @@ -1070,8 +1137,18 @@ class ConnectingPage(QtGui.QWizardPage): self.progress.setValue(66) # Download cert - pCertChecker.download_new_client_cert( - credentials=credentials) + 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( @@ -1096,9 +1173,20 @@ class ConnectingPage(QtGui.QWizardPage): return True # - # pagewizard methods + # 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 @@ -1189,8 +1277,9 @@ class LastPage(QtGui.QWizardPage): return eip_status_handler = self.eip_status_handler() eip_statuschange_signal = wizard.eip_statuschange_signal - eip_statuschange_signal.connect( - lambda status: eip_status_handler.send(status)) + if eip_statuschange_signal: + eip_statuschange_signal.connect( + lambda status: eip_status_handler.send(status)) if __name__ == '__main__': -- cgit v1.2.3 From 0590991d7777de473a7df21ed32e1fa7caa9cf4b Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 26 Oct 2012 00:12:08 +0900 Subject: user credentials saved on login/signup branches. cert request is using magick decorator that retrieves the certificates using srp. --- src/leap/gui/firstrunwizard.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index 78f8afb5..4cad9c3f 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -28,10 +28,7 @@ except ImportError: # We must be in 2.6 from leap.util.dicts import OrderedDict -# XXX DEBUG -logging.basicConfig() logger = logging.getLogger(__name__) -logger.setLevel(logging.DEBUG) APP_LOGO = ':/images/leap-color-small.png' @@ -194,22 +191,32 @@ class FirstRunWizard(QtGui.QWizard): 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.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) provider = self.field('provider_domain') - username = self.field('userName') - password = self.field('userPassword') remember_pass = self.field('rememberPassword') logger.debug('chosen provider: %s', provider) logger.debug('username: %s', username) logger.debug('remember password: %s', remember_pass) - super(FirstRunWizard, self).accept() - settings = QtCore.QSettings() # 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) -- cgit v1.2.3 From b847bbfb8e1fed3dd478a0314ed618b6a1ae8cb6 Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 26 Oct 2012 00:18:06 +0900 Subject: save user/pass only if save_user checked in wizard --- src/leap/gui/firstrunwizard.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index 4cad9c3f..fd49380c 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -195,7 +195,7 @@ class FirstRunWizard(QtGui.QWizard): # username and password are in different fields # if they were stored in log_in or sign_up pages. - from_login = self.wizard().from_login + from_login = self.from_login unamek_base = 'userName' passwk_base = 'userPassword' unamek = 'login_%s' % unamek_base if from_login else unamek_base @@ -221,16 +221,17 @@ class FirstRunWizard(QtGui.QWizard): settings.setValue("provider_domain", provider) full_username = "%s@%s" % (username, provider) - settings.setValue("eip_username", full_username) settings.setValue("remember_user_and_pass", remember_pass) - seed = self.get_random_str(10) - settings.setValue("%s_seed" % provider, seed) + 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) + # 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 -- cgit v1.2.3 From 593e4ba1ddf185d14f27c96ffb970fde7a3271fa Mon Sep 17 00:00:00 2001 From: kali Date: Fri, 26 Oct 2012 02:04:34 +0900 Subject: fix systray context menu. Closes #761 --- src/leap/gui/firstrunwizard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index fd49380c..6b9921d9 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -1218,7 +1218,7 @@ class LastPage(QtGui.QWizardPage): def __init__(self, parent=None): super(LastPage, self).__init__(parent) - self.setTitle("Connecting...") + self.setTitle("Connecting to Encrypted Internet Proxy service...") self.setPixmap( QtGui.QWizard.LogoPixmap, @@ -1253,7 +1253,7 @@ class LastPage(QtGui.QWizardPage): statusline.setText(status) def set_finished_status(self): - self.setTitle('You are using an encrypted connection!') + self.setTitle('You are now using an encrypted connection!') finishText = self.wizard().buttonText( QtGui.QWizard.FinishButton) finishText = finishText.replace('&', '') -- cgit v1.2.3 From c387a52f841e8933ed7282d198ed1ece863979fc Mon Sep 17 00:00:00 2001 From: kali Date: Tue, 6 Nov 2012 01:26:05 +0900 Subject: new validation pages in a reusable MVC style using progress indicators inside QTableWidget --- src/leap/gui/firstrunwizard.py | 166 +++++++++++++++++++---------------------- 1 file changed, 78 insertions(+), 88 deletions(-) (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py index 6b9921d9..7876c3c8 100755 --- a/src/leap/gui/firstrunwizard.py +++ b/src/leap/gui/firstrunwizard.py @@ -19,9 +19,11 @@ from leap.crypto import certs from leap.crypto import leapkeyring from leap.eip import checks as eipchecks from leap.eip import exceptions as eipexceptions -from leap.gui import mainwindow_rc +from leap.gui.progress import ValidationPage from leap.util.coroutines import coroutine +from leap.gui import mainwindow_rc + try: from collections import OrderedDict except ImportError: @@ -101,7 +103,6 @@ class FirstRunWizard(QtGui.QWizard): # XXX ??? ^v self.is_previously_registered = bool(self.eip_username) self.from_login = False - #self.allow_revisit = None pages_dict = OrderedDict(( # (name, WizardPage) @@ -110,13 +111,15 @@ class FirstRunWizard(QtGui.QWizard): SelectProviderPage), ('login', LogInPage), ('providerinfo', ProviderInfoPage), - ('providersetup', ProviderSetupPage), + ('providersetupvalidation', ProviderSetupValidationPage), ('signup', RegisterUserPage), ('connecting', ConnectingPage), ('lastpage', LastPage) )) self.add_pages_from_dict(pages_dict) + self.validation_errors = {} + self.setPixmap( QtGui.QWizard.BannerPixmap, QtGui.QPixmap(':/images/banner.png')) @@ -151,25 +154,11 @@ class FirstRunWizard(QtGui.QWizard): """ return self.pages_dict.keys().index(page_name) - # XXX was trying to allow temporary - # a revisit. this does not work cause visitedPages - # is not called internally. - - #def allow_page_revisit(self, page_name): - #self.allow_revisit = self.get_page_index(page_name) -# - #def visitedPages(self): - #""" - #reimplementation of visitedPages - #that temporary allows to revisit a page - #if allow_revisit is set - #""" - #visited = super(FirstRunWizard, self).visitedPages() - #allow = self.allow_revisit - #if allow: - #visited.remove(allow) - #self.allow_revisit = None - #return visited + 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 @@ -447,6 +436,20 @@ class SelectProviderPage(QtGui.QWizardPage): self.certinfoGroup.hide() def validatePage(self): + ################################## + # XXX FIXME! + ################################## + ################################## + ################################## + ################################## + ##### validation skipped !!! ##### + ################################## + ################################## + return True + ################################## + ################################## + ################################## + wizard = self.wizard() netchecker = wizard.netchecker() providercertchecker = wizard.providercertchecker() @@ -559,39 +562,25 @@ class ProviderInfoPage(QtGui.QWizardPage): def nextId(self): wizard = self.wizard() - if not wizard: - return - return wizard.get_page_index('providersetup') + next_ = "providersetupvalidation" + return wizard.get_page_index(next_) -class ProviderSetupPage(QtGui.QWizardPage): +class ProviderSetupValidationPage(ValidationPage): def __init__(self, parent=None): - super(ProviderSetupPage, self).__init__(parent) - - self.setTitle("Provider Setup") - self.setSubTitle("Setting up provider.") + super(ProviderSetupValidationPage, self).__init__(parent) + self.setTitle("Setting up provider") + #self.setSubTitle( + #"auto configuring provider...") self.setPixmap( QtGui.QWizard.LogoPixmap, QtGui.QPixmap(APP_LOGO)) - self.status = QtGui.QLabel("") - self.progress = QtGui.QProgressBar() - self.progress.setMaximum(100) - self.progress.hide() - - layout = QtGui.QGridLayout() - layout.addWidget(self.status, 0, 1) - layout.addWidget(self.progress, 5, 1) - - self.setLayout(layout) - - def set_status(self, status): - self.status.setText(status) - self.status.setWordWrap(True) - - def fetch_and_validate(self): - # Fake... till you make it... + def _do_checks(self, signal=None): + """ + executes actual checks in a separate thread + """ import time domain = self.field('provider_domain') wizard = self.wizard() @@ -600,7 +589,7 @@ class ProviderSetupPage(QtGui.QWizardPage): pCertChecker = wizard.providercertchecker certchecker = pCertChecker(domain=domain) - self.set_status('Fetching CA certificate') + signal.emit('Fetching CA certificate') self.progress.setValue(30) if pconfig: @@ -615,68 +604,66 @@ class ProviderSetupPage(QtGui.QWizardPage): # (Check with the trusted fingerprints dict # or something smart) - certchecker.download_ca_cert( - uri=ca_cert_uri, - verify=False) + #certchecker.download_ca_cert( + #uri=ca_cert_uri, + #verify=False) + + time.sleep(2) - self.set_status('Checking CA fingerprint') + signal.emit('Checking CA fingerprint') self.progress.setValue(66) - ca_cert_fingerprint = pconfig.get('ca_cert_fingerprint', None) + #ca_cert_fingerprint = pconfig.get('ca_cert_fingerprint', None) # XXX get fingerprint dict (types) - sha256_fpr = ca_cert_fingerprint.split('=')[1] + #sha256_fpr = ca_cert_fingerprint.split('=')[1] - validate_fpr = certchecker.check_ca_cert_fingerprint( - fingerprint=sha256_fpr) + #validate_fpr = certchecker.check_ca_cert_fingerprint( + #fingerprint=sha256_fpr) time.sleep(0.5) - if not validate_fpr: + #if not validate_fpr: # XXX update validationMsg # should catch exception - return False + #return False - self.set_status('Validating api certificate') + 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) + #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 + #api_cert_verified = True - if not api_cert_verified: + #if not api_cert_verified: # XXX update validationMsg # should catch exception - return False + #return False time.sleep(0.5) #ca_cert_path = checker.ca_cert_path self.progress.setValue(100) + signal.emit('end_sentinel') time.sleep(1) - # pagewizard methods - - def initializePage(self): - self.set_status( - 'We are going to contact the provider to get ' - 'the certificates that will be used to stablish ' - 'a secure connection.

Click next to continue.') - self.progress.setValue(0) - self.progress.hide() - - # XXX use a call to "next" instead? - #self.wizard().next() - - def validatePage(self): - self.progress.show() - self.fetch_and_validate() - - return True + def _do_validation(self): + """ + called after _do_checks has finished + (connected to checker thread finished signal) + """ + 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() @@ -952,12 +939,15 @@ class RegisterUserPage(QtGui.QWizardPage, UserFormMixIn): signup = auth.LeapSRPRegister( schema="http", - provider=domain, + #provider=domain, + ########################### + # FIXME! REMOVE DEBUG! + # # debug ----- - #provider="localhost", + provider="localhost", #register_path="timeout", - #port=8000 + port=8000 ) try: ok, req = signup.register_user(username, password) -- cgit v1.2.3 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/firstrunwizard.py | 1301 ---------------------------------------- 1 file changed, 1301 deletions(-) delete mode 100755 src/leap/gui/firstrunwizard.py (limited to 'src/leap/gui/firstrunwizard.py') diff --git a/src/leap/gui/firstrunwizard.py b/src/leap/gui/firstrunwizard.py deleted file mode 100755 index 7876c3c8..00000000 --- a/src/leap/gui/firstrunwizard.py +++ /dev/null @@ -1,1301 +0,0 @@ -#!/usr/bin/env python -import logging -import json -import socket - -import requests - -import sip -sip.setapi('QString', 2) -sip.setapi('QVariant', 2) - -from PyQt4 import QtCore -from PyQt4 import QtGui - -from leap.base import auth -from leap.base import checks as basechecks -from leap.base import exceptions as baseexceptions -from leap.crypto import certs -from leap.crypto import leapkeyring -from leap.eip import checks as eipchecks -from leap.eip import exceptions as eipexceptions -from leap.gui.progress import ValidationPage -from leap.util.coroutines import coroutine - -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__) - -APP_LOGO = ':/images/leap-color-small.png' - -# bare is the username portion of a JID -# full includes the "at" and some extra chars -# that can be allowed for fqdn - -BARE_USERNAME_REGEX = r"^[A-Za-z\d_]+$" -FULL_USERNAME_REGEX = r"^[A-Za-z\d_@.-]+$" - - -ErrorLabelStyleSheet = """ -QLabel { color: red; - font-weight: bold} -""" - - -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): - 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 - - # 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(( - # (name, WizardPage) - ('intro', IntroPage), - ('providerselection', - SelectProviderPage), - ('login', LogInPage), - ('providerinfo', ProviderInfoPage), - ('providersetupvalidation', ProviderSetupValidationPage), - ('signup', RegisterUserPage), - ('connecting', ConnectingPage), - ('lastpage', 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)) - - -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_) - - -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() - - #layout.addWidget(self.certInfo, 4, 1, 4, 2) - #layout.addWidget(self.certWarning, 6, 1, 6, 2) - #layout.addWidget( - #self.trustProviderCertCheckBox, - #8, 1, 8, 2) - - #self.trustProviderCertCheckBox.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 - ################################## - ################################## - ################################## - - 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') - - -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 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_) - - -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) - """ - 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_) - - -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) - - -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 - - -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. - 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') - - # XXX TODO -- remove debug info - # XXX get from provider info - # XXX enforce https - # and pass a verify value - - signup = auth.LeapSRPRegister( - schema="http", - #provider=domain, - - ########################### - # FIXME! REMOVE DEBUG! - # - # debug ----- - provider="localhost", - #register_path="timeout", - port=8000 - ) - 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') - - -class GlobalEIPSettings(QtGui.QWizardPage): - """ - not in use right now - """ - def __init__(self, parent=None): - super(GlobalEIPSettings, self).__init__(parent) - - -class ConnectingPage(QtGui.QWizardPage): - 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): - validated = self.fetch_and_validate() - return validated - - -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): - 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)) - - -if __name__ == '__main__': - # standalone test - import sys - import logging - logging.basicConfig() - logger = logging.getLogger() - logger.setLevel(logging.DEBUG) - - app = QtGui.QApplication(sys.argv) - - trusted_certs = { - "3DF83F316BFA0186" - "0A11A5C9C7FC24B9" - "18C62B941192CC1A" - "49AE62218B2A4B7C": ['springbok']} - - wizard = FirstRunWizard(None, trusted_certs=trusted_certs) - wizard.show() - sys.exit(app.exec_()) -- cgit v1.2.3