diff options
| -rw-r--r-- | src/leap/bitmask/backend.py | 137 | ||||
| -rw-r--r-- | src/leap/bitmask/gui/mainwindow.py | 8 | ||||
| -rw-r--r-- | src/leap/bitmask/services/mail/conductor.py | 56 | ||||
| -rw-r--r-- | src/leap/bitmask/services/mail/imapcontroller.py | 5 | ||||
| -rw-r--r-- | src/leap/bitmask/services/mail/smtpbootstrapper.py | 24 | ||||
| -rw-r--r-- | src/leap/bitmask/services/soledad/soledadbootstrapper.py | 2 | 
6 files changed, 163 insertions, 69 deletions
| diff --git a/src/leap/bitmask/backend.py b/src/leap/bitmask/backend.py index fd09929a..6a6b1065 100644 --- a/src/leap/bitmask/backend.py +++ b/src/leap/bitmask/backend.py @@ -46,7 +46,10 @@ from leap.bitmask.services.eip.eipbootstrapper import EIPBootstrapper  from leap.bitmask.services.eip import vpnlauncher, vpnprocess  from leap.bitmask.services.eip import linuxvpnlauncher, darwinvpnlauncher -from leap.bitmask.services.mail import imap + +from leap.bitmask.services.mail.imapcontroller import IMAPController +from leap.bitmask.services.mail.smtpbootstrapper import SMTPBootstrapper +from leap.bitmask.services.mail.smtpconfig import SMTPConfig  from leap.bitmask.services.soledad.soledadbootstrapper import \      SoledadBootstrapper @@ -557,15 +560,21 @@ class Soledad(object):      """      zope.interface.implements(ILEAPComponent) -    def __init__(self, signaler=None): +    def __init__(self, soledad_proxy, keymanager_proxy, signaler=None):          """          Constructor for the Soledad component. +        :param soledad_proxy: proxy to pass around a Soledad object. +        :type soledad_proxy: zope.ProxyBase +        :param keymanager_proxy: proxy to pass around a Keymanager object. +        :type keymanager_proxy: zope.ProxyBase          :param signaler: Object in charge of handling communication                           back to the frontend          :type signaler: Signaler          """          self.key = "soledad" +        self._soledad_proxy = soledad_proxy +        self._keymanager_proxy = keymanager_proxy          self._signaler = signaler          self._soledad_bootstrapper = SoledadBootstrapper(signaler)          self._soledad_defer = None @@ -591,6 +600,7 @@ class Soledad(object):                  self._soledad_bootstrapper.run_soledad_setup_checks,                  provider_config, username, password,                  download_if_needed=True) +            self._soledad_defer.addCallback(self._set_proxies_cb)          else:              if self._signaler is not None:                  self._signaler.signal(self._signaler.SOLEDAD_BOOTSTRAP_FAILED) @@ -598,6 +608,16 @@ class Soledad(object):          return self._soledad_defer +    def _set_proxies_cb(self, _): +        """ +        Update the soledad and keymanager proxies to reference the ones created +        in the bootstrapper. +        """ +        zope.proxy.setProxiedObject(self._soledad_proxy, +                                    self._soledad_bootstrapper.soledad) +        zope.proxy.setProxiedObject(self._keymanager_proxy, +                                    self._soledad_bootstrapper.keymanager) +      def load_offline(self, username, password, uuid):          """          Load the soledad database in offline mode. @@ -641,28 +661,70 @@ class Mail(object):      zope.interface.implements(ILEAPComponent) -    def __init__(self, signaler=None): +    def __init__(self, soledad_proxy, keymanager_proxy, signaler=None):          """          Constructor for the Mail component. +        :param soledad_proxy: proxy to pass around a Soledad object. +        :type soledad_proxy: zope.ProxyBase +        :param keymanager_proxy: proxy to pass around a Keymanager object. +        :type keymanager_proxy: zope.ProxyBase          :param signaler: Object in charge of handling communication                           back to the frontend          :type signaler: Signaler          """          self.key = "mail"          self._signaler = signaler +        self._soledad_proxy = soledad_proxy +        self._keymanager_proxy = keymanager_proxy +        self._imap_controller = IMAPController(self._soledad_proxy, +                                               self._keymanager_proxy) +        self._smtp_bootstrapper = SMTPBootstrapper() +        self._smtp_config = SMTPConfig() -    def start_smtp_service(self): -        pass +    def start_smtp_service(self, full_user_id, download_if_needed=False): +        """ +        Start the SMTP service. -    def start_imap_service(self, offline=False): -        pass +        :param full_user_id: user id, in the form "user@provider" +        :type full_user_id: str +        :param download_if_needed: True if it should check for mtime +                                   for the file +        :type download_if_needed: bool +        """ +        return threads.deferToThread( +            self._smtp_bootstrapper.start_smtp_service, +            self._keymanager_proxy, full_user_id, download_if_needed) + +    def start_imap_service(self, full_user_id, offline=False): +        """ +        Start the IMAP service. + +        :param full_user_id: user id, in the form "user@provider" +        :type full_user_id: str +        :param offline: whether imap should start in offline mode or not. +        :type offline: bool +        """ +        return threads.deferToThread( +            self._imap_controller.start_imap_service, +            full_user_id, offline)      def stop_smtp_service(self): -        pass +        """ +        Stop the SMTP service. +        """ +        return threads.deferToThread(self._smtp_bootstrapper.stop_smtp_service) -    def stop_imap_service(self): -        pass +    def stop_imap_service(self, cv): +        """ +        Stop imap service (fetcher, factory and port). + +        :param cv: A condition variable to which we can signal when imap +                   indeed stops. +        :type cv: threading.Condition +        """ +        return threads.deferToThread( +            self._imap_controller.stop_imap_service, cv)  class Authenticate(object): @@ -1075,12 +1137,22 @@ class Backend(object):          # Signaler object to translate commands into Qt signals          self._signaler = Signaler() +        # Objects needed by several components, so we make a proxy and pass +        # them around +        self._soledad_proxy = zope.proxy.ProxyBase(None) +        self._keymanager_proxy = zope.proxy.ProxyBase(None) +          # Component registration          self._register(Provider(self._signaler, bypass_checks))          self._register(Register(self._signaler))          self._register(Authenticate(self._signaler))          self._register(EIP(self._signaler)) -        self._register(Soledad(self._signaler)) +        self._register(Soledad(self._soledad_proxy, +                               self._keymanager_proxy, +                               self._signaler)) +        self._register(Mail(self._soledad_proxy, +                            self._keymanager_proxy, +                            self._signaler))          # We have a looping call on a thread executing all the          # commands in queue. Right now this queue is an actual Queue @@ -1473,11 +1545,54 @@ class Backend(object):          """          self._call_queue.put(("soledad", "close", None)) +    def start_smtp_service(self, full_user_id, download_if_needed=False): +        """ +        Start the SMTP service. + +        :param full_user_id: user id, in the form "user@provider" +        :type full_user_id: str +        :param download_if_needed: True if it should check for mtime +                                   for the file +        :type download_if_needed: bool +        """ +        self._call_queue.put(("mail", "start_smtp_service", None, +                              full_user_id, download_if_needed)) + +    def start_imap_service(self, full_user_id, offline=False): +        """ +        Start the IMAP service. + +        :param full_user_id: user id, in the form "user@provider" +        :type full_user_id: str +        :param offline: whether imap should start in offline mode or not. +        :type offline: bool +        """ +        self._call_queue.put(("mail", "start_imap_service", None, +                              full_user_id, offline)) + +    def stop_smtp_service(self): +        """ +        Stop the SMTP service. +        """ +        self._call_queue.put(("mail", "stop_smtp_service", None)) + +    def stop_imap_service(self, cv): +        """ +        Stop imap service. + +        :param cv: A condition variable to which we can signal when imap +                   indeed stops. +        :type cv: threading.Condition +        """ +        self._call_queue.put(("mail", "stop_imap_service", None, cv)) +      ###########################################################################      # XXX HACK: this section is meant to be a place to hold methods and      # variables needed in the meantime while we migrate all to the backend.      def get_provider_config(self): +        # TODO: refactor the provider config into a singleton/global loading it +        # every time from the file.          provider_config = self._components["provider"]._provider_config          return provider_config diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index bf76f574..370a9d43 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -282,8 +282,9 @@ class MainWindow(QtGui.QMainWindow):          self._soledad = ProxyBase(None)          self._keymanager = ProxyBase(None) -        self._mail_conductor = mail_conductor.MailConductor( -            self._soledad, self._keymanager) +        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 @@ -1423,8 +1424,7 @@ class MainWindow(QtGui.QMainWindow):              return          if self._provides_mx_and_enabled(): -            self._mail_conductor.start_smtp_service(self._provider_config, -                                                    download_if_needed=True) +            self._mail_conductor.start_smtp_service(download_if_needed=True)      # XXX --- should remove from here, and connecte directly to the state      # machine. diff --git a/src/leap/bitmask/services/mail/conductor.py b/src/leap/bitmask/services/mail/conductor.py index aa22afe4..67bc007e 100644 --- a/src/leap/bitmask/services/mail/conductor.py +++ b/src/leap/bitmask/services/mail/conductor.py @@ -19,14 +19,9 @@ Mail Services Conductor  """  import logging -from twisted.internet import threads -  from leap.bitmask.config import flags  from leap.bitmask.gui import statemachines  from leap.bitmask.services.mail import connection as mail_connection -from leap.bitmask.services.mail.smtpbootstrapper import SMTPBootstrapper -from leap.bitmask.services.mail.smtpconfig import SMTPConfig -from leap.bitmask.services.mail.imapcontroller import IMAPController  from leap.common.events import events_pb2 as leap_events  from leap.common.events import register as leap_register @@ -39,20 +34,12 @@ class IMAPControl(object):      """      Methods related to IMAP control.      """ -    def __init__(self, soledad, keymanager): +    def __init__(self):          """          Initializes smtp variables. - -        :param soledad: a transparent proxy that eventually will point to a -                        Soledad Instance. -        :type soledad: zope.proxy.ProxyBase -        :param keymanager: a transparent proxy that eventually will point to a -                           Keymanager Instance. -        :type keymanager: zope.proxy.ProxyBase          """          self.imap_machine = None          self.imap_connection = None -        self._imap_controller = IMAPController(soledad, keymanager)          leap_register(signal=leap_events.IMAP_SERVICE_STARTED,                        callback=self._handle_imap_events, @@ -77,12 +64,11 @@ class IMAPControl(object):          """          Start imap service.          """ -        threads.deferToThread(self._imap_controller.start_imap_service, -                              self.userid, flags.OFFLINE) +        self._backend.start_imap_service(self.userid, flags.OFFLINE)      def stop_imap_service(self, cv):          """ -        Stop imap service (fetcher, factory and port). +        Stop imap service.          :param cv: A condition variable to which we can signal when imap                     indeed stops. @@ -91,7 +77,7 @@ class IMAPControl(object):          self.imap_connection.qtsigs.disconnecting_signal.emit()          logger.debug('Stopping imap service.') -        self._imap_controller.stop_imap_service(cv) +        self._backend.stop_imap_service(cv)      def _handle_imap_events(self, req):          """ @@ -137,12 +123,9 @@ class SMTPControl(object):          """          Initializes smtp variables.          """ -        self.smtp_config = SMTPConfig()          self.smtp_connection = None          self.smtp_machine = None -        self.smtp_bootstrapper = SMTPBootstrapper() -          leap_register(signal=leap_events.SMTP_SERVICE_STARTED,                        callback=self._handle_smtp_events,                        reqcbk=lambda req, resp: None) @@ -158,30 +141,23 @@ class SMTPControl(object):          """          self.smtp_connection = smtp_connection -    def start_smtp_service(self, provider_config, download_if_needed=False): +    def start_smtp_service(self, download_if_needed=False):          """          Starts the SMTP service. -        :param provider_config: Provider configuration -        :type provider_config: ProviderConfig          :param download_if_needed: True if it should check for mtime                                     for the file          :type download_if_needed: bool          """          self.smtp_connection.qtsigs.connecting_signal.emit() -        threads.deferToThread( -            self.smtp_bootstrapper.start_smtp_service, -            provider_config, self.smtp_config, self._keymanager, -            self.userid, download_if_needed) +        self._backend.start_smtp_service(self.userid, download_if_needed)      def stop_smtp_service(self):          """          Stops the SMTP service.          """          self.smtp_connection.qtsigs.disconnecting_signal.emit() -        self.smtp_bootstrapper.stop_smtp_service() - -    # handle smtp events +        self._backend.stop_smtp_service()      def _handle_smtp_events(self, req):          """ @@ -195,8 +171,6 @@ class SMTPControl(object):          elif req.event == leap_events.SMTP_SERVICE_FAILED_TO_START:              self.on_smtp_failed() -    # emit connection signals -      def on_smtp_connecting(self):          """          Callback for SMTP connecting state. @@ -224,21 +198,17 @@ class MailConductor(IMAPControl, SMTPControl):      """      # XXX We could consider to use composition instead of inheritance here. -    def __init__(self, soledad, keymanager): +    def __init__(self, backend):          """          Initializes the mail conductor. -        :param soledad: a transparent proxy that eventually will point to a -                        Soledad Instance. -        :type soledad: zope.proxy.ProxyBase -        :param keymanager: a transparent proxy that eventually will point to a -                           Keymanager Instance. -        :type keymanager: zope.proxy.ProxyBase +        :param backend: Backend being used +        :type backend: Backend          """ -        IMAPControl.__init__(self, soledad, keymanager) +        IMAPControl.__init__(self)          SMTPControl.__init__(self) -        self._soledad = soledad -        self._keymanager = keymanager + +        self._backend = backend          self._mail_machine = None          self._mail_connection = mail_connection.MailConnection() diff --git a/src/leap/bitmask/services/mail/imapcontroller.py b/src/leap/bitmask/services/mail/imapcontroller.py index efca5867..d0bf4c34 100644 --- a/src/leap/bitmask/services/mail/imapcontroller.py +++ b/src/leap/bitmask/services/mail/imapcontroller.py @@ -50,6 +50,11 @@ class IMAPController(object):      def start_imap_service(self, userid, offline=False):          """          Start IMAP service. + +        :param userid: user id, in the form "user@provider" +        :type userid: str +        :param offline: whether imap should start in offline mode or not. +        :type offline: bool          """          logger.debug('Starting imap service') diff --git a/src/leap/bitmask/services/mail/smtpbootstrapper.py b/src/leap/bitmask/services/mail/smtpbootstrapper.py index 7ecf8134..785fe404 100644 --- a/src/leap/bitmask/services/mail/smtpbootstrapper.py +++ b/src/leap/bitmask/services/mail/smtpbootstrapper.py @@ -28,7 +28,7 @@ from leap.bitmask.services.mail.smtpconfig import SMTPConfig  from leap.bitmask.util import is_file  from leap.common import certs as leap_certs -from leap.common.check import leap_assert, leap_assert_type +from leap.common.check import leap_assert  from leap.common.files import check_and_fix_urw_only  logger = logging.getLogger(__name__) @@ -38,6 +38,10 @@ class NoSMTPHosts(Exception):      """This is raised when there is no SMTP host to use.""" +class MalformedUserId(Exception): +    """This is raised when an userid does not have the form user@provider.""" + +  class SMTPBootstrapper(AbstractBootstrapper):      """      SMTP init procedure @@ -126,15 +130,10 @@ class SMTPBootstrapper(AbstractBootstrapper):              smtp_key=client_cert_path,              encrypted_only=False) -    def start_smtp_service(self, provider_config, smtp_config, keymanager, -                           userid, download_if_needed=False): +    def start_smtp_service(self, keymanager, userid, download_if_needed=False):          """          Starts the SMTP service. -        :param provider_config: Provider configuration -        :type provider_config: ProviderConfig -        :param smtp_config: SMTP configuration to populate -        :type smtp_config: SMTPConfig          :param keymanager: a transparent proxy that eventually will point to a                             Keymanager Instance.          :type keymanager: zope.proxy.ProxyBase @@ -144,12 +143,15 @@ class SMTPBootstrapper(AbstractBootstrapper):                                     for the file          :type download_if_needed: bool          """ -        leap_assert_type(provider_config, ProviderConfig) -        leap_assert_type(smtp_config, SMTPConfig) +        try: +            username, domain = userid.split('@') +        except ValueError: +            logger.critical("Malformed userid parameter!") +            raise MalformedUserId() -        self._provider_config = provider_config +        self._provider_config = ProviderConfig.get_provider_config(domain)          self._keymanager = keymanager -        self._smtp_config = smtp_config +        self._smtp_config = SMTPConfig()          self._useid = userid          self._download_if_needed = download_if_needed diff --git a/src/leap/bitmask/services/soledad/soledadbootstrapper.py b/src/leap/bitmask/services/soledad/soledadbootstrapper.py index c015f5b7..2bdad7e2 100644 --- a/src/leap/bitmask/services/soledad/soledadbootstrapper.py +++ b/src/leap/bitmask/services/soledad/soledadbootstrapper.py @@ -651,5 +651,7 @@ class SoledadBootstrapper(AbstractBootstrapper):              self._signaler.signal(signal_finished)          except Exception as e:              # TODO: we should handle more specific exceptions in here +            self._soledad = None +            self._keymanager = None              logger.exception("Error while bootstrapping Soledad: %r" % (e, ))              self._signaler.signal(signal_failed) | 
