summaryrefslogtreecommitdiff
path: root/src/leap/bitmask/backend.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap/bitmask/backend.py')
-rw-r--r--src/leap/bitmask/backend.py146
1 files changed, 127 insertions, 19 deletions
diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py
index 8a289a79..45ea451c 100644
--- a/src/leap/bitmask/backend.py
+++ b/src/leap/bitmask/backend.py
@@ -18,8 +18,8 @@
Backend for everything
"""
import logging
-import os
+from functools import partial
from Queue import Queue, Empty
from twisted.internet import threads, defer
@@ -29,6 +29,8 @@ from twisted.python import log
import zope.interface
from leap.bitmask.config.providerconfig import ProviderConfig
+from leap.bitmask.crypto.srpregister import SRPRegister
+from leap.bitmask.provider import get_provider_path
from leap.bitmask.provider.providerbootstrapper import ProviderBootstrapper
# Frontend side
@@ -134,6 +136,9 @@ class Provider(object):
:param provider: URL for the provider
:type provider: unicode
+
+ :returns: the defer for the operation running in a thread.
+ :rtype: twisted.internet.defer.Deferred
"""
log.msg("Setting up provider %s..." % (provider.encode("idna"),))
pb = self._provider_bootstrapper
@@ -141,23 +146,31 @@ 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.
:param provider: URL for the provider
:type provider: unicode
- """
+ :returns: the defer for the operation running in a thread.
+ :rtype: twisted.internet.defer.Deferred
+ """
d = None
# If there's no loaded provider or
# we want to connect to other provider...
if (not self._provider_config.loaded() or
self._provider_config.get_domain() != provider):
- self._provider_config.load(
- os.path.join("leap", "providers",
- provider, "provider.json"))
+ self._provider_config.load(get_provider_path(provider))
if self._provider_config.loaded():
d = self._provider_bootstrapper.run_provider_setup_checks(
@@ -174,6 +187,57 @@ class Provider(object):
return d
+class Register(object):
+ """
+ Interfaces with setup and bootstrapping operations for a provider
+ """
+
+ zope.interface.implements(ILEAPComponent)
+
+ def __init__(self, signaler=None):
+ """
+ Constructor for the Register component
+
+ :param signaler: Object in charge of handling communication
+ back to the frontend
+ :type signaler: Signaler
+ """
+ object.__init__(self)
+ self.key = "register"
+ self._signaler = signaler
+ self._provider_config = ProviderConfig()
+
+ def register_user(self, domain, username, password):
+ """
+ Register a user using the domain and password given as parameters.
+
+ :param domain: the domain we need to register the user.
+ :type domain: unicode
+ :param username: the user name
+ :type username: unicode
+ :param password: the password for the username
+ :type password: unicode
+
+ :returns: the defer for the operation running in a thread.
+ :rtype: twisted.internet.defer.Deferred
+ """
+ # If there's no loaded provider or
+ # we want to connect to other provider...
+ if (not self._provider_config.loaded() or
+ self._provider_config.get_domain() != domain):
+ self._provider_config.load(get_provider_path(domain))
+
+ if self._provider_config.loaded():
+ srpregister = SRPRegister(signaler=self._signaler,
+ provider_config=self._provider_config)
+ return threads.deferToThread(
+ partial(srpregister.register_user, username, password))
+ else:
+ if self._signaler is not None:
+ self._signaler.signal(self._signaler.srp_registration_failed)
+ logger.error("Could not load provider configuration.")
+
+
class Signaler(QtCore.QObject):
"""
Signaler object, handles converting string commands to Qt signals.
@@ -182,8 +246,9 @@ class Signaler(QtCore.QObject):
live in the frontend.
"""
- # Signals for the ProviderBootstrapper
+ ####################
# These will only exist in the frontend
+ # Signals for the ProviderBootstrapper
prov_name_resolution = QtCore.Signal(object)
prov_https_connection = QtCore.Signal(object)
prov_download_provider_info = QtCore.Signal(object)
@@ -194,7 +259,18 @@ class Signaler(QtCore.QObject):
prov_problem_with_provider = QtCore.Signal(object)
- # These will exist both in the backend and the front end.
+ prov_unsupported_client = QtCore.Signal(object)
+ prov_unsupported_api = QtCore.Signal(object)
+
+ prov_cancelled_setup = QtCore.Signal(object)
+
+ # Signals for SRPRegister
+ srp_registration_finished = QtCore.Signal(object)
+ srp_registration_failed = QtCore.Signal(object)
+ srp_registration_taken = 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
# it's going to emit defined here
@@ -204,7 +280,14 @@ class Signaler(QtCore.QObject):
PROV_DOWNLOAD_CA_CERT_KEY = "prov_download_ca_cert"
PROV_CHECK_CA_FINGERPRINT_KEY = "prov_check_ca_fingerprint"
PROV_CHECK_API_CERTIFICATE_KEY = "prov_check_api_certificate"
- PROV_PROV_PROBLEM_WITH_PROVIER_KEY = "prov_problem_with_provider"
+ 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"
+
+ SRP_REGISTRATION_FINISHED = "srp_registration_finished"
+ SRP_REGISTRATION_FAILED = "srp_registration_failed"
+ SRP_REGISTRATION_TAKEN = "srp_registration_taken"
def __init__(self):
"""
@@ -220,7 +303,14 @@ class Signaler(QtCore.QObject):
self.PROV_DOWNLOAD_CA_CERT_KEY,
self.PROV_CHECK_CA_FINGERPRINT_KEY,
self.PROV_CHECK_API_CERTIFICATE_KEY,
- self.PROV_PROV_PROBLEM_WITH_PROVIER_KEY
+ self.PROV_PROBLEM_WITH_PROVIDER_KEY,
+ self.PROV_UNSUPPORTED_CLIENT,
+ self.PROV_UNSUPPORTED_API,
+ self.PROV_CANCELLED_SETUP,
+
+ self.SRP_REGISTRATION_FINISHED,
+ self.SRP_REGISTRATION_FAILED,
+ self.SRP_REGISTRATION_TAKEN,
]
for sig in signals:
@@ -243,6 +333,11 @@ class Signaler(QtCore.QObject):
# will do zmq.send_multipart, and the frontend version will be
# similar to this
log.msg("Signaling %s :: %s" % (key, data))
+
+ # for some reason emitting 'None' gives a segmentation fault.
+ if data is None:
+ data = ''
+
try:
self._signals[key].emit(data)
except KeyError:
@@ -274,6 +369,7 @@ class Backend(object):
# Component registration
self._register(Provider(self._signaler, bypass_checks))
+ self._register(Register(self._signaler))
# We have a looping call on a thread executing all the
# commands in queue. Right now this queue is an actual Queue
@@ -303,7 +399,8 @@ class Backend(object):
Stops the looping call and tries to cancel all the defers.
"""
log.msg("Stopping worker...")
- self._lc.stop()
+ if self._lc.running:
+ self._lc.stop()
while len(self._ongoing_defers) > 0:
d = self._ongoing_defers.pop()
d.cancel()
@@ -345,17 +442,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()
@@ -367,7 +467,8 @@ class Backend(object):
:param d: defer to remove
:type d: twisted.internet.defer.Deferred
"""
- self._ongoing_defers.remove(d)
+ if d in self._ongoing_defers:
+ self._ongoing_defers.remove(d)
# XXX: Temporal interface until we migrate to zmq
# We simulate the calls to zmq.send_multipart. Once we separate
@@ -377,5 +478,12 @@ 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))
+
+ def register_user(self, provider, username, password):
+ self._call_queue.put(("register", "register_user", None, provider,
+ username, password))