diff --git a/moggie/app/cli/notmuch.py b/moggie/app/cli/notmuch.py index d876a9ad7..1088f9018 100644 --- a/moggie/app/cli/notmuch.py +++ b/moggie/app/cli/notmuch.py @@ -190,7 +190,7 @@ async def as_summary(self, thread): 'files': fc, 'authors': authors, 'subject': top.get('subject', md.get('subject', '(no subject)')), - 'query': ['id:%d' % mid for mid in msgs] + [None], + 'query': [self.sign_id('id:%s' % ','.join('%d' % mid for mid in msgs))] + [None], 'tags': tags} info['_tag_list'] = ' (%s)' % (' '.join(tags)) if tags else '' info['_file_count'] = '(%d)' % fc if (fc > len(msgs)) else '' @@ -205,7 +205,7 @@ async def as_summary(self, thread): async def as_messages(self, md): if md is not None: md = Metadata(*md) - yield ('%s', 'id:%8.8d' % md.idx) + yield ('%s', self.sign_id('id:%8.8d' % md.idx)) async def as_tags(self, tag_info): if tag_info is not None: @@ -391,6 +391,16 @@ async def run(self): if self.options.get('--limit=', [None])[-1]: limit = int(self.options['--limit='][-1]) + if (self.access is not True) and self.access._live_token: + access_id = self.access.config_key[len(AppConfig.ACCESS_PREFIX):] + token = self.access._live_token + def id_signer(_id): + sig = self.access.make_signature(_id, token=token) + return '%s.%s.%s' % (_id, access_id, sig) + self.sign_id = id_signer + else: + self.sign_id = lambda _id: _id + prev = None first = True async for result in self.results(query, limit, formatter): diff --git a/moggie/config/__init__.py b/moggie/config/__init__.py index cbb3cb5fa..df582c302 100644 --- a/moggie/config/__init__.py +++ b/moggie/config/__init__.py @@ -1,5 +1,7 @@ import binascii import base64 +import copy +import hashlib import json import logging import math @@ -196,6 +198,7 @@ def __init__(self, *args, **kwarg): super().__init__(*args, **kwarg) self._role_dict = DictItemProxy(self.config, self.config_key, 'roles') self._token_dict = DictItemProxy(self.config, self.config_key, 'tokens') + self._live_token = None roles = property(lambda self: self._role_dict) tokens = property(lambda self: self._token_dict) @@ -230,6 +233,21 @@ def get_default_context(self): for ctx, role in sorted(list(self.roles.items())): return ctx + def make_signature(self, *data, token=None): + sig = hashlib.sha1(bytes(token or self._live_token, 'utf-8')) + for d in data: + sig.update(bytes(d, 'utf-8')) + return sig.hexdigest() + + def check_signature(self, sig, *data): + for t in self.tokens: + tsig = self.make_signature(*data, token=t) + if sig == tsig: + return True + else: + logging.debug('tsig=%s != %s (t=%s)' % (tsig, sig, t)) + return False + def grants(self, context, roles): role = self.roles.get(context, None) ctx = self.config.contexts.get(context) @@ -504,6 +522,8 @@ def access_from_token(self, token, _raise=True): self._caches['tokens'] = token_cache acl = self._caches.get('tokens', {}).get(token) if acl is not None: + acl = copy.copy(acl) + acl._live_token = token return acl if _raise: raise PermissionError('No access granted')