예제 #1
0
    def _route_msg(self, encrypt_and_sign_result):
        """
        Sends the msg using the ESMTPSenderFactory.

        :param encrypt_and_sign_result: A tuple containing the 'maybe'
                                        encrypted message and the recipient
        :type encrypt_and_sign_result: tuple
        """
        message, recipient = encrypt_and_sign_result
        log.msg("Connecting to SMTP server %s:%s" % (self._host, self._port))
        msg = message.as_string(False)

        # we construct a defer to pass to the ESMTPSenderFactory
        d = defer.Deferred()
        d.addCallbacks(self.sendSuccess, self.sendError)
        # we don't pass an ssl context factory to the ESMTPSenderFactory
        # because ssl will be handled by reactor.connectSSL() below.
        factory = smtp.ESMTPSenderFactory(
            "",  # username is blank, no client auth here
            "",  # password is blank, no client auth here
            self._from_address,
            recipient.dest.addrstr,
            StringIO(msg),
            d,
            heloFallback=True,
            requireAuthentication=False,
            requireTransportSecurity=True)
        factory.domain = __version__
        emit(catalog.SMTP_SEND_MESSAGE_START, recipient.dest.addrstr)
        reactor.connectSSL(self._host,
                           self._port,
                           factory,
                           contextFactory=SSLContextFactory(
                               self._cert, self._key))
예제 #2
0
    def _extract_data(self, json_content):
        """
        Extracts the necessary parameters from json_content (M2,
        id, token)

        Might raise SRPAuthenticationError based:
          SRPBadDataFromServer

        :param json_content: Data received from the server
        :type json_content: dict
        """
        try:
            M2 = json_content.get("M2", None)
            uuid = json_content.get("id", None)
            token = json_content.get("token", None)
        except Exception as e:
            logger.error(e)
            raise SRPAuthBadDataFromServer()

        self.set_uuid(uuid)
        self.set_token(token)

        if M2 is None or self.get_uuid() is None:
            logger.error("Something went wrong. Content = %r" %
                         (json_content, ))
            raise SRPAuthBadDataFromServer()

        emit(catalog.CLIENT_UID, uuid)  # make the rpc call async

        return M2
예제 #3
0
    def _route_msg(self, encrypt_and_sign_result):
        """
        Sends the msg using the ESMTPSenderFactory.

        :param encrypt_and_sign_result: A tuple containing the 'maybe'
                                        encrypted message and the recipient
        :type encrypt_and_sign_result: tuple
        """
        message, recipient = encrypt_and_sign_result
        log.msg("Connecting to SMTP server %s:%s" % (self._host, self._port))
        msg = message.as_string(False)

        # we construct a defer to pass to the ESMTPSenderFactory
        d = defer.Deferred()
        d.addCallbacks(self.sendSuccess, self.sendError)
        # we don't pass an ssl context factory to the ESMTPSenderFactory
        # because ssl will be handled by reactor.connectSSL() below.
        factory = smtp.ESMTPSenderFactory(
            "",  # username is blank, no client auth here
            "",  # password is blank, no client auth here
            self._from_address,
            recipient.dest.addrstr,
            StringIO(msg),
            d,
            heloFallback=True,
            requireAuthentication=False,
            requireTransportSecurity=True)
        factory.domain = __version__
        emit(catalog.SMTP_SEND_MESSAGE_START, recipient.dest.addrstr)
        reactor.connectSSL(
            self._host, self._port, factory,
            contextFactory=SSLContextFactory(self._cert, self._key))
예제 #4
0
    def _extract_data(self, json_content):
        """
        Extracts the necessary parameters from json_content (M2,
        id, token)

        Might raise SRPAuthenticationError based:
          SRPBadDataFromServer

        :param json_content: Data received from the server
        :type json_content: dict
        """
        try:
            M2 = json_content.get("M2", None)
            uuid = json_content.get("id", None)
            token = json_content.get("token", None)
        except Exception as e:
            logger.error(e)
            raise SRPAuthBadDataFromServer()

        self.set_uuid(uuid)
        self.set_token(token)

        if M2 is None or self.get_uuid() is None:
            logger.error("Something went wrong. Content = %r" %
                         (json_content,))
            raise SRPAuthBadDataFromServer()

        emit(catalog.CLIENT_UID, uuid)  # make the rpc call async

        return M2
예제 #5
0
 def __cb_signal_unread_to_ui(self, unseen):
     """
     Send the unread signal to UI.
     :param unseen: number of unseen messages.
     :type unseen: int
     """
     # TODO change name of the signal, independent from imap now.
     emit(catalog.MAIL_UNREAD_MESSAGES, str(unseen))
예제 #6
0
        def if_key_not_found_send_unencrypted(failure, message):
            failure.trap(KeyNotFound, KeyAddressMismatch)

            log.msg('Will send unencrypted message to %s.' % to_address)
            emit(catalog.SMTP_START_SIGN, self._from_address)
            d = self._sign(message, from_address)
            d.addCallback(signal_sign)
            return d
예제 #7
0
        def if_key_not_found_send_unencrypted(failure, message):
            failure.trap(KeyNotFound, KeyAddressMismatch)

            log.msg('Will send unencrypted message to %s.' % to_address)
            emit(catalog.SMTP_START_SIGN, self._from_address)
            d = self._sign(message, from_address)
            d.addCallback(signal_sign)
            return d
예제 #8
0
    def get_key(self, address, ktype, private=False, fetch_remote=True):
        """
        Return a key of type ktype bound to address.

        First, search for the key in local storage. If it is not available,
        then try to fetch from nickserver.

        :param address: The address bound to the key.
        :type address: str
        :param ktype: The type of the key.
        :type ktype: subclass of EncryptionKey
        :param private: Look for a private key instead of a public one?
        :type private: bool
        :param fetch_remote: If key not found in local storage try to fetch
                             from nickserver
        :type fetch_remote: bool

        :return: A Deferred which fires with an EncryptionKey of type ktype
                 bound to address, or which fails with KeyNotFound if no key
                 was found neither locally or in keyserver.
        :rtype: Deferred

        :raise UnsupportedKeyTypeError: if invalid key type
        """
        self._assert_supported_key_type(ktype)
        logger.debug("getting key for %s" % (address,))
        leap_assert(
            ktype in self._wrapper_map,
            'Unkown key type: %s.' % str(ktype))
        emit(catalog.KEYMANAGER_LOOKING_FOR_KEY, address)

        def key_found(key):
            emit(catalog.KEYMANAGER_KEY_FOUND, address)
            return key

        def key_not_found(failure):
            if not failure.check(KeyNotFound):
                return failure

            emit(catalog.KEYMANAGER_KEY_NOT_FOUND, address)

            # we will only try to fetch a key from nickserver if fetch_remote
            # is True and the key is not private.
            if fetch_remote is False or private is True:
                return failure

            emit(catalog.KEYMANAGER_LOOKING_FOR_KEY, address)
            d = self._fetch_keys_from_server(address)
            d.addCallback(
                lambda _:
                self._wrapper_map[ktype].get_key(address, private=False))
            d.addCallback(key_found)
            return d

        # return key if it exists in local database
        d = self._wrapper_map[ktype].get_key(address, private=private)
        d.addCallbacks(key_found, key_not_found)
        return d
예제 #9
0
    def get_key(self, address, ktype, private=False, fetch_remote=True):
        """
        Return a key of type ktype bound to address.

        First, search for the key in local storage. If it is not available,
        then try to fetch from nickserver.

        :param address: The address bound to the key.
        :type address: str
        :param ktype: The type of the key.
        :type ktype: subclass of EncryptionKey
        :param private: Look for a private key instead of a public one?
        :type private: bool
        :param fetch_remote: If key not found in local storage try to fetch
                             from nickserver
        :type fetch_remote: bool

        :return: A Deferred which fires with an EncryptionKey of type ktype
                 bound to address, or which fails with KeyNotFound if no key
                 was found neither locally or in keyserver.
        :rtype: Deferred

        :raise UnsupportedKeyTypeError: if invalid key type
        """
        self._assert_supported_key_type(ktype)
        logger.debug("getting key for %s" % (address, ))
        leap_assert(ktype in self._wrapper_map,
                    'Unkown key type: %s.' % str(ktype))
        emit(catalog.KEYMANAGER_LOOKING_FOR_KEY, address)

        def key_found(key):
            emit(catalog.KEYMANAGER_KEY_FOUND, address)
            return key

        def key_not_found(failure):
            if not failure.check(KeyNotFound):
                return failure

            emit(catalog.KEYMANAGER_KEY_NOT_FOUND, address)

            # we will only try to fetch a key from nickserver if fetch_remote
            # is True and the key is not private.
            if fetch_remote is False or private is True:
                return failure

            emit(catalog.KEYMANAGER_LOOKING_FOR_KEY, address)
            d = self._fetch_keys_from_server(address)
            d.addCallback(lambda _: self._wrapper_map[ktype].get_key(
                address, private=False))
            d.addCallback(key_found)
            return d

        # return key if it exists in local database
        d = self._wrapper_map[ktype].get_key(address, private=private)
        d.addCallbacks(key_found, key_not_found)
        return d
예제 #10
0
    def connectionLost(self):
        """
        Log an error when the connection is lost.
        """
        log.msg("Connection lost unexpectedly!")
        log.err()
        emit(catalog.SMTP_CONNECTION_LOST, self._user.dest.addrstr)
        # unexpected loss of connection; don't save

        self._lines = []
예제 #11
0
        def process_decrypted(res):
            if isinstance(res, tuple):
                decrdata, _ = res
                success = True
            else:
                decrdata = ""
                success = False

            emit(catalog.MAIL_MSG_DECRYPTED, "1" if success else "0")
            return self._process_decrypted_doc(doc, decrdata)
예제 #12
0
    def connectionLost(self):
        """
        Log an error when the connection is lost.
        """
        log.msg("Connection lost unexpectedly!")
        log.err()
        emit(catalog.SMTP_CONNECTION_LOST, self._user.dest.addrstr)
        # unexpected loss of connection; don't save

        self._lines = []
예제 #13
0
 def send(pubkey):
     data = {
         self.PUBKEY_KEY: pubkey.key_data
     }
     uri = "%s/%s/users/%s.json" % (
         self._api_uri,
         self._api_version,
         self._uid)
     self._put(uri, data)
     emit(catalog.KEYMANAGER_DONE_UPLOADING_KEYS, self._address)
예제 #14
0
    def sendSuccess(self, smtp_sender_result):
        """
        Callback for a successful send.

        :param smtp_sender_result: The result from the ESMTPSender from
                                   _route_msg
        :type smtp_sender_result: tuple(int, list(tuple))
        """
        dest_addrstr = smtp_sender_result[1][0][0]
        log.msg('Message sent to %s' % dest_addrstr)
        emit(catalog.SMTP_SEND_MESSAGE_SUCCESS, dest_addrstr)
예제 #15
0
        def not_found(failure):
            failure.trap(KeyNotFound)

            # if key was not found, check config to see if will send anyway
            if self._encrypted_only:
                emit(catalog.SMTP_RECIPIENT_REJECTED, user.dest.addrstr)
                raise smtp.SMTPBadRcpt(user.dest.addrstr)
            log.msg("Warning: will send an unencrypted message (because "
                    "encrypted_only' is set to False).")
            emit(catalog.SMTP_RECIPIENT_ACCEPTED_UNENCRYPTED,
                 user.dest.addrstr)
예제 #16
0
    def sendSuccess(self, smtp_sender_result):
        """
        Callback for a successful send.

        :param smtp_sender_result: The result from the ESMTPSender from
                                   _route_msg
        :type smtp_sender_result: tuple(int, list(tuple))
        """
        dest_addrstr = smtp_sender_result[1][0][0]
        log.msg('Message sent to %s' % dest_addrstr)
        emit(catalog.SMTP_SEND_MESSAGE_SUCCESS, dest_addrstr)
예제 #17
0
        def not_found(failure):
            failure.trap(KeyNotFound)

            # if key was not found, check config to see if will send anyway
            if self._encrypted_only:
                emit(catalog.SMTP_RECIPIENT_REJECTED, user.dest.addrstr)
                raise smtp.SMTPBadRcpt(user.dest.addrstr)
            log.msg("Warning: will send an unencrypted message (because "
                    "encrypted_only' is set to False).")
            emit(
                catalog.SMTP_RECIPIENT_ACCEPTED_UNENCRYPTED,
                user.dest.addrstr)
예제 #18
0
def run_service(store, **kwargs):
    """
    Main entry point to run the service from the client.

    :param store: a soledad instance

    :returns: the port as returned by the reactor when starts listening, and
              the factory for the protocol.
    """
    leap_check(store, "store cannot be None")
    # XXX this can also be a ProxiedObject, FIXME
    # leap_assert_type(store, Soledad)

    port = kwargs.get('port', IMAP_PORT)
    userid = kwargs.get('userid', None)
    leap_check(userid is not None, "need an user id")

    uuid = store.uuid
    factory = LeapIMAPFactory(uuid, userid, store)

    try:
        tport = reactor.listenTCP(port, factory, interface="localhost")
    except CannotListenError:
        logger.error("IMAP Service failed to start: "
                     "cannot listen in port %s" % (port, ))
    except Exception as exc:
        logger.error("Error launching IMAP service: %r" % (exc, ))
    else:
        # all good.

        if DO_MANHOLE:
            # TODO get pass from env var.too.
            manhole_factory = manhole.getManholeFactory(
                {
                    'f': factory,
                    'a': factory.theAccount,
                    'gm': factory.theAccount.getMailbox
                }, "boss", "leap")
            reactor.listenTCP(manhole.MANHOLE_PORT,
                              manhole_factory,
                              interface="127.0.0.1")
        logger.debug("IMAP4 Server is RUNNING in port  %s" % (port, ))
        emit(catalog.IMAP_SERVICE_STARTED, str(port))

        # FIXME -- change service signature
        return tport, factory

    # not ok, signal error.
    emit(catalog.IMAP_SERVICE_FAILED_TO_START, str(port))
예제 #19
0
        def msgSavedCallback(result):
            if empty(result):
                return

            for listener in self._listeners:
                listener(result)

            def signal_deleted(doc_id):
                emit(catalog.MAIL_MSG_DELETED_INCOMING)
                return doc_id

            emit(catalog.MAIL_MSG_SAVED_LOCALLY)
            d = self._delete_incoming_message(doc)
            d.addCallback(signal_deleted)
            return d
예제 #20
0
파일: imap.py 프로젝트: Meistache/leap_mail
def run_service(store, **kwargs):
    """
    Main entry point to run the service from the client.

    :param store: a soledad instance

    :returns: the port as returned by the reactor when starts listening, and
              the factory for the protocol.
    """
    leap_check(store, "store cannot be None")
    # XXX this can also be a ProxiedObject, FIXME
    # leap_assert_type(store, Soledad)

    port = kwargs.get('port', IMAP_PORT)
    userid = kwargs.get('userid', None)
    leap_check(userid is not None, "need an user id")

    uuid = store.uuid
    factory = LeapIMAPFactory(uuid, userid, store)

    try:
        tport = reactor.listenTCP(port, factory,
                                  interface="localhost")
    except CannotListenError:
        logger.error("IMAP Service failed to start: "
                     "cannot listen in port %s" % (port,))
    except Exception as exc:
        logger.error("Error launching IMAP service: %r" % (exc,))
    else:
        # all good.

        if DO_MANHOLE:
            # TODO get pass from env var.too.
            manhole_factory = manhole.getManholeFactory(
                {'f': factory,
                 'a': factory.theAccount,
                 'gm': factory.theAccount.getMailbox},
                "boss", "leap")
            reactor.listenTCP(manhole.MANHOLE_PORT, manhole_factory,
                              interface="127.0.0.1")
        logger.debug("IMAP4 Server is RUNNING in port  %s" % (port,))
        emit(catalog.IMAP_SERVICE_STARTED, str(port))

        # FIXME -- change service signature
        return tport, factory

    # not ok, signal error.
    emit(catalog.IMAP_SERVICE_FAILED_TO_START, str(port))
예제 #21
0
    def _signal_fetch_to_ui(self, doclist):
        """
        Send leap events to ui.

        :param doclist: iterable with msg documents.
        :type doclist: iterable.
        :returns: doclist
        :rtype: iterable
        """
        if doclist:
            fetched_ts = time.mktime(time.gmtime())
            num_mails = len(doclist) if doclist is not None else 0
            if num_mails != 0:
                log.msg("there are %s mails" % (num_mails,))
            emit(catalog.MAIL_FETCHED_INCOMING,
                 str(num_mails), str(fetched_ts))
            return doclist
예제 #22
0
        def key_not_found(failure):
            if not failure.check(KeyNotFound):
                return failure

            emit(catalog.KEYMANAGER_KEY_NOT_FOUND, address)

            # we will only try to fetch a key from nickserver if fetch_remote
            # is True and the key is not private.
            if fetch_remote is False or private is True:
                return failure

            emit(catalog.KEYMANAGER_LOOKING_FOR_KEY, address)
            d = self._fetch_keys_from_server(address)
            d.addCallback(lambda _: self._wrapper_map[ktype].get_key(
                address, private=False))
            d.addCallback(key_found)
            return d
예제 #23
0
        def key_not_found(failure):
            if not failure.check(KeyNotFound):
                return failure

            emit(catalog.KEYMANAGER_KEY_NOT_FOUND, address)

            # we will only try to fetch a key from nickserver if fetch_remote
            # is True and the key is not private.
            if fetch_remote is False or private is True:
                return failure

            emit(catalog.KEYMANAGER_LOOKING_FOR_KEY, address)
            d = self._fetch_keys_from_server(address)
            d.addCallback(
                lambda _:
                self._wrapper_map[ktype].get_key(address, private=False))
            d.addCallback(key_found)
            return d
예제 #24
0
def setup_smtp_gateway(port, userid, keymanager, smtp_host, smtp_port,
                       smtp_cert, smtp_key, encrypted_only):
    """
    Setup SMTP gateway to run with Twisted.

    This function sets up the SMTP gateway configuration and the Twisted
    reactor.

    :param port: The port in which to run the server.
    :type port: int
    :param userid: The user currently logged in
    :type userid: str
    :param keymanager: A Key Manager from where to get recipients' public
                       keys.
    :type keymanager: leap.common.keymanager.KeyManager
    :param smtp_host: The hostname of the remote SMTP server.
    :type smtp_host: str
    :param smtp_port: The port of the remote SMTP server.
    :type smtp_port: int
    :param smtp_cert: The client certificate for authentication.
    :type smtp_cert: str
    :param smtp_key: The client key for authentication.
    :type smtp_key: str
    :param encrypted_only: Whether the SMTP gateway should send unencrypted
                           mail or not.
    :type encrypted_only: bool

    :returns: tuple of SMTPFactory, twisted.internet.tcp.Port
    """
    # configure the use of this service with twistd
    outgoing_mail = OutgoingMail(userid, keymanager, smtp_cert, smtp_key,
                                 smtp_host, smtp_port)
    factory = SMTPFactory(userid, keymanager, encrypted_only, outgoing_mail)
    try:
        tport = reactor.listenTCP(port, factory, interface="localhost")
        emit(catalog.SMTP_SERVICE_STARTED, str(port))
        return factory, tport
    except CannotListenError:
        logger.error("STMP Service failed to start: "
                     "cannot listen in port %s" % port)
        emit(catalog.SMTP_SERVICE_FAILED_TO_START, str(port))
    except Exception as exc:
        logger.error("Unhandled error while launching smtp gateway service")
        logger.exception(exc)
예제 #25
0
def setup_smtp_gateway(port, userid, keymanager, smtp_host, smtp_port,
                       smtp_cert, smtp_key, encrypted_only):
    """
    Setup SMTP gateway to run with Twisted.

    This function sets up the SMTP gateway configuration and the Twisted
    reactor.

    :param port: The port in which to run the server.
    :type port: int
    :param userid: The user currently logged in
    :type userid: str
    :param keymanager: A Key Manager from where to get recipients' public
                       keys.
    :type keymanager: leap.common.keymanager.KeyManager
    :param smtp_host: The hostname of the remote SMTP server.
    :type smtp_host: str
    :param smtp_port: The port of the remote SMTP server.
    :type smtp_port: int
    :param smtp_cert: The client certificate for authentication.
    :type smtp_cert: str
    :param smtp_key: The client key for authentication.
    :type smtp_key: str
    :param encrypted_only: Whether the SMTP gateway should send unencrypted
                           mail or not.
    :type encrypted_only: bool

    :returns: tuple of SMTPFactory, twisted.internet.tcp.Port
    """
    # configure the use of this service with twistd
    outgoing_mail = OutgoingMail(
        userid, keymanager, smtp_cert, smtp_key, smtp_host, smtp_port)
    factory = SMTPFactory(userid, keymanager, encrypted_only, outgoing_mail)
    try:
        tport = reactor.listenTCP(port, factory, interface="localhost")
        emit(catalog.SMTP_SERVICE_STARTED, str(port))
        return factory, tport
    except CannotListenError:
        logger.error("STMP Service failed to start: "
                     "cannot listen in port %s" % port)
        emit(catalog.SMTP_SERVICE_FAILED_TO_START, str(port))
    except Exception as exc:
        logger.error("Unhandled error while launching smtp gateway service")
        logger.exception(exc)
예제 #26
0
    def _process_doclist(self, doclist):
        """
        Iterates through the doclist, checks if each doc
        looks like a message, and yields a deferred that will decrypt and
        process the message.

        :param doclist: iterable with msg documents.
        :type doclist: iterable.
        :returns: a list of deferreds for individual messages.
        """
        log.msg('processing doclist')
        if not doclist:
            logger.debug("no docs found")
            return
        num_mails = len(doclist)

        deferreds = []
        for index, doc in enumerate(doclist):
            logger.debug("processing doc %d of %d" % (index + 1, num_mails))
            emit(catalog.MAIL_MSG_PROCESSING,
                 str(index), str(num_mails))

            keys = doc.content.keys()

            # TODO Compatibility check with the index in pre-0.6 mx
            # that does not write the ERROR_DECRYPTING_KEY
            # This should be removed in 0.7

            has_errors = doc.content.get(fields.ERROR_DECRYPTING_KEY, None)
            if has_errors is None:
                warnings.warn("JUST_MAIL_COMPAT_IDX will be deprecated!",
                              DeprecationWarning)

            if has_errors:
                logger.debug("skipping msg with decrypting errors...")
            elif self._is_msg(keys):
                d = self._decrypt_doc(doc)
                d.addCallback(self._extract_keys)
                d.addCallbacks(self._add_message_locally, self._errback)
                deferreds.append(d)
        d = defer.gatherResults(deferreds, consumeErrors=True)
        d.addCallback(lambda _: doclist)
        return d
예제 #27
0
    def run(self):
        """
        Check for updates
        """
        if not self.mirrors:
            return

        while True:
            try:
                tuf.conf.repository_directory = os.path.join(self.bundle_path,
                                                             'repo')

                updater = tuf.client.updater.Updater('leap-updater',
                                                     self.mirrors)
                updater.refresh()

                targets = updater.all_targets()
                updated_targets = updater.updated_targets(targets,
                                                          self.source_path)
                if updated_targets:
                    logger.info("There is updates needed. Start downloading "
                                "updates.")
                for target in updated_targets:
                    updater.download_target(target, self.dest_path)
                    self._set_permissions(target)
                if os.path.isdir(self.dest_path):
                    if os.path.isdir(self.update_path):
                        shutil.rmtree(self.update_path)
                    shutil.move(self.dest_path, self.update_path)
                    filepath = sorted([f['filepath'] for f in updated_targets])
                    emit(catalog.UPDATER_NEW_UPDATES,
                         ", ".join(filepath))
                    logger.info("Updates ready: %s" % (filepath,))
                    return
            except NotImplemented as e:
                logger.error("NotImplemented: %s" % (e,))
                return
            except Exception as e:
                logger.error("An unexpected error has occurred while "
                             "updating: %s" % (e,))
            finally:
                time.sleep(self.delay)
예제 #28
0
    def _sync_soledad(self):
        """
        Synchronize with remote soledad.

        :returns: a list of LeapDocuments, or None.
        :rtype: iterable or None
        """
        def _log_synced(result):
            log.msg('FETCH soledad SYNCED.')
            return result
        try:
            log.msg('FETCH: syncing soledad...')
            d = self._soledad.sync()
            d.addCallback(_log_synced)
            return d
        # TODO is this still raised? or should we do failure.trap
        # instead?
        except InvalidAuthTokenError:
            # if the token is invalid, send an event so the GUI can
            # disable mail and show an error message.
            emit(catalog.SOLEDAD_INVALID_AUTH_TOKEN)
예제 #29
0
    def gen_key(self, ktype):
        """
        Generate a key of type ktype bound to the user's address.

        :param ktype: The type of the key.
        :type ktype: subclass of EncryptionKey

        :return: A Deferred which fires with the generated EncryptionKey.
        :rtype: Deferred

        :raise UnsupportedKeyTypeError: if invalid key type
        """
        self._assert_supported_key_type(ktype)

        def signal_finished(key):
            emit(catalog.KEYMANAGER_FINISHED_KEY_GENERATION, self._address)
            return key

        emit(catalog.KEYMANAGER_STARTED_KEY_GENERATION, self._address)
        d = self._wrapper_map[ktype].gen_key(self._address)
        d.addCallback(signal_finished)
        return d
예제 #30
0
    def gen_key(self, ktype):
        """
        Generate a key of type ktype bound to the user's address.

        :param ktype: The type of the key.
        :type ktype: subclass of EncryptionKey

        :return: A Deferred which fires with the generated EncryptionKey.
        :rtype: Deferred

        :raise UnsupportedKeyTypeError: if invalid key type
        """
        self._assert_supported_key_type(ktype)

        def signal_finished(key):
            emit(catalog.KEYMANAGER_FINISHED_KEY_GENERATION, self._address)
            return key

        emit(catalog.KEYMANAGER_STARTED_KEY_GENERATION, self._address)
        d = self._wrapper_map[ktype].gen_key(self._address)
        d.addCallback(signal_finished)
        return d
예제 #31
0
    def _verify_session(self, M2):
        """
        Verifies the session based on the M2 parameter. If the
        verification succeeds, it sets the session_id for this
        session

        Might raise SRPAuthenticationError based:
          SRPAuthBadDataFromServer
          SRPAuthVerificationFailed

        :param M2: M2 SRP parameter
        :type M2: str
        """
        logger.debug("Verifying session...")
        try:
            unhex_M2 = self._safe_unhexlify(M2)
        except TypeError:
            logger.error("Bad data from server (HAWK)")
            raise SRPAuthBadDataFromServer()

        self._srp_user.verify_session(unhex_M2)

        if not self._srp_user.authenticated():
            logger.error("Auth verification failed.")
            raise SRPAuthVerificationFailed()
        logger.debug("Session verified.")

        session_id = self._session.cookies.get(self.SESSION_ID_KEY, None)
        if not session_id:
            logger.error("Bad cookie from server (missing _session_id)")
            raise SRPAuthNoSessionId()

        # make the rpc call async
        emit(catalog.CLIENT_SESSION_ID, session_id)

        self.set_session_id(session_id)
        logger.debug("SUCCESS LOGIN")
        return True
예제 #32
0
    def _verify_session(self, M2):
        """
        Verifies the session based on the M2 parameter. If the
        verification succeeds, it sets the session_id for this
        session

        Might raise SRPAuthenticationError based:
          SRPAuthBadDataFromServer
          SRPAuthVerificationFailed

        :param M2: M2 SRP parameter
        :type M2: str
        """
        logger.debug("Verifying session...")
        try:
            unhex_M2 = self._safe_unhexlify(M2)
        except TypeError:
            logger.error("Bad data from server (HAWK)")
            raise SRPAuthBadDataFromServer()

        self._srp_user.verify_session(unhex_M2)

        if not self._srp_user.authenticated():
            logger.error("Auth verification failed.")
            raise SRPAuthVerificationFailed()
        logger.debug("Session verified.")

        session_id = self._session.cookies.get(self.SESSION_ID_KEY, None)
        if not session_id:
            logger.error("Bad cookie from server (missing _session_id)")
            raise SRPAuthNoSessionId()

        # make the rpc call async
        emit(catalog.CLIENT_SESSION_ID, session_id)

        self.set_session_id(session_id)
        logger.debug("SUCCESS LOGIN")
        return True
예제 #33
0
 def send(pubkey):
     data = {self.PUBKEY_KEY: pubkey.key_data}
     uri = "%s/%s/users/%s.json" % (self._api_uri, self._api_version,
                                    self._uid)
     self._put(uri, data)
     emit(catalog.KEYMANAGER_DONE_UPLOADING_KEYS, self._address)
예제 #34
0
    def _maybe_encrypt_and_sign(self, raw, recipient):
        """
        Attempt to encrypt and sign the outgoing message.

        The behaviour of this method depends on:

            1. the original message's content-type, and
            2. the availability of the recipient's public key.

        If the original message's content-type is "multipart/encrypted", then
        the original message is not altered. For any other content-type, the
        method attempts to fetch the recipient's public key. If the
        recipient's public key is available, the message is encrypted and
        signed; otherwise it is only signed.

        Note that, if the C{encrypted_only} configuration is set to True and
        the recipient's public key is not available, then the recipient
        address would have been rejected in SMTPDelivery.validateTo().

        The following table summarizes the overall behaviour of the gateway:

        +---------------------------------------------------+----------------+
        | content-type        | rcpt pubkey | enforce encr. | action         |
        +---------------------+-------------+---------------+----------------+
        | multipart/encrypted | any         | any           | pass           |
        | other               | available   | any           | encrypt + sign |
        | other               | unavailable | yes           | reject         |
        | other               | unavailable | no            | sign           |
        +---------------------+-------------+---------------+----------------+

        :param raw: The raw message
        :type raw: str
        :param recipient: The recipient for the message
        :type: recipient: smtp.User

        :return: A Deferred that will be fired with a MIMEMultipart message
                 and the original recipient Message
        :rtype: Deferred
        """
        # pass if the original message's content-type is "multipart/encrypted"
        origmsg = Parser().parsestr(raw)

        if origmsg.get_content_type() == 'multipart/encrypted':
            return defer.success((origmsg, recipient))

        from_address = validate_address(self._from_address)
        username, domain = from_address.split('@')
        to_address = validate_address(recipient.dest.addrstr)

        def maybe_encrypt_and_sign(message):
            d = self._encrypt_and_sign(message, to_address, from_address)
            d.addCallbacks(signal_encrypt_sign,
                           if_key_not_found_send_unencrypted,
                           errbackArgs=(message,))
            return d

        def signal_encrypt_sign(newmsg):
            emit(catalog.SMTP_END_ENCRYPT_AND_SIGN,
                 "%s,%s" % (self._from_address, to_address))
            return newmsg, recipient

        def if_key_not_found_send_unencrypted(failure, message):
            failure.trap(KeyNotFound, KeyAddressMismatch)

            log.msg('Will send unencrypted message to %s.' % to_address)
            emit(catalog.SMTP_START_SIGN, self._from_address)
            d = self._sign(message, from_address)
            d.addCallback(signal_sign)
            return d

        def signal_sign(newmsg):
            emit(catalog.SMTP_END_SIGN, self._from_address)
            return newmsg, recipient

        log.msg("Will encrypt the message with %s and sign with %s."
                % (to_address, from_address))
        emit(catalog.SMTP_START_ENCRYPT_AND_SIGN,
             "%s,%s" % (self._from_address, to_address))
        d = self._maybe_attach_key(origmsg, from_address, to_address)
        d.addCallback(maybe_encrypt_and_sign)
        return d
예제 #35
0
 def _signal_unread_to_ui(self, *args):
     """
     Sends unread event to ui.
     """
     emit(catalog.MAIL_UNREAD_MESSAGES,
          str(self._inbox_collection.count_unseen()))
예제 #36
0
 def signal_finished(key):
     emit(catalog.KEYMANAGER_FINISHED_KEY_GENERATION, self._address)
     return key
예제 #37
0
def we_are_the_one_and_only():
    """
    Returns True if we are the only instance running, False otherwise.
    If we came later, send a raise signal to the main instance of the
    application.

    Under windows we are not using flock magic, so we wait during
    RAISE_WINDOW_TIMEOUT time, if not ack is
    received, we assume it was a stalled lock, so we remove it and continue
    with initialization.

    :rtype: bool
    """
    if IS_UNIX:
        locker = UnixLock()
        locker.get_lock()
        we_are_the_one = locker.locked_by_us
        if not we_are_the_one:
            emit(catalog.RAISE_WINDOW)
        return we_are_the_one

    elif IS_WIN:
        locker = WindowsLock()
        locker.get_lock()
        we_are_the_one = locker.locked_by_us

        if not we_are_the_one:
            locker.release_lock()
        lock_path = locker.get_locking_path()
        ts = get_modification_ts(lock_path)

        nowfun = datetime.datetime.now
        t0 = nowfun()
        pause = RAISE_WINDOW_TIMEOUT / float(RAISE_WINDOW_WAIT_STEPS)
        timeout_delta = datetime.timedelta(0, RAISE_WINDOW_TIMEOUT)
        check_interval = lambda: nowfun() - t0 < timeout_delta

        # let's assume it's a stalled lock
        we_are_the_one = True
        emit(catalog.RAISE_WINDOW)

        while check_interval():
            if get_modification_ts(lock_path) > ts:
                # yay! someone claimed their control over the lock.
                # so the lock is alive
                logger.debug('Raise window ACK-ed')
                we_are_the_one = False
                break
            else:
                time.sleep(pause)

        if we_are_the_one:
            # ok, it really was a stalled lock. let's remove all
            # that is left, and put only ours there.
            WindowsLock.release_all_locks()
            WindowsLock().get_lock()

        return we_are_the_one

    else:
        logger.warning("Multi-instance checker "
                       "not implemented for %s" % (platform.system()))
        # lies, lies, lies...
        return True
예제 #38
0
 def found(_):
     log.msg("Accepting mail for %s..." % user.dest.addrstr)
     emit(catalog.SMTP_RECIPIENT_ACCEPTED_ENCRYPTED, user.dest.addrstr)
예제 #39
0
 def signal_finished(key):
     emit(catalog.KEYMANAGER_FINISHED_KEY_GENERATION, self._address)
     return key
예제 #40
0
def we_are_the_one_and_only():
    """
    Returns True if we are the only instance running, False otherwise.
    If we came later, send a raise signal to the main instance of the
    application.

    Under windows we are not using flock magic, so we wait during
    RAISE_WINDOW_TIMEOUT time, if not ack is
    received, we assume it was a stalled lock, so we remove it and continue
    with initialization.

    :rtype: bool
    """
    if IS_UNIX:
        locker = UnixLock()
        locker.get_lock()
        we_are_the_one = locker.locked_by_us
        if not we_are_the_one:
            emit(catalog.RAISE_WINDOW)
        return we_are_the_one

    elif IS_WIN:
        locker = WindowsLock()
        locker.get_lock()
        we_are_the_one = locker.locked_by_us

        if not we_are_the_one:
            locker.release_lock()
        lock_path = locker.get_locking_path()
        ts = get_modification_ts(lock_path)

        nowfun = datetime.datetime.now
        t0 = nowfun()
        pause = RAISE_WINDOW_TIMEOUT / float(RAISE_WINDOW_WAIT_STEPS)
        timeout_delta = datetime.timedelta(0, RAISE_WINDOW_TIMEOUT)
        check_interval = lambda: nowfun() - t0 < timeout_delta

        # let's assume it's a stalled lock
        we_are_the_one = True
        emit(catalog.RAISE_WINDOW)

        while check_interval():
            if get_modification_ts(lock_path) > ts:
                # yay! someone claimed their control over the lock.
                # so the lock is alive
                logger.debug('Raise window ACK-ed')
                we_are_the_one = False
                break
            else:
                time.sleep(pause)

        if we_are_the_one:
            # ok, it really was a stalled lock. let's remove all
            # that is left, and put only ours there.
            WindowsLock.release_all_locks()
            WindowsLock().get_lock()

        return we_are_the_one

    else:
        logger.warning("Multi-instance checker "
                       "not implemented for %s" % (platform.system()))
        # lies, lies, lies...
        return True
예제 #41
0
 def key_found(key):
     emit(catalog.KEYMANAGER_KEY_FOUND, address)
     return key
예제 #42
0
 def signal_sign(newmsg):
     emit(catalog.SMTP_END_SIGN, self._from_address)
     return newmsg, recipient
예제 #43
0
 def key_found(key):
     emit(catalog.KEYMANAGER_KEY_FOUND, address)
     return key
예제 #44
0
 def signal_encrypt_sign(newmsg):
     emit(catalog.SMTP_END_ENCRYPT_AND_SIGN,
          "%s,%s" % (self._from_address, to_address))
     return newmsg, recipient
예제 #45
0
    def _maybe_encrypt_and_sign(self, raw, recipient):
        """
        Attempt to encrypt and sign the outgoing message.

        The behaviour of this method depends on:

            1. the original message's content-type, and
            2. the availability of the recipient's public key.

        If the original message's content-type is "multipart/encrypted", then
        the original message is not altered. For any other content-type, the
        method attempts to fetch the recipient's public key. If the
        recipient's public key is available, the message is encrypted and
        signed; otherwise it is only signed.

        Note that, if the C{encrypted_only} configuration is set to True and
        the recipient's public key is not available, then the recipient
        address would have been rejected in SMTPDelivery.validateTo().

        The following table summarizes the overall behaviour of the gateway:

        +---------------------------------------------------+----------------+
        | content-type        | rcpt pubkey | enforce encr. | action         |
        +---------------------+-------------+---------------+----------------+
        | multipart/encrypted | any         | any           | pass           |
        | other               | available   | any           | encrypt + sign |
        | other               | unavailable | yes           | reject         |
        | other               | unavailable | no            | sign           |
        +---------------------+-------------+---------------+----------------+

        :param raw: The raw message
        :type raw: str
        :param recipient: The recipient for the message
        :type: recipient: smtp.User

        :return: A Deferred that will be fired with a MIMEMultipart message
                 and the original recipient Message
        :rtype: Deferred
        """
        # pass if the original message's content-type is "multipart/encrypted"
        origmsg = Parser().parsestr(raw)

        if origmsg.get_content_type() == 'multipart/encrypted':
            return defer.success((origmsg, recipient))

        from_address = validate_address(self._from_address)
        username, domain = from_address.split('@')
        to_address = validate_address(recipient.dest.addrstr)

        def maybe_encrypt_and_sign(message):
            d = self._encrypt_and_sign(message, to_address, from_address)
            d.addCallbacks(signal_encrypt_sign,
                           if_key_not_found_send_unencrypted,
                           errbackArgs=(message, ))
            return d

        def signal_encrypt_sign(newmsg):
            emit(catalog.SMTP_END_ENCRYPT_AND_SIGN,
                 "%s,%s" % (self._from_address, to_address))
            return newmsg, recipient

        def if_key_not_found_send_unencrypted(failure, message):
            failure.trap(KeyNotFound, KeyAddressMismatch)

            log.msg('Will send unencrypted message to %s.' % to_address)
            emit(catalog.SMTP_START_SIGN, self._from_address)
            d = self._sign(message, from_address)
            d.addCallback(signal_sign)
            return d

        def signal_sign(newmsg):
            emit(catalog.SMTP_END_SIGN, self._from_address)
            return newmsg, recipient

        log.msg("Will encrypt the message with %s and sign with %s." %
                (to_address, from_address))
        emit(catalog.SMTP_START_ENCRYPT_AND_SIGN,
             "%s,%s" % (self._from_address, to_address))
        d = self._maybe_attach_key(origmsg, from_address, to_address)
        d.addCallback(maybe_encrypt_and_sign)
        return d
예제 #46
0
 def signal_deleted(doc_id):
     emit(catalog.MAIL_MSG_DELETED_INCOMING)
     return doc_id
예제 #47
0
 def found(_):
     log.msg("Accepting mail for %s..." % user.dest.addrstr)
     emit(catalog.SMTP_RECIPIENT_ACCEPTED_ENCRYPTED, user.dest.addrstr)
예제 #48
0
 def signal_sign(newmsg):
     emit(catalog.SMTP_END_SIGN, self._from_address)
     return newmsg, recipient
예제 #49
0
 def signal_encrypt_sign(newmsg):
     emit(catalog.SMTP_END_ENCRYPT_AND_SIGN,
          "%s,%s" % (self._from_address, to_address))
     return newmsg, recipient