piknik

Unnamed repository; edit this file 'description' to name the repository.
Info | Log | Files | Refs | README | LICENSE

commit 198ece70a0b1fa06a78fd6c968852d1ce91aade7
parent 67c4e43941054267f6e9513448481cd4de0519f6
Author: lash <dev@holbrook.no>
Date:   Tue, 15 Nov 2022 16:36:58 +0000

Comment output when using show tool

Diffstat:
MCHANGELOG | 2++
Mpiknik/basket.py | 4++--
Mpiknik/crypto.py | 8++++----
Mpiknik/msg.py | 3++-
Mpiknik/runnable/comment.py | 5+++--
Mpiknik/runnable/show.py | 59++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mpiknik/store/__init__.py | 3++-
Mrequirements.txt | 1+
8 files changed, 72 insertions(+), 13 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG @@ -1,6 +1,8 @@ - 0.2.0 * GPG signing of issue messages. * Use visitor pattern for messages verifier + * View message log in show command + ? Option to dump comment attachment files when viewing with show - 0.1.3 * Add command for adding MIME Multipart comments - 0.1.2 diff --git a/piknik/basket.py b/piknik/basket.py @@ -148,8 +148,8 @@ class Basket: v = self.__msg.get(issue_id) m = IssueMessage.parse(o, v.decode('utf-8'), envelope_callback=envelope_callback, message_callback=message_callback) return m - except FileNotFoundError: - logg.debug('instantiating new message log for {}'.format(issue_id)) + except FileNotFoundError as e: + logg.debug('instantiating new message log for {} {}'.format(issue_id, e)) return IssueMessage(o) diff --git a/piknik/crypto.py b/piknik/crypto.py @@ -49,20 +49,20 @@ class PGPSigner: if env_header != 'pgp': raise VerifyError('expected envelope type "pgp", but got {}'.format(env_header)) if self.__envelope_state > -1 and self.__envelope_state < 2: - raise VerifyError('new envelope before previous was verified') + raise VerifyError('new envelope before previous was verified ({})'.format(self.__envelope_state)) self.__envelope = msg self.__envelope_state = 0 def message_callback(self, envelope, msg, message_id): - if msg.get('Content-Type') != 'application/pgp-signature': - return - if self.__envelope_state == 0: self.__envelope_state = 1 self.__envelope = msg return + if msg.get('Content-Type') != 'application/pgp-signature': + return + v = self.__envelope.as_string() sig = msg.get_payload() (fd, fp) = tempfile.mkstemp() diff --git a/piknik/msg.py b/piknik/msg.py @@ -91,7 +91,8 @@ class IssueMessage: r = f.read() f.close() r = b64encode(r) - m.set_payload(str(r)) + m.add_header('Content-Length', str(len(r))) + m.set_payload(r.decode()) return m diff --git a/piknik/runnable/comment.py b/piknik/runnable/comment.py @@ -9,10 +9,11 @@ from piknik import Issue from piknik.store import FileStoreFactory from piknik.crypto import PGPSigner +logging.basicConfig(level=logging.DEBUG) + next_i = 1 def next_message_arg(): global next_i - print('next {}'.format(next_i)) r = sys.argv[next_i] @@ -39,7 +40,7 @@ arg = argp.parse_args(sys.argv[1:]) signer = PGPSigner(default_key=arg.s, use_agent=True) store_factory = FileStoreFactory(arg.d) -basket = Basket(store_factory, message_wrapper=signer.sign, message_verifier=signer.verify) +basket = Basket(store_factory, message_wrapper=signer.sign) def main(): diff --git a/piknik/runnable/show.py b/piknik/runnable/show.py @@ -1,9 +1,18 @@ +# standard imports import sys import argparse +import logging +from base64 import b64decode +from email.utils import parsedate_to_datetime +# external imports +from mimeparse import parse_mime_type + +# local imports from piknik import Basket from piknik import Issue from piknik.store import FileStoreFactory +from piknik.crypto import PGPSigner argp = argparse.ArgumentParser() @@ -16,6 +25,52 @@ store_factory = FileStoreFactory(arg.d) basket = Basket(store_factory) +# TODO can implement as email parser api instead? +class PGPWrapper(PGPSigner): + + def __init__(self, home_dir=None): + super(PGPWrapper, self).__init__(home_dir=home_dir) + self.message_date = None + + + def render_message(self, message, message_id): + r = None + m = parse_mime_type(message.get_content_type()) + print('content {}'.format(m)) + + if m[0] == 'text': + if m[1] == 'plain': + r = message.get_payload() + if message.get('Content-Transfer-Encoding') == 'BASE64': + r = b64decode(r).decode() + else: + r = '[rich text]' + else: + sz = message.get('Content-Length') + if sz == None: + sz = 'unknown' + r = '[file: ' + message.get_filename() + ', size: ' + sz + ']' + + print("message {} - {}\n\t{}\n".format(self.message_date, message_id, r)) + + + def message_callback(self, envelope, message, message_id): + super(PGPWrapper, self).message_callback(envelope, message, message_id) + + if message_id == None: + return + + if message.get('X-Piknik-Msg-Id') == None: + if message.get('Content-Type') == 'application/pgp-signature': + return + self.render_message(message, message_id) + else: + d = message.get('Date') + self.message_date = parsedate_to_datetime(d) + +verifier = PGPWrapper() + + def render_default(b, o, t): print("""id: {} title: {} @@ -42,9 +97,7 @@ tags: {} s += ' (owner)' print('\t' + str(s)) - m = basket.get_msg(arg.issue_id) - print() - print(m) + m = basket.get_msg(arg.issue_id, envelope_callback=verifier.envelope_callback, message_callback=verifier.message_callback) def main(): diff --git a/piknik/store/__init__.py b/piknik/store/__init__.py @@ -34,11 +34,12 @@ class MsgDir(HexDir): def key_to_string(self, k): u = uuid.UUID(bytes=k) - return str(u) + return u.bytes.hex() def put(self, k, v): u = uuid.UUID(k) + print('putting {}'.format(u.bytes.hex())) return self.add(u.bytes, v) diff --git a/requirements.txt b/requirements.txt @@ -1,3 +1,4 @@ shep~=0.3.0 leveldir~=0.3.1 python-gnupg~=0.5.0 +python-mimeparse~=1.6.0