From f0951ad92cb0bf2116a333b8df8279918c5febd6 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Thu, 15 May 2014 16:46:00 -0300 Subject: Move soledad password change to backend. Also cleanup soledad usage in the GUI. --- src/leap/bitmask/backend.py | 84 +++++++++++++++++++++++-- src/leap/bitmask/gui/advanced_key_management.py | 12 ++-- src/leap/bitmask/gui/mainwindow.py | 27 +++----- src/leap/bitmask/gui/preferenceswindow.py | 70 ++++++++++++++------- 4 files changed, 141 insertions(+), 52 deletions(-) diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index 6a6b1065..49a5ca0f 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -56,6 +56,8 @@ from leap.bitmask.services.soledad.soledadbootstrapper import \ from leap.common import certs as leap_certs +from leap.soledad.client import NoStorageSecret, PassphraseTooShort + # Frontend side from PySide import QtCore @@ -644,14 +646,52 @@ class Soledad(object): logger.debug("Cancelling soledad defer.") self._soledad_defer.cancel() self._soledad_defer = None + zope.proxy.setProxiedObject(self._soledad_proxy, None) def close(self): """ Close soledad database. """ - soledad = self._soledad_bootstrapper.soledad - if soledad is not None: - soledad.close() + if not zope.proxy.sameProxiedObjects(self._soledad_proxy, None): + self._soledad_proxy.close() + zope.proxy.setProxiedObject(self._soledad_proxy, None) + + def _change_password_ok(self, _): + """ + Password change callback. + """ + if self._signaler is not None: + self._signaler.signal(self._signaler.SOLEDAD_PASSWORD_CHANGE_OK) + + def _change_password_error(self, failure): + """ + Password change errback. + + :param failure: failure object containing problem. + :type failure: twisted.python.failure.Failure + """ + if failure.check(NoStorageSecret): + logger.error("No storage secret for password change in Soledad.") + if failure.check(PassphraseTooShort): + logger.error("Passphrase too short.") + + if self._signaler is not None: + self._signaler.signal(self._signaler.SOLEDAD_PASSWORD_CHANGE_ERROR) + + def change_password(self, new_password): + """ + Change the database's password. + + :param new_password: the new password. + :type new_password: unicode + + :returns: a defer to interact with. + :rtype: twisted.internet.defer.Deferred + """ + d = threads.deferToThread(self._soledad_proxy.change_passphrase, + new_password) + d.addCallback(self._change_password_ok) + d.addErrback(self._change_password_error) class Mail(object): @@ -691,6 +731,9 @@ class Mail(object): :param download_if_needed: True if it should check for mtime for the file :type download_if_needed: bool + + :returns: a defer to interact with. + :rtype: twisted.internet.defer.Deferred """ return threads.deferToThread( self._smtp_bootstrapper.start_smtp_service, @@ -704,6 +747,9 @@ class Mail(object): :type full_user_id: str :param offline: whether imap should start in offline mode or not. :type offline: bool + + :returns: a defer to interact with. + :rtype: twisted.internet.defer.Deferred """ return threads.deferToThread( self._imap_controller.start_imap_service, @@ -712,6 +758,9 @@ class Mail(object): def stop_smtp_service(self): """ Stop the SMTP service. + + :returns: a defer to interact with. + :rtype: twisted.internet.defer.Deferred """ return threads.deferToThread(self._smtp_bootstrapper.stop_smtp_service) @@ -722,6 +771,9 @@ class Mail(object): :param cv: A condition variable to which we can signal when imap indeed stops. :type cv: threading.Condition + + :returns: a defer to interact with. + :rtype: twisted.internet.defer.Deferred """ return threads.deferToThread( self._imap_controller.stop_imap_service, cv) @@ -927,6 +979,8 @@ class Signaler(QtCore.QObject): soledad_offline_finished = QtCore.Signal(object) soledad_invalid_auth_token = QtCore.Signal(object) soledad_cancelled_bootstrap = QtCore.Signal(object) + soledad_password_change_ok = QtCore.Signal(object) + soledad_password_change_error = QtCore.Signal(object) # This signal is used to warn the backend user that is doing something # wrong @@ -1003,6 +1057,9 @@ class Signaler(QtCore.QObject): SOLEDAD_OFFLINE_FINISHED = "soledad_offline_finished" SOLEDAD_INVALID_AUTH_TOKEN = "soledad_invalid_auth_token" + SOLEDAD_PASSWORD_CHANGE_OK = "soledad_password_change_ok" + SOLEDAD_PASSWORD_CHANGE_ERROR = "soledad_password_change_error" + SOLEDAD_CANCELLED_BOOTSTRAP = "soledad_cancelled_bootstrap" BACKEND_BAD_CALL = "backend_bad_call" @@ -1083,6 +1140,9 @@ class Signaler(QtCore.QObject): self.SOLEDAD_INVALID_AUTH_TOKEN, self.SOLEDAD_CANCELLED_BOOTSTRAP, + self.SOLEDAD_PASSWORD_CHANGE_OK, + self.SOLEDAD_PASSWORD_CHANGE_ERROR, + self.BACKEND_BAD_CALL, ] @@ -1470,7 +1530,7 @@ class Backend(object): """ self._call_queue.put(("authenticate", "cancel_login", None)) - def change_password(self, current_password, new_password): + def auth_change_password(self, current_password, new_password): """ Change the user's password. @@ -1488,6 +1548,22 @@ class Backend(object): self._call_queue.put(("authenticate", "change_password", None, current_password, new_password)) + def soledad_change_password(self, new_password): + """ + Change the database's password. + + :param new_password: the new password for the user. + :type new_password: unicode + + Signals: + srp_not_logged_in_error + srp_password_change_ok + srp_password_change_badpw + srp_password_change_error + """ + self._call_queue.put(("soledad", "change_password", None, + new_password)) + def get_logged_in_status(self): """ Signal if the user is currently logged in or not. diff --git a/src/leap/bitmask/gui/advanced_key_management.py b/src/leap/bitmask/gui/advanced_key_management.py index be6b4410..1681caca 100644 --- a/src/leap/bitmask/gui/advanced_key_management.py +++ b/src/leap/bitmask/gui/advanced_key_management.py @@ -20,7 +20,6 @@ Advanced Key Management import logging from PySide import QtGui -from zope.proxy import sameProxiedObjects from leap.keymanager import openpgp from leap.keymanager.errors import KeyAddressMismatch, KeyFingerprintMismatch @@ -34,7 +33,7 @@ class AdvancedKeyManagement(QtGui.QDialog): """ Advanced Key Management """ - def __init__(self, parent, has_mx, user, keymanager, soledad): + def __init__(self, parent, has_mx, user, keymanager, soledad_started): """ :param parent: parent object of AdvancedKeyManagement. :parent type: QWidget @@ -45,8 +44,8 @@ class AdvancedKeyManagement(QtGui.QDialog): :type user: unicode :param keymanager: the existing keymanager instance :type keymanager: KeyManager - :param soledad: a loaded instance of Soledad - :type soledad: Soledad + :param soledad_started: whether soledad has started or not + :type soledad_started: bool """ QtGui.QDialog.__init__(self, parent) @@ -56,7 +55,6 @@ class AdvancedKeyManagement(QtGui.QDialog): # XXX: Temporarily disable the key import. self.ui.pbImportKeys.setVisible(False) - # if Soledad is not started yet if not has_mx: msg = self.tr("The provider that you are using " "does not support {0}.") @@ -64,8 +62,7 @@ class AdvancedKeyManagement(QtGui.QDialog): self._disable_ui(msg) return - # if Soledad is not started yet - if sameProxiedObjects(soledad, None): + if not soledad_started: msg = self.tr("To use this, you need to enable/start {0}.") msg = msg.format(get_service_display_name(MX_SERVICE)) self._disable_ui(msg) @@ -79,7 +76,6 @@ class AdvancedKeyManagement(QtGui.QDialog): # self.ui.lblStatus.setText(msg) self._keymanager = keymanager - self._soledad = soledad self._key = keymanager.get_key(user, openpgp.OpenPGPKey) self._key_priv = keymanager.get_key( diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index cd3e77c9..e1527bbe 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -189,6 +189,7 @@ class MainWindow(QtGui.QMainWindow): self._provisional_provider_config = ProviderConfig() self._already_started_eip = False + self._soledad_started = False # This is created once we have a valid provider config self._srp_auth = None @@ -276,15 +277,9 @@ class MainWindow(QtGui.QMainWindow): self._bypass_checks = bypass_checks self._start_hidden = start_hidden - # We initialize Soledad and Keymanager instances as - # transparent proxies, so we can pass the reference freely - # around. - self._soledad = ProxyBase(None) self._keymanager = ProxyBase(None) self._mail_conductor = mail_conductor.MailConductor(self._backend) - # self._mail_conductor = mail_conductor.MailConductor( - # self._soledad, self._keymanager) self._mail_conductor.connect_mail_signals(self._mail_status) # Eip machine is a public attribute where the state machine for @@ -603,8 +598,8 @@ class MainWindow(QtGui.QMainWindow): provider_config = self._get_best_provider_config() has_mx = provider_config.provides_mx() - akm = AdvancedKeyManagement( - self, has_mx, logged_user, self._keymanager, self._soledad) + akm = AdvancedKeyManagement(self, has_mx, logged_user, + self._keymanager, self._soledad_started) akm.show() @QtCore.Slot() @@ -619,8 +614,8 @@ class MainWindow(QtGui.QMainWindow): user = self._login_widget.get_user() prov = self._login_widget.get_selected_provider() preferences = PreferencesWindow( - self, self._backend, self._provider_config, self._soledad, - user, prov) + self, self._backend, self._provider_config, + self._soledad_started, user, prov) self.soledad_ready.connect(preferences.set_soledad_ready) preferences.show() @@ -1265,6 +1260,9 @@ class MainWindow(QtGui.QMainWindow): self._backend.cancel_setup_provider() self._backend.cancel_login() self._backend.cancel_soledad_bootstrap() + self._backend.close_soledad() + + self._soledad_started = False @QtCore.Slot() def _set_login_cancelled(self): @@ -1419,9 +1417,8 @@ class MainWindow(QtGui.QMainWindow): """ logger.debug("Done bootstrapping Soledad") - # Update the proxy objects to point to - # the initialized instances. - setProxiedObject(self._soledad, self._backend.get_soledad()) + # Update the proxy objects to point to the initialized instances. + # setProxiedObject(self._soledad, self._backend.get_soledad()) setProxiedObject(self._keymanager, self._backend.get_keymanager()) self._soledad_started = True @@ -1930,8 +1927,6 @@ class MainWindow(QtGui.QMainWindow): Starts the logout sequence """ - setProxiedObject(self._soledad, None) - self._cancel_ongoing_defers() # XXX: If other defers are doing authenticated stuff, this @@ -2041,8 +2036,6 @@ class MainWindow(QtGui.QMainWindow): if self._logged_user is not None: self._backend.logout() - self._backend.close_soledad() - logger.debug('Terminating vpn') self._backend.stop_eip(shutdown=True) diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index 2947c5db..77a3994f 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -23,12 +23,10 @@ import logging from functools import partial from PySide import QtCore, QtGui -from zope.proxy import sameProxiedObjects from leap.bitmask.provider import get_provider_path from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.gui.ui_preferences import Ui_Preferences -from leap.soledad.client import NoStorageSecret from leap.bitmask.util.password import basic_password_checks from leap.bitmask.services import get_supported from leap.bitmask.config.providerconfig import ProviderConfig @@ -43,8 +41,8 @@ class PreferencesWindow(QtGui.QDialog): """ preferences_saved = QtCore.Signal() - def __init__(self, parent, backend, provider_config, - soledad, username, domain): + def __init__(self, parent, backend, provider_config, soledad_started, + username, domain): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget @@ -52,8 +50,8 @@ class PreferencesWindow(QtGui.QDialog): :type backend: Backend :param provider_config: ProviderConfig object. :type provider_config: ProviderConfig - :param soledad: Soledad instance - :type soledad: Soledad + :param soledad_started: whether soledad has started or not + :type soledad_started: bool :param username: the user set in the login widget :type username: unicode :param domain: the selected domain in the login widget @@ -64,8 +62,8 @@ class PreferencesWindow(QtGui.QDialog): self._backend = backend self._settings = LeapSettings() - self._soledad = soledad self._provider_config = provider_config + self._soledad_started = soledad_started self._username = username self._domain = domain @@ -118,7 +116,7 @@ class PreferencesWindow(QtGui.QDialog): pw_enabled = False else: # check if Soledad is bootstrapped - if sameProxiedObjects(self._soledad, None): + if not self._soledad_started: msg = self.tr( "You need to wait until {0} is ready in " "order to change the password.".format(mx_name)) @@ -209,10 +207,10 @@ class PreferencesWindow(QtGui.QDialog): return self._set_changing_password(True) - self._backend.change_password(current_password, new_password) + self._backend.auth_change_password(current_password, new_password) @QtCore.Slot() - def _change_password_ok(self): + def _srp_change_password_ok(self): """ TRIGGERS: self._backend.signaler.srp_password_change_ok @@ -221,12 +219,33 @@ class PreferencesWindow(QtGui.QDialog): """ new_password = self.ui.leNewPassword.text() logger.debug("SRP password changed successfully.") - try: - self._soledad.change_passphrase(new_password) - logger.debug("Soledad password changed successfully.") - except NoStorageSecret: - logger.debug( - "No storage secret for password change in Soledad.") + self._backend.soledad_change_password(new_password) + + @QtCore.Slot(unicode) + def _srp_change_password_problem(self, msg): + """ + TRIGGERS: + self._backend.signaler.srp_password_change_error + self._backend.signaler.srp_password_change_badpw + + Callback used to display an error on changing password. + + :param msg: the message to show to the user. + :type msg: unicode + """ + logger.error("Error changing password") + self._set_password_change_status(msg, error=True) + self._set_changing_password(False) + + @QtCore.Slot() + def _soledad_change_password_ok(self): + """ + TRIGGERS: + Signaler.soledad_password_change_ok + + Callback used to display a successfully changed password. + """ + logger.debug("Soledad password changed successfully.") self._set_password_change_status( self.tr("Password changed successfully."), success=True) @@ -234,18 +253,17 @@ class PreferencesWindow(QtGui.QDialog): self._set_changing_password(False) @QtCore.Slot(unicode) - def _change_password_problem(self, msg): + def _soledad_change_password_problem(self, msg): """ TRIGGERS: - self._backend.signaler.srp_password_change_error - self._backend.signaler.srp_password_change_badpw + Signaler.soledad_password_change_error Callback used to display an error on changing password. :param msg: the message to show to the user. :type msg: unicode """ - logger.error("Error changing password") + logger.error("Error changing soledad password") self._set_password_change_status(msg, error=True) self._set_changing_password(False) @@ -418,12 +436,18 @@ class PreferencesWindow(QtGui.QDialog): sig.srp_status_logged_in.connect(self._is_logged_in) sig.srp_status_not_logged_in.connect(self._not_logged_in) - sig.srp_password_change_ok.connect(self._change_password_ok) + sig.srp_password_change_ok.connect(self._srp_change_password_ok) - pwd_change_error = lambda: self._change_password_problem( + pwd_change_error = lambda: self._srp_change_password_problem( self.tr("There was a problem changing the password.")) sig.srp_password_change_error.connect(pwd_change_error) - pwd_change_badpw = lambda: self._change_password_problem( + pwd_change_badpw = lambda: self._srp_change_password_problem( self.tr("You did not enter a correct current password.")) sig.srp_password_change_badpw.connect(pwd_change_badpw) + + sig.soledad_password_change_ok.connect( + self._soledad_change_password_ok) + + sig.soledad_password_change_error.connect( + self._soledad_change_password_problem) -- cgit v1.2.3