diff options
-rw-r--r-- | changes/bug-5048_version-checks-in-wizard | 1 | ||||
-rw-r--r-- | changes/bug-5219_srpauth-error-messages | 1 | ||||
-rw-r--r-- | src/leap/bitmask/crypto/srpauth.py | 73 | ||||
-rw-r--r-- | src/leap/bitmask/gui/mainwindow.py | 99 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/wizard.ui | 73 | ||||
-rw-r--r-- | src/leap/bitmask/gui/wizard.py | 11 |
6 files changed, 142 insertions, 116 deletions
diff --git a/changes/bug-5048_version-checks-in-wizard b/changes/bug-5048_version-checks-in-wizard new file mode 100644 index 00000000..a5593e6c --- /dev/null +++ b/changes/bug-5048_version-checks-in-wizard @@ -0,0 +1 @@ +- Use version checks in the wizard when the user choose to use an existing provider. Closes #5048. diff --git a/changes/bug-5219_srpauth-error-messages b/changes/bug-5219_srpauth-error-messages new file mode 100644 index 00000000..d46b1504 --- /dev/null +++ b/changes/bug-5219_srpauth-error-messages @@ -0,0 +1 @@ +- Move error messages from srpauth to the GUI and refactor signals. Closes #5219. diff --git a/src/leap/bitmask/crypto/srpauth.py b/src/leap/bitmask/crypto/srpauth.py index b46f0ea6..7cf7e55a 100644 --- a/src/leap/bitmask/crypto/srpauth.py +++ b/src/leap/bitmask/crypto/srpauth.py @@ -171,9 +171,6 @@ class SRPAuth(QtCore.QObject): self._srp_user = None self._srp_a = None - # Error msg displayed if the username or the password is invalid - self._WRONG_USER_PASS = self.tr("Invalid username or password.") - # User credentials stored for password changing checks self._username = None self._password = None @@ -267,14 +264,11 @@ class SRPAuth(QtCore.QObject): # Clean up A value, we don't need it anymore self._srp_a = None except requests.exceptions.ConnectionError as e: - logger.error("No connection made (salt): %r" % - (e,)) - raise SRPAuthConnectionError("Could not establish a " - "connection") + logger.error("No connection made (salt): {0!r}".format(e)) + raise SRPAuthConnectionError() except Exception as e: logger.error("Unknown error: %r" % (e,)) - raise SRPAuthenticationError("Unknown error: %r" % - (e,)) + raise SRPAuthenticationError() content, mtime = reqhelper.get_content(init_session) @@ -283,23 +277,22 @@ class SRPAuth(QtCore.QObject): "Status code = %r. Content: %r" % (init_session.status_code, content)) if init_session.status_code == 422: - raise SRPAuthBadUserOrPassword(self._WRONG_USER_PASS) + logger.error("Invalid username or password.") + raise SRPAuthBadUserOrPassword() - raise SRPAuthBadStatusCode(self.tr("There was a problem with" - " authentication")) + logger.error("There was a problem with authentication.") + raise SRPAuthBadStatusCode() json_content = json.loads(content) salt = json_content.get("salt", None) B = json_content.get("B", None) if salt is None: - logger.error("No salt parameter sent") - raise SRPAuthNoSalt(self.tr("The server did not send " - "the salt parameter")) + logger.error("The server didn't send the salt parameter.") + raise SRPAuthNoSalt() if B is None: - logger.error("No B parameter sent") - raise SRPAuthNoB(self.tr("The server did not send " - "the B parameter")) + logger.error("The server didn't send the B parameter.") + raise SRPAuthNoB() return salt, B @@ -330,8 +323,7 @@ class SRPAuth(QtCore.QObject): unhex_B = self._safe_unhexlify(B) except (TypeError, ValueError) as e: logger.error("Bad data from server: %r" % (e,)) - raise SRPAuthBadDataFromServer( - self.tr("The data sent from the server had errors")) + raise SRPAuthBadDataFromServer() M = self._srp_user.process_challenge(unhex_salt, unhex_B) auth_url = "%s/%s/%s/%s" % (self._provider_config.get_api_uri(), @@ -352,13 +344,13 @@ class SRPAuth(QtCore.QObject): timeout=REQUEST_TIMEOUT) except requests.exceptions.ConnectionError as e: logger.error("No connection made (HAMK): %r" % (e,)) - raise SRPAuthConnectionError(self.tr("Could not connect to " - "the server")) + raise SRPAuthConnectionError() try: content, mtime = reqhelper.get_content(auth_result) except JSONDecodeError: - raise SRPAuthJSONDecodeError("Bad JSON content in auth result") + logger.error("Bad JSON content in auth result.") + raise SRPAuthJSONDecodeError() if auth_result.status_code == 422: error = "" @@ -372,14 +364,13 @@ class SRPAuth(QtCore.QObject): "received: %s", (content,)) logger.error("[%s] Wrong password (HAMK): [%s]" % (auth_result.status_code, error)) - raise SRPAuthBadUserOrPassword(self._WRONG_USER_PASS) + raise SRPAuthBadUserOrPassword() if auth_result.status_code not in (200,): logger.error("No valid response (HAMK): " "Status code = %s. Content = %r" % (auth_result.status_code, content)) - raise SRPAuthBadStatusCode(self.tr("Unknown error (%s)") % - (auth_result.status_code,)) + raise SRPAuthBadStatusCode() return json.loads(content) @@ -400,8 +391,7 @@ class SRPAuth(QtCore.QObject): token = json_content.get("token", None) except Exception as e: logger.error(e) - raise SRPAuthBadDataFromServer("Something went wrong with the " - "login") + raise SRPAuthBadDataFromServer() self.set_uuid(uuid) self.set_token(token) @@ -409,8 +399,7 @@ class SRPAuth(QtCore.QObject): if M2 is None or self.get_uuid() is None: logger.error("Something went wrong. Content = %r" % (json_content,)) - raise SRPAuthBadDataFromServer(self.tr("Problem getting data " - "from server")) + raise SRPAuthBadDataFromServer() events_signal( proto.CLIENT_UID, content=uuid, @@ -436,22 +425,19 @@ class SRPAuth(QtCore.QObject): unhex_M2 = self._safe_unhexlify(M2) except TypeError: logger.error("Bad data from server (HAWK)") - raise SRPAuthBadDataFromServer(self.tr("Bad data from server")) + raise SRPAuthBadDataFromServer() self._srp_user.verify_session(unhex_M2) if not self._srp_user.authenticated(): - logger.error("Auth verification failed") - raise SRPAuthVerificationFailed(self.tr("Auth verification " - "failed")) + logger.error("Auth verification failed.") + raise SRPAuthVerificationFailed() logger.debug("Session verified.") session_id = self._session.cookies.get(self.SESSION_ID_KEY, None) if not session_id: logger.error("Bad cookie from server (missing _session_id)") - raise SRPAuthNoSessionId(self.tr("Session cookie " - "verification " - "failed")) + raise SRPAuthNoSessionId() events_signal( proto.CLIENT_SESSION_ID, content=session_id, @@ -618,8 +604,9 @@ class SRPAuth(QtCore.QObject): __instance = None - authentication_finished = QtCore.Signal(bool, str) - logout_finished = QtCore.Signal(bool, str) + authentication_finished = QtCore.Signal() + logout_ok = QtCore.Signal() + logout_error = QtCore.Signal() def __init__(self, provider_config): """ @@ -693,7 +680,7 @@ class SRPAuth(QtCore.QObject): :type _: IGNORED """ logger.debug("Successful login!") - self.authentication_finished.emit(True, self.tr("Succeeded")) + self.authentication_finished.emit() def get_session_id(self): return self.__instance.get_session_id() @@ -711,8 +698,10 @@ class SRPAuth(QtCore.QObject): """ try: self.__instance.logout() - self.logout_finished.emit(True, self.tr("Succeeded")) + logger.debug("Logout success") + self.logout_ok.emit() return True except Exception as e: - self.logout_finished.emit(False, "%s" % (e,)) + logger.debug("Logout error: {0!r}".format(e)) + self.logout_error.emit() return False diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 004d135b..7cec4831 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -32,7 +32,10 @@ from leap.bitmask import __version_hash__ as VERSION_HASH from leap.bitmask.config import flags from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.config.providerconfig import ProviderConfig + +from leap.bitmask.crypto import srpauth from leap.bitmask.crypto.srpauth import SRPAuth + from leap.bitmask.gui.loggerwindow import LoggerWindow from leap.bitmask.gui.advanced_key_management import AdvancedKeyManagement from leap.bitmask.gui.login import LoginWidget @@ -1051,13 +1054,30 @@ class MainWindow(QtGui.QMainWindow): # as we are doing with the prov_cancelled_setup signal. # After we move srpauth to the backend, we need to update this. logger.error("Error logging in, {0!r}".format(failure)) + if failure.check(CancelledError): logger.debug("Defer cancelled.") failure.trap(Exception) self._set_login_cancelled() + return + elif failure.check(srpauth.SRPAuthBadUserOrPassword): + msg = self.tr("Invalid username or password.") + elif failure.check(srpauth.SRPAuthBadStatusCode, + srpauth.SRPAuthenticationError, + srpauth.SRPAuthVerificationFailed, + srpauth.SRPAuthNoSessionId, + srpauth.SRPAuthNoSalt, srpauth.SRPAuthNoB, + srpauth.SRPAuthBadDataFromServer, + srpauth.SRPAuthJSONDecodeError): + msg = self.tr("There was a server problem with authentication.") + elif failure.check(srpauth.SRPAuthConnectionError): + msg = self.tr("Could not establish a connection.") else: - self._login_widget.set_status(str(failure.value)) - self._login_widget.set_enabled(True) + # this shouldn't happen, but just in case. + msg = self.tr("Unknown error: {0!r}".format(failure.value)) + + self._login_widget.set_status(msg) + self._login_widget.set_enabled(True) def _cancel_login(self): """ @@ -1119,8 +1139,8 @@ class MainWindow(QtGui.QMainWindow): self._srp_auth = SRPAuth(self._provider_config) self._srp_auth.authentication_finished.connect( self._authentication_finished) - self._srp_auth.logout_finished.connect( - self._done_logging_out) + self._srp_auth.logout_ok.connect(self._logout_ok) + self._srp_auth.logout_error.connect(self._logout_error) self._login_defer = self._srp_auth.authenticate(username, password) self._login_defer.addErrback(self._login_errback) @@ -1130,7 +1150,7 @@ class MainWindow(QtGui.QMainWindow): logger.error(data[self._backend.ERROR_KEY]) self._login_widget.set_enabled(True) - def _authentication_finished(self, ok, message): + def _authentication_finished(self): """ SLOT TRIGGER: self._srp_auth.authentication_finished @@ -1138,30 +1158,23 @@ class MainWindow(QtGui.QMainWindow): Once the user is properly authenticated, try starting the EIP service """ - # In general we want to "filter" likely complicated error - # messages, but in this case, the messages make more sense as - # they come. Since they are "Unknown user" or "Unknown - # password" - self._login_widget.set_status(message, error=not ok) - - if ok: - self._logged_user = self._login_widget.get_user() - user = self._logged_user - domain = self._provider_config.get_domain() - full_user_id = make_address(user, domain) - self._mail_conductor.userid = full_user_id - self._login_defer = None - self._start_eip_bootstrap() - - # if soledad/mail is enabled: - if MX_SERVICE in self._enabled_services: - btn_enabled = self._login_widget.set_logout_btn_enabled - btn_enabled(False) - self.soledad_ready.connect(lambda: btn_enabled(True)) - self._soledad_bootstrapper.soledad_failed.connect( - lambda: btn_enabled(True)) - else: - self._login_widget.set_enabled(True) + self._login_widget.set_status(self.tr("Succeeded"), error=False) + + self._logged_user = self._login_widget.get_user() + user = self._logged_user + domain = self._provider_config.get_domain() + full_user_id = make_address(user, domain) + self._mail_conductor.userid = full_user_id + self._login_defer = None + self._start_eip_bootstrap() + + # if soledad/mail is enabled: + if MX_SERVICE in self._enabled_services: + btn_enabled = self._login_widget.set_logout_btn_enabled + btn_enabled(False) + self.soledad_ready.connect(lambda: btn_enabled(True)) + self._soledad_bootstrapper.soledad_failed.connect( + lambda: btn_enabled(True)) def _start_eip_bootstrap(self): """ @@ -1831,11 +1844,22 @@ class MainWindow(QtGui.QMainWindow): threads.deferToThread(self._srp_auth.logout) self.logout.emit() - def _done_logging_out(self, ok, message): - # TODO missing params in docstring + def _logout_error(self): """ SLOT - TRIGGER: self._srp_auth.logout_finished + TRIGGER: self._srp_auth.logout_error + + Inform the user about a logout error. + """ + self._login_widget.done_logout() + self.ui.lblLoginProvider.setText(self.tr("Login")) + self._login_widget.set_status( + self.tr("Something went wrong with the logout.")) + + def _logout_ok(self): + """ + SLOT + TRIGGER: self._srp_auth.logout_ok Switches the stackedWidget back to the login stage after logging out @@ -1843,14 +1867,9 @@ class MainWindow(QtGui.QMainWindow): self._login_widget.done_logout() self.ui.lblLoginProvider.setText(self.tr("Login")) - if ok: - self._logged_user = None - self._login_widget.logged_out() - self._mail_status.mail_state_disabled() - - else: - self._login_widget.set_status( - self.tr("Something went wrong with the logout.")) + self._logged_user = None + self._login_widget.logged_out() + self._mail_status.mail_state_disabled() def _intermediate_stage(self, data): # TODO this method name is confusing as hell. diff --git a/src/leap/bitmask/gui/ui/wizard.ui b/src/leap/bitmask/gui/ui/wizard.ui index d9b8499e..6c592522 100644 --- a/src/leap/bitmask/gui/ui/wizard.ui +++ b/src/leap/bitmask/gui/ui/wizard.ui @@ -269,20 +269,7 @@ <string>Configure or select a provider</string> </property> <layout class="QGridLayout" name="gridLayout_5"> - <item row="5" column="1"> - <widget class="QLineEdit" name="lnProvider"/> - </item> - <item row="5" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>https://</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="4" column="0"> + <item row="1" column="0"> <widget class="QRadioButton" name="rbNewProvider"> <property name="text"> <string>Configure new provider:</string> @@ -292,14 +279,27 @@ </property> </widget> </item> - <item row="5" column="2"> - <widget class="QPushButton" name="btnCheck"> + <item row="0" column="2"> + <widget class="QComboBox" name="cbProviders"> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="label"> <property name="text"> - <string>Check</string> + <string>https://</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="2" column="0"> + <item row="1" column="2"> + <widget class="QLineEdit" name="lnProvider"/> + </item> + <item row="0" column="0"> <widget class="QRadioButton" name="rbExistingProvider"> <property name="text"> <string>Use existing one:</string> @@ -309,7 +309,7 @@ </property> </widget> </item> - <item row="3" column="0"> + <item row="0" column="1"> <widget class="QLabel" name="label_8"> <property name="text"> <string>https://</string> @@ -319,12 +319,29 @@ </property> </widget> </item> - <item row="3" column="1"> - <widget class="QComboBox" name="cbProviders"> - <property name="enabled"> - <bool>false</bool> - </property> - </widget> + <item row="2" column="2"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="btnCheck"> + <property name="text"> + <string>Check</string> + </property> + </widget> + </item> + </layout> </item> </layout> </widget> @@ -859,8 +876,8 @@ <y>174</y> </hint> <hint type="destinationlabel"> - <x>454</x> - <y>254</y> + <x>450</x> + <y>266</y> </hint> </hints> </connection> @@ -884,7 +901,7 @@ <sender>rbExistingProvider</sender> <signal>toggled(bool)</signal> <receiver>btnCheck</receiver> - <slot>setDisabled(bool)</slot> + <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> <x>169</x> diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index e1bed6b8..024b23bc 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -223,7 +223,7 @@ class Wizard(QtGui.QWizard): depending on the lnProvider content. """ enabled = len(self.ui.lnProvider.text()) != 0 - enabled = enabled and self.ui.rbNewProvider.isChecked() + enabled = enabled or self.ui.rbExistingProvider.isChecked() self.ui.btnCheck.setEnabled(enabled) if reset: @@ -367,8 +367,10 @@ class Wizard(QtGui.QWizard): Starts the checks for a given provider """ - if len(self.ui.lnProvider.text()) == 0: - return + if self.ui.rbNewProvider.isChecked(): + self._domain = self.ui.lnProvider.text() + else: + self._domain = self.ui.cbProviders.currentText() self._provider_checks_ok = False @@ -380,7 +382,6 @@ class Wizard(QtGui.QWizard): self.ui.btnCheck.setEnabled(False) self.ui.lnProvider.setEnabled(False) self.button(QtGui.QWizard.BackButton).clearFocus() - self._domain = self.ui.lnProvider.text() self.ui.lblNameResolution.setPixmap(self.QUESTION_ICON) self._provider_select_defer = self._backend.\ @@ -401,8 +402,6 @@ class Wizard(QtGui.QWizard): if skip: self._reset_provider_check() - self.page(self.SELECT_PROVIDER_PAGE).set_completed(skip) - self.button(QtGui.QWizard.NextButton).setEnabled(skip) self._use_existing_provider = skip def _complete_task(self, data, label, complete=False, complete_page=-1): |