diff options
-rw-r--r-- | docs/changelog.rst | 1 | ||||
-rw-r--r-- | src/leap/bitmask/cli/mail.py | 22 | ||||
-rw-r--r-- | src/leap/bitmask/core/dispatcher.py | 12 | ||||
-rw-r--r-- | src/leap/bitmask/core/mail_services.py | 32 | ||||
-rw-r--r-- | src/leap/bitmask/mail/mail.py | 15 | ||||
-rw-r--r-- | src/leap/bitmask/mail/utils.py | 5 | ||||
-rw-r--r-- | ui/app/lib/bitmask.js | 13 |
7 files changed, 96 insertions, 4 deletions
diff --git a/docs/changelog.rst b/docs/changelog.rst index 23fc46de..3b5ff5de 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -9,6 +9,7 @@ Features ~~~~~~~~ - `#8217 <https://0xacab.org/leap/bitmask-dev/issues/8217>`_: renew OpenPGP keys before they expire. - `#9074 <https://0xacab.org/leap/bitmask-dev/issues/9074>`_: pin provider ca certs. +- `#6914 <https://0xacab.org/leap/bitmask-dev/issues/6914>`_: expose an API to retrive message status. - Set a windows title, so that Bitmask windows can be programmatically manipulated. Bugfixes 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 @@ -286,6 +286,18 @@ class MailCmd(SubCommand): 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: userid = parts[2] 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 diff --git a/ui/app/lib/bitmask.js b/ui/app/lib/bitmask.js index 6ab87ff3..45df6927 100644 --- a/ui/app/lib/bitmask.js +++ b/ui/app/lib/bitmask.js @@ -395,6 +395,19 @@ var bitmask = function(){ }, /** + * Get message status of one email + * + * @param {string} uid The uid to get status about + * @param {string} mbox The name of the mailbox where the message is stored + * @param {string} message_id The Message-Id from the headers of the email + * + * @return {Promise<{'secured': bool}>} Returns the status of the email + */ + msg_status: function(uid, mbox, message_id) { + return call(['mail', 'msg_status', mbox, message_id]); + }, + + /** * Get status on the mixnet for an address. * * @param {string} uid The uid to get status about |