From 1801a78f9d05ea9d2f3c0321f3b1cc257d1ad278 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 21 Aug 2013 13:02:44 -0300 Subject: Add password change feature. --- src/leap/bitmask/gui/preferenceswindow.py | 160 +++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 2 deletions(-) (limited to 'src/leap/bitmask/gui/preferenceswindow.py') diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index 5f8dd5cc..67448768 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -16,13 +16,15 @@ # along with this program. If not, see . """ -Preferences log window +Preferences window """ import logging +from functools import partial from PySide import QtGui from leap.bitmask.gui.ui_preferences import Ui_Preferences +from leap.soledad.client import NoStorageSecret from leap.bitmask.crypto.srpauth import SRPAuthBadPassword logger = logging.getLogger(__name__) @@ -32,9 +34,163 @@ class PreferencesWindow(QtGui.QDialog): """ Window that displays the preferences. """ - def __init__(self, parent): + + WEAK_PASSWORDS = ("123456", "qweasd", "qwerty", "password") + + def __init__(self, parent, srp_auth, soledad): + """ + :param parent: parent object of the PreferencesWindow. + :parent type: QWidget + :param srp_auth: SRPAuth object configured in the main app. + :type srp_auth: SRPAuth + :param soledad: Soledad object configured in the main app. + :type soledad: Soledad + """ QtGui.QDialog.__init__(self, parent) + self._srp_auth = srp_auth + self._soledad = soledad + # Load UI self.ui = Ui_Preferences() self.ui.setupUi(self) + self.ui.lblPasswordChangeStatus.setVisible(False) + + # Connections + self.ui.pbChangePassword.clicked.connect(self._change_password) + + def _basic_password_checks(self, username, password, password2): + """ + Performs basic password checks to avoid really easy passwords. + + :param username: username provided at the registrarion form + :type username: str + :param password: password from the registration form + :type password: str + :param password2: second password from the registration form + :type password: str + + :returns: True and empty message if all the checks pass, + False and an error message otherwise + :rtype: tuple(bool, str) + """ + message = None + + if message is None and password != password2: + message = self.tr("Passwords don't match") + + if message is None and len(password) < 6: + message = self.tr("Password too short") + + if message is None and password in self.WEAK_PASSWORDS: + message = self.tr("Password too easy") + + if message is None and username == password: + message = self.tr("Password equal to username") + + return message is None, message + + def _set_password_change_status(self, status, error=False, success=False): + """ + Sets the status label for the password change. + + :param status: status message to display, can be HTML + :type status: str + """ + if error: + status = "%s" % (status,) + elif success: + status = "%s" % (status,) + + self.ui.lblPasswordChangeStatus.setVisible(True) + self.ui.lblPasswordChangeStatus.setText(status) + + def _set_changing_password(self, disable): + """ + Enables or disables the widgets in the password change group box. + + :param disable: True if the widgets should be disabled and + it displays the status label that shows that is + changing the password. + False if they should be enabled. + :type disable: bool + """ + if disable: + self._set_password_change_disable(self.tr("Changing password...")) + + self.ui.leCurrentPassword.setEnabled(not disable) + self.ui.leNewPassword.setEnabled(not disable) + self.ui.leNewPassword2.setEnabled(not disable) + self.ui.pbChangePassword.setEnabled(not disable) + + def _change_password(self): + """ + Changes the user's password if the inputboxes are correctly filled. + """ + username = self._srp_auth.get_username() + current_password = self.ui.leCurrentPassword.text() + new_password = self.ui.leNewPassword.text() + new_password2 = self.ui.leNewPassword2.text() + + ok, msg = self._basic_password_checks( + username, new_password, new_password2) + + if not ok: + self._set_changing_password(False) + self._set_password_change_status(msg, error=True) + self.ui.leNewPassword.setFocus() + return + + self._set_changing_password(True) + d = self._srp_auth.change_password(current_password, new_password) + d.addCallback(partial(self._change_password_success, new_password)) + d.addErrback(self._change_password_problem) + + def _change_password_success(self, new_password, _): + """ + Callback used to display a successfully performed action. + + :param new_password: the new password for the user. + :type new_password: str. + :param _: the returned data from self._srp_auth.change_password + Ignored + """ + logger.debug("SRP password changed successfully.") + try: + self._soledad.change_passphrase(str(new_password)) + logger.debug("Soledad password changed successfully.") + except NoStorageSecret: + logger.debug( + "No storage secret for password change in Soledad.") + + self._set_password_change_status( + self.tr("Password changed successfully."), success=True) + self._clear_inputs() + self._set_changing_password(False) + + def _change_password_problem(self, failure): + """ + Errback called if there was a problem with the deferred. + Also is used to display an error message. + + :param failure: the cause of the method failed. + :type failure: twisted.python.Failure + """ + logger.error("Error changing password: %s", (failure, )) + problem = self.tr("There was a problem changing the password.") + + if failure.check(SRPAuthBadPassword): + problem = self.tr("You did not enter a correct current password.") + + self._set_password_change_status(problem, error=True) + + self._set_changing_password(False) + failure.trap(Exception) + + def _clear_inputs(self): + """ + Clear the contents of the inputs. + """ + self.ui.leCurrentPassword.setText("") + self.ui.leNewPassword.setText("") + self.ui.leNewPassword2.setText("") -- cgit v1.2.3