summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changes/bug_cancel-login-does-not-work1
-rw-r--r--src/leap/bitmask/backend.py36
-rw-r--r--src/leap/bitmask/crypto/srpauth.py13
-rw-r--r--src/leap/bitmask/gui/mainwindow.py69
-rw-r--r--src/leap/bitmask/services/abstractbootstrapper.py7
-rw-r--r--src/leap/bitmask/services/soledad/soledadbootstrapper.py2
6 files changed, 90 insertions, 38 deletions
diff --git a/changes/bug_cancel-login-does-not-work b/changes/bug_cancel-login-does-not-work
new file mode 100644
index 00000000..8fbccb5a
--- /dev/null
+++ b/changes/bug_cancel-login-does-not-work
@@ -0,0 +1 @@
+- Cancel login does not work or needs to be pressed twice. Closes #4869, #4973.
diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py
index df79381c..34457e34 100644
--- a/src/leap/bitmask/backend.py
+++ b/src/leap/bitmask/backend.py
@@ -141,6 +141,14 @@ class Provider(object):
self._download_provider_defer = d
return d
+ def cancel_setup_provider(self):
+ """
+ Cancel the ongoing setup provider defer (if any).
+ """
+ d = self._download_provider_defer
+ if d is not None:
+ d.cancel()
+
def bootstrap(self, provider):
"""
Second stage of bootstrapping for a provider.
@@ -195,6 +203,8 @@ class Signaler(QtCore.QObject):
prov_unsupported_client = QtCore.Signal(object)
prov_unsupported_api = QtCore.Signal(object)
+ prov_cancelled_setup = QtCore.Signal(object)
+
# These will exist both in the backend and the front end.
# The frontend might choose to not "interpret" all the signals
# from the backend, but the backend needs to have all the signals
@@ -208,6 +218,7 @@ class Signaler(QtCore.QObject):
PROV_PROBLEM_WITH_PROVIDER_KEY = "prov_problem_with_provider"
PROV_UNSUPPORTED_CLIENT = "prov_unsupported_client"
PROV_UNSUPPORTED_API = "prov_unsupported_api"
+ PROV_CANCELLED_SETUP = "prov_cancelled_setup"
def __init__(self):
"""
@@ -225,7 +236,8 @@ class Signaler(QtCore.QObject):
self.PROV_CHECK_API_CERTIFICATE_KEY,
self.PROV_PROBLEM_WITH_PROVIDER_KEY,
self.PROV_UNSUPPORTED_CLIENT,
- self.PROV_UNSUPPORTED_API
+ self.PROV_UNSUPPORTED_API,
+ self.PROV_CANCELLED_SETUP,
]
for sig in signals:
@@ -355,17 +367,20 @@ class Backend(object):
# cmd is: component, method, signalback, *args
func = getattr(self._components[cmd[0]], cmd[1])
d = func(*cmd[3:])
- # A call might not have a callback signal, but if it does,
- # we add it to the chain
- if cmd[2] is not None:
- d.addCallbacks(self._signal_back, log.err, cmd[2])
- d.addCallbacks(self._done_action, log.err,
- callbackKeywords={"d": d})
- d.addErrback(log.err)
- self._ongoing_defers.append(d)
+ if d is not None: # d may be None if a defer chain is cancelled.
+ # A call might not have a callback signal, but if it does,
+ # we add it to the chain
+ if cmd[2] is not None:
+ d.addCallbacks(self._signal_back, log.err, cmd[2])
+ d.addCallbacks(self._done_action, log.err,
+ callbackKeywords={"d": d})
+ d.addErrback(log.err)
+ self._ongoing_defers.append(d)
except Empty:
# If it's just empty we don't have anything to do.
pass
+ except defer.CancelledError:
+ logger.debug("defer cancelled somewhere (CancelledError).")
except Exception:
# But we log the rest
log.err()
@@ -387,5 +402,8 @@ class Backend(object):
def setup_provider(self, provider):
self._call_queue.put(("provider", "setup_provider", None, provider))
+ def cancel_setup_provider(self):
+ self._call_queue.put(("provider", "cancel_setup_provider", None))
+
def provider_bootstrap(self, provider):
self._call_queue.put(("provider", "bootstrap", None, provider))
diff --git a/src/leap/bitmask/crypto/srpauth.py b/src/leap/bitmask/crypto/srpauth.py
index bdd38db2..1fb7b774 100644
--- a/src/leap/bitmask/crypto/srpauth.py
+++ b/src/leap/bitmask/crypto/srpauth.py
@@ -655,7 +655,6 @@ class SRPAuth(QtCore.QObject):
username = username.lower()
d = self.__instance.authenticate(username, password)
d.addCallback(self._gui_notify)
- d.addErrback(self._errback)
return d
def change_password(self, current_password, new_password):
@@ -695,18 +694,6 @@ class SRPAuth(QtCore.QObject):
logger.debug("Successful login!")
self.authentication_finished.emit(True, self.tr("Succeeded"))
- def _errback(self, failure):
- """
- General errback for the whole login process. Will notify the
- UI with the proper signal.
-
- :param failure: Failure object captured from a callback.
- :type failure: twisted.python.failure.Failure
- """
- logger.error("Error logging in %s" % (failure,))
- self.authentication_finished.emit(False, "%s" % (failure.value,))
- failure.trap(Exception)
-
def get_session_id(self):
return self.__instance.get_session_id()
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py
index c078e3f4..6512ffce 100644
--- a/src/leap/bitmask/gui/mainwindow.py
+++ b/src/leap/bitmask/gui/mainwindow.py
@@ -23,8 +23,9 @@ from threading import Condition
from datetime import datetime
from PySide import QtCore, QtGui
-from twisted.internet import threads
from zope.proxy import ProxyBase, setProxiedObject
+from twisted.internet import threads
+from twisted.internet.defer import CancelledError
from leap.bitmask import __version__ as VERSION
from leap.bitmask import __version_hash__ as VERSION_HASH
@@ -342,7 +343,7 @@ class MainWindow(QtGui.QMainWindow):
self._keymanager = ProxyBase(None)
self._login_defer = None
- self._download_provider_defer = None
+ self._soledad_defer = None
self._mail_conductor = mail_conductor.MailConductor(
self._soledad, self._keymanager)
@@ -395,6 +396,8 @@ class MainWindow(QtGui.QMainWindow):
sig.prov_unsupported_client.connect(self._needs_update)
sig.prov_unsupported_api.connect(self._incompatible_api)
+ sig.prov_cancelled_setup.connect(self._set_login_cancelled)
+
def _backend_disconnect(self):
"""
Helper to disconnect from backend signals.
@@ -1035,6 +1038,25 @@ class MainWindow(QtGui.QMainWindow):
if self._login_widget.start_login():
self._download_provider_config()
+ def _login_errback(self, failure):
+ """
+ Error handler for the srpauth.authenticate method.
+
+ :param failure: failure object that Twisted generates
+ :type failure: twisted.python.failure.Failure
+ """
+ # NOTE: this behavior needs to be managed through the signaler,
+ # 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()
+ else:
+ self._login_widget.set_status(str(failure.value))
+ self._login_widget.set_enabled(True)
+
def _cancel_login(self):
"""
SLOT
@@ -1043,17 +1065,29 @@ class MainWindow(QtGui.QMainWindow):
Stops the login sequence.
"""
- logger.debug("Cancelling log in.")
+ logger.debug("Cancelling setup provider defer.")
+ self._backend.cancel_setup_provider()
- if self._download_provider_defer:
- logger.debug("Cancelling download provider defer.")
- self._download_provider_defer.cancel()
-
- if self._login_defer:
+ if self._login_defer is not None:
logger.debug("Cancelling login defer.")
self._login_defer.cancel()
+ if self._soledad_defer is not None:
+ logger.debug("Cancelling soledad defer.")
+ self._soledad_defer.cancel()
+
+ def _set_login_cancelled(self):
+ """
+ SLOT
+ TRIGGERS:
+ Signaler.prov_cancelled_setup fired by
+ self._backend.cancel_setup_provider()
+
+ This method re-enables the login widget and display a message for
+ the cancelled operation.
+ """
self._login_widget.set_status(self.tr("Log in cancelled by the user."))
+ self._login_widget.set_enabled(True)
def _provider_config_loaded(self, data):
"""
@@ -1080,6 +1114,7 @@ class MainWindow(QtGui.QMainWindow):
# TODO Add errback!
self._login_defer = self._srp_auth.authenticate(username, password)
+ self._login_defer.addErrback(self._login_errback)
else:
self._login_widget.set_status(
"Unable to login: Problem with provider")
@@ -1168,8 +1203,8 @@ class MainWindow(QtGui.QMainWindow):
provider_config = self._provider_config
if self._logged_user is not None:
- fun = sb.run_soledad_setup_checks
- fun(provider_config, username, password,
+ self._soledad_defer = sb.run_soledad_setup_checks(
+ provider_config, username, password,
download_if_needed=True)
###################################################################
@@ -1243,6 +1278,7 @@ class MainWindow(QtGui.QMainWindow):
# Ok, now soledad is ready, so we can allow other things that
# depend on soledad to start.
+ self._soledad_defer = None
# this will trigger start_imap_service
# and start_smtp_boostrapping
@@ -1814,9 +1850,9 @@ class MainWindow(QtGui.QMainWindow):
"""
passed = data[self._backend.PASSED_KEY]
if not passed:
+ msg = self.tr("Unable to connect: Problem with provider")
+ self._login_widget.set_status(msg)
self._login_widget.set_enabled(True)
- self._login_widget.set_status(
- self.tr("Unable to connect: Problem with provider"))
logger.error(data[self._backend.ERROR_KEY])
#
@@ -1888,9 +1924,12 @@ class MainWindow(QtGui.QMainWindow):
logger.debug("Cancelling login defer.")
self._login_defer.cancel()
- if self._download_provider_defer:
- logger.debug("Cancelling download provider defer.")
- self._download_provider_defer.cancel()
+ logger.debug("Cancelling setup provider defer.")
+ self._backend.cancel_setup_provider()
+
+ if self._soledad_defer is not None:
+ logger.debug("Cancelling soledad defer.")
+ self._soledad_defer.cancel()
# TODO missing any more cancels?
diff --git a/src/leap/bitmask/services/abstractbootstrapper.py b/src/leap/bitmask/services/abstractbootstrapper.py
index 3bee8e01..fc6bd3e9 100644
--- a/src/leap/bitmask/services/abstractbootstrapper.py
+++ b/src/leap/bitmask/services/abstractbootstrapper.py
@@ -28,6 +28,7 @@ from PySide import QtCore
from twisted.python import log
from twisted.internet import threads
+from twisted.internet.defer import CancelledError
from leap.common.check import leap_assert, leap_assert_type
@@ -91,6 +92,12 @@ class AbstractBootstrapper(QtCore.QObject):
:param failure: failure object that Twisted generates
:type failure: twisted.python.failure.Failure
"""
+ if failure.check(CancelledError):
+ logger.debug("Defer cancelled.")
+ failure.trap(Exception)
+ self._signaler.signal(self._signaler.PROV_CANCELLED_SETUP)
+ return
+
if self._signal_to_emit:
err_msg = self._err_msg \
if self._err_msg is not None \
diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py
index 9a292b18..53846b31 100644
--- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py
+++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py
@@ -617,4 +617,4 @@ class SoledadBootstrapper(AbstractBootstrapper):
(self._gen_key, self.gen_key)
]
- self.addCallbackChain(cb_chain)
+ return self.addCallbackChain(cb_chain)