From 4b7cf6800e5f2c5ffd5ce78502ced13bc714692b Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 10 Mar 2025 18:51:20 +0100 Subject: [PATCH 1/2] Add inline PGP support --- dodo/pgp_util.py | 16 ++++++++++++++++ dodo/thread.py | 5 ++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/dodo/pgp_util.py b/dodo/pgp_util.py index b24ddb0..695e522 100644 --- a/dodo/pgp_util.py +++ b/dodo/pgp_util.py @@ -33,6 +33,10 @@ Gpg = None +INLINE_BEGIN = "-----BEGIN PGP MESSAGE-----\n" +INLINE_END = "\n-----END PGP MESSAGE-----" + + class GpgError(Exception): pass @@ -148,3 +152,15 @@ def encrypt(msg: email.message.EmailMessage) -> email.message.EmailMessage: filename='encrypted.asc', cte='7bit') encrypted_mail.attach(pgp_encrypted_part) return encrypted_mail + + +def maybe_decrypt_inline(contents: str) -> str: + stripped = contents.strip("\n") + if not (stripped.startswith(INLINE_BEGIN) and stripped.endswith(INLINE_END)): + return contents + + ensure_gpg() + assert Gpg is not None # for mypy + decrypted = Gpg.decrypt(contents) + raise_for_status(decrypted) + return decrypted.data.decode() diff --git a/dodo/thread.py b/dodo/thread.py index ab9c50a..4f54b82 100644 --- a/dodo/thread.py +++ b/dodo/thread.py @@ -44,6 +44,7 @@ from . import util from . import keymap from . import panel +from . import pgp_util logger = logging.getLogger(__name__) @@ -145,7 +146,9 @@ def requestStarted(self, request: QWebEngineUrlRequestJob) -> None: if text is not None: break else: - text = util.simple_escape(util.body_text(self.message_json)) + text = util.body_text(self.message_json) + text = pgp_util.maybe_decrypt_inline(text) + text = util.simple_escape(text) text = util.colorize_text(text) text = util.linkify(text) From 62656ff282dbe0103f468f0831ebc9e7c07afd70 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 10 Mar 2025 18:52:02 +0100 Subject: [PATCH 2/2] Add inline PGP support for attachments --- dodo/pgp_util.py | 10 ++++++++++ dodo/util.py | 11 +++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/dodo/pgp_util.py b/dodo/pgp_util.py index 695e522..1fb67f5 100644 --- a/dodo/pgp_util.py +++ b/dodo/pgp_util.py @@ -164,3 +164,13 @@ def maybe_decrypt_inline(contents: str) -> str: decrypted = Gpg.decrypt(contents) raise_for_status(decrypted) return decrypted.data.decode() + + +def decrypt_inline_attachment(data: bytes) -> bytes: + ensure_gpg() + assert Gpg is not None # for mypy + + assert data.startswith(INLINE_BEGIN.encode()) and data.endswith(INLINE_END.encode()) + decrypted = Gpg.decrypt(data) + raise_for_status(decrypted) + return decrypted.data diff --git a/dodo/util.py b/dodo/util.py index 8532bfb..1a2287d 100644 --- a/dodo/util.py +++ b/dodo/util.py @@ -37,6 +37,7 @@ from bleach.linkifier import Linker from . import settings +from . import pgp_util def clean_html2html(s: str) -> str: """Sanitize the given HTML string @@ -341,13 +342,19 @@ def write_attachments(m: dict) -> Tuple[str, List[str]]: check=True, ) filename = part["filename"] - if not proc.stdout: + data = proc.stdout + + if not data: print(f"Ignoring attachment {filename}: Got empty contents from notmuch") continue + if filename.endswith(".pgp"): + filename = os.path.splitext(filename)[0] + data = pgp_util.decrypt_inline_attachment(data) + p = os.path.join(temp_dir, sanitize_filename(filename)) with open(p, 'wb') as att: - att.write(proc.stdout) + att.write(data) file_paths.append(p) if len(file_paths) == 0: