summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuben Pollan <meskio@sindominio.net>2017-12-08 18:10:13 +0100
committerKali Kaneko <kali@leap.se>2017-12-20 15:27:06 +0100
commitd2e5f8406b6101971c196f40e39322e36d6bdb33 (patch)
treecfe3fb852f80effd52b7a75688cd2a5118fe9a1f
parentd5bd7394344afd2c6466f368a0de7566094a0d0d (diff)
[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
-rw-r--r--docs/changelog.rst1
-rw-r--r--src/leap/bitmask/cli/mail.py22
-rw-r--r--src/leap/bitmask/core/dispatcher.py12
-rw-r--r--src/leap/bitmask/core/mail_services.py32
-rw-r--r--src/leap/bitmask/mail/mail.py15
-rw-r--r--src/leap/bitmask/mail/utils.py5
-rw-r--r--ui/app/lib/bitmask.js13
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