sup

A curses threads-with-tags style email client

sup.git

git clone https://supmua.dev/git/sup/
commit 104e89e51733eca481a02bab731b7d030d74e400
parent 07ae55696a4121295386b4cd6ae498b2c00254a0
Author: Dan Callaghan <djc@djc.id.au>
Date:   Sat, 12 Apr 2025 15:28:19 +1000

fix signing key selection for sign_and_encrypt

The GPGME::Crypto#encrypt() method looks for :signers in its options
hash, but Sup was passing :signer which has no effect. As a result, the
mail would always be signed with the user's default signing key.

Keep the :signer misspelling on the Sup side, to avoid breaking anyone's
existing 'gpg-options' hooks, but pass :signers to GPGME.

Fixes #522.

Diffstat:
M lib/sup/crypto.rb | 2 ++
M test/test_crypto.rb | 33 +++++++++++++++++++++++++++++++++
2 files changed, 35 insertions(+), 0 deletions(-)
diff --git a/lib/sup/crypto.rb b/lib/sup/crypto.rb
@@ -177,6 +177,8 @@ EOS
     end
     gpg_opts = HookManager.run("gpg-options",
                                {:operation => "encrypt", :options => gpg_opts}) || gpg_opts
+    ## On the sup side we use :signer for backwards compatibility, but GPGME wants :signers.
+    gpg_opts[:signers] = gpg_opts[:signer]
     recipients = to + [from]
     recipients = HookManager.run("gpg-expand-keys", { :recipients => recipients }) || recipients
     begin
diff --git a/test/test_crypto.rb b/test/test_crypto.rb
@@ -113,6 +113,39 @@ class TestCryptoManager < Minitest::Test
       assert_equal "ABCDEFG" , decrypted[2].body
     end
 
+    def test_decrypt_and_verify
+      skip CryptoManager.not_working_reason if not CryptoManager.have_crypto?
+
+      encrypted = CryptoManager.sign_and_encrypt @from_email, [@to_email], "ABCDEFG"
+      assert_instance_of RMail::Message, encrypted
+      assert_instance_of String, (encrypted.body[1].body)
+      decrypted = CryptoManager.decrypt encrypted.body[1], true
+      assert_instance_of Array, decrypted
+      assert_instance_of Chunk::CryptoNotice, decrypted[0]
+      assert_instance_of Chunk::CryptoNotice, decrypted[1]
+      assert_instance_of RMail::Message, decrypted[2]
+      assert_match(/^Signature made .* using RSA key ID 072B50BE/,
+                   decrypted[1].lines[0])
+      assert_equal "Good signature from \"#{@from_email}\"", decrypted[1].lines[1]
+      assert_equal "ABCDEFG" , decrypted[2].body
+    end
+
+    def test_decrypt_and_verify_nondefault_key
+      skip CryptoManager.not_working_reason if not CryptoManager.have_crypto?
+
+      encrypted = CryptoManager.sign_and_encrypt @from_email_ecc, [@to_email], "ABCDEFG"
+      assert_instance_of RMail::Message, encrypted
+      assert_instance_of String, (encrypted.body[1].body)
+      decrypted = CryptoManager.decrypt encrypted.body[1], true
+      assert_instance_of Array, decrypted
+      assert_instance_of Chunk::CryptoNotice, decrypted[0]
+      assert_instance_of Chunk::CryptoNotice, decrypted[1]
+      assert_instance_of RMail::Message, decrypted[2]
+      assert_match(/^Signature made .* key ID AC34B83C/, decrypted[1].lines[0])
+      assert_equal "Good signature from \"#{@from_email_ecc}\"", decrypted[1].lines[1]
+      assert_equal "ABCDEFG" , decrypted[2].body
+    end
+
     def test_verify
       skip CryptoManager.not_working_reason if not CryptoManager.have_crypto?