From d2e5f8406b6101971c196f40e39322e36d6bdb33 Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Fri, 8 Dec 2017 18:10:13 +0100 Subject: [feat] Add msg_status call to the mail API To get the status of a single message providing it's mailbox and message-id. For now it only returns encryption/signature status. - Resolves: #6914 --- src/leap/bitmask/cli/mail.py | 22 ++++++++++++++++++++++ src/leap/bitmask/core/dispatcher.py | 12 ++++++++++++ src/leap/bitmask/core/mail_services.py | 32 ++++++++++++++++++++++++++++---- src/leap/bitmask/mail/mail.py | 15 +++++++++++++++ src/leap/bitmask/mail/utils.py | 5 +++++ 5 files changed, 82 insertions(+), 4 deletions(-) (limited to 'src/leap/bitmask') diff --git a/src/leap/bitmask/cli/mail.py b/src/leap/bitmask/cli/mail.py index bb880e7b..25f3df52 100644 --- a/src/leap/bitmask/cli/mail.py +++ b/src/leap/bitmask/cli/mail.py @@ -35,6 +35,7 @@ SUBCOMMANDS: disable Stop service status Display status about service get_token Returns token for the mail service + msg_status Get message status msg_add Add a msg file to a mailbox '''.format(name=command.appname) @@ -75,6 +76,27 @@ SUBCOMMANDS: return self._send(command.default_printer) + def msg_status(self, raw_args): + parser = argparse.ArgumentParser( + description='Bitmask email status', + prog='%s %s %s' % tuple(sys.argv[:3])) + parser.add_argument('-u', '--userid', default='', + help='Select the userid of the mail') + parser.add_argument('-m', '--mbox', default='INBOX', + help='the mailbox whre the message is stored') + parser.add_argument('msgid', nargs=1, + help='message id to get the status from') + subargs = parser.parse_args(raw_args) + + if subargs.userid: + userid = subargs.userid + else: + userid = self.cfg.get('bonafide', 'active', default=None) + + self.data += ['msg_status', userid, subargs.mbox, subargs.msgid[0]] + + return self._send(command.default_printer) + def msg_add(self, raw_args): parser = argparse.ArgumentParser( description='Bitmask email status', diff --git a/src/leap/bitmask/core/dispatcher.py b/src/leap/bitmask/core/dispatcher.py index e97e6c0b..20c0615b 100644 --- a/src/leap/bitmask/core/dispatcher.py +++ b/src/leap/bitmask/core/dispatcher.py @@ -285,6 +285,18 @@ class MailCmd(SubCommand): 'wrong number of arguments: expected 1, got none') return mail.get_token(userid) + @register_method('dict') + def do_MSG_STATUS(self, mail, *parts, **kw): + try: + userid = parts[2] + mbox = parts[3] + message_id = parts[4] + except IndexError: + raise DispatchError( + 'wrong number of arguments: expected 3') + d = mail.do_msg_status(userid, mbox, message_id) + return d + @register_method('dict') def do_MIXNET_STATUS(self, mail, *parts, **kw): try: diff --git a/src/leap/bitmask/core/mail_services.py b/src/leap/bitmask/core/mail_services.py index ac5000fa..24bc48fa 100644 --- a/src/leap/bitmask/core/mail_services.py +++ b/src/leap/bitmask/core/mail_services.py @@ -22,6 +22,7 @@ This should be moved to the different submodules when it stabilizes. """ import json import os +import re import shutil import tempfile from collections import defaultdict @@ -48,6 +49,7 @@ try: from leap.bitmask.mail.smtp import service as smtp_service from leap.bitmask.mail.incoming.service import IncomingMail from leap.bitmask.mail.incoming.service import INCOMING_CHECK_PERIOD + from leap.bitmask.mail.utils import first from leap.soledad.client.api import Soledad HAS_MAIL = True except ImportError: @@ -625,6 +627,32 @@ class StandardMailService(service.MultiService, HookableService): token = self._service_tokens.get(userid) return {'user': userid, 'token': token} + @defer.inlineCallbacks + def do_msg_status(self, userid, mbox, msgid): + account = self._get_account(userid) + msg = yield account.get_message_by_msgid(mbox, msgid) + if msg is None: + raise Exception("Not found message id: " + msgid) + + headers = msg.get_headers() + encryption = headers.get(IncomingMail.LEAP_ENCRYPTION_HEADER, '') + signature = headers.get(IncomingMail.LEAP_SIGNATURE_HEADER, '') + + status = {} + pubkey_re = re.compile(' pubkey="([0-9A-F]*)"') + fingerprint = first(pubkey_re.findall(signature)) + status['signature'] = signature.split(';')[0] + status['sign_fp'] = fingerprint + status['encryption'] = encryption + + if ((IncomingMail.LEAP_ENCRYPTION_DECRYPTED == encryption) and + (IncomingMail.LEAP_SIGNATURE_VALID == status['signature'])): + status['secured'] = True + else: + status['secured'] = False + + defer.returnValue(status) + def do_msg_add(self, userid, raw_msg, mailbox=None): if not mailbox: mailbox = INBOX_NAME @@ -898,10 +926,6 @@ def _get_config_for_service(service, basedir, provider): return config -def first(xs): - return xs[0] - - def _pick_server(config, strategy=first): """ Picks a server from a list of possible choices. diff --git a/src/leap/bitmask/mail/mail.py b/src/leap/bitmask/mail/mail.py index 9a7b1aed..53b34132 100644 --- a/src/leap/bitmask/mail/mail.py +++ b/src/leap/bitmask/mail/mail.py @@ -1038,6 +1038,21 @@ class Account(object): """ raise NotImplementedError() + def get_message_by_msgid(self, mbox, msgid): + """ + :rtype: Message + """ + def get_msg_from_mdoc(mdoc_id): + if not mdoc_id: + return None + + return self.adaptor.get_msg_from_mdoc_id( + Message, self.store, mdoc_id) + + d = self.adaptor.get_mdoc_id_from_msgid(self.store, mbox, msgid) + d.addCallback(get_msg_from_mdoc) + return d + # Session handling def end_session(self): diff --git a/src/leap/bitmask/mail/utils.py b/src/leap/bitmask/mail/utils.py index 64fca981..d5128573 100644 --- a/src/leap/bitmask/mail/utils.py +++ b/src/leap/bitmask/mail/utils.py @@ -373,3 +373,8 @@ class CaseInsensitiveDict(dict): def __getitem__(self, key): return super(CaseInsensitiveDict, self).__getitem__(key.lower()) + + def get(self, key, default=None): + if key.lower() in self: + return self[key] + return default -- cgit v1.2.3