Archive of RubyForge sup-devel mailing list
 help / color / mirror / Atom feed
From: Michael Stapelberg <michael+sup@stapelberg.de>
To: sup-devel <sup-devel@rubyforge.org>
Subject: [sup-devel] [PATCH] Implement inline GPG
Date: Thu, 18 Feb 2010 12:40:45 +0100	[thread overview]
Message-ID: <1266493070-sup-7733@midna.zekjur.net> (raw)

[-- Attachment #1: Type: text/plain, Size: 319 bytes --]

Hi,

as my previous patch was not merged, I have updated the patch to apply against
the current code. Furthermore, it now correctly handles character sets for the
GPG encrypted part.

The patch has been tested by me and another user and seems to work fine.

Please merge it for the next release.

Best regards,
Michael

[-- Attachment #2: 0001-Implement-inline-GPG.patch --]
[-- Type: application/octet-stream, Size: 7629 bytes --]

From 87e8a9b90c9566710a03b6673b5e77459350683c Mon Sep 17 00:00:00 2001
From: Michael Stapelberg <michael@stapelberg.de>
Date: Wed, 17 Feb 2010 16:36:18 +0100
Subject: [PATCH] Implement inline GPG
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The SIG_PATTERN had to be changed because GPG, when clearsigning (which
is what happens when you send inline GPG messages), kind of escapes
lines beginning with dashes (so that the -----BEGIN PGP MESSAGE-----
lines don’t get messed up). Therefore, signatures, starting with "-- "
will be escaped as "- -- ". The manpage of GPG states that the process
of clearsigning is not reversible. Thus, there is no method in GPG to
get the original message.
---
 lib/sup/crypto.rb  |   62 ++++++++++++++++++++++++++++++++-------------------
 lib/sup/message.rb |   31 +++++++++++++++++++++++++-
 2 files changed, 69 insertions(+), 24 deletions(-)

diff --git a/lib/sup/crypto.rb b/lib/sup/crypto.rb
index 91652c7..4f75936 100644
--- a/lib/sup/crypto.rb
+++ b/lib/sup/crypto.rb
@@ -86,18 +86,24 @@ class CryptoManager
     encrypt from, to, payload, true
   end
 
-  def verify payload, signature # both RubyMail::Message objects
+  def verify payload, signature, detached=true # both RubyMail::Message objects
     return unknown_status(cant_find_binary) unless @cmd
 
-    payload_fn = Tempfile.new "redwood.payload"
-    payload_fn.write format_payload(payload)
-    payload_fn.close
+    if detached
+      payload_fn = Tempfile.new "redwood.payload"
+      payload_fn.write format_payload(payload)
+      payload_fn.close
+    end
 
     signature_fn = Tempfile.new "redwood.signature"
     signature_fn.write signature.decode
     signature_fn.close
 
-    output = run_gpg "--verify #{signature_fn.path} #{payload_fn.path}"
+    if detached
+      output = run_gpg "--verify #{signature_fn.path} #{payload_fn.path}"
+    else
+      output = run_gpg "--verify #{signature_fn.path}"
+    end
     output_lines = output.split(/\n/)
 
     if output =~ /^gpg: (.* signature from .*$)/
@@ -112,7 +118,7 @@ class CryptoManager
   end
 
   ## returns decrypted_message, status, desc, lines
-  def decrypt payload # a RubyMail::Message object
+  def decrypt payload, armor=false # a RubyMail::Message object
     return unknown_status(cant_find_binary) unless @cmd
 
     payload_fn = Tempfile.new "redwood.payload"
@@ -142,24 +148,34 @@ class CryptoManager
       Chunk::CryptoNotice.new :invalid, $1, message.split("\n")
     end
 
-    # This is gross. This decrypted payload could very well be a multipart
-    # element itself, as opposed to a simple payload. For example, a
-    # multipart/signed element, like those generated by Mutt when encrypting
-    # and signing a message (instead of just clearsigning the body).
-    # Supposedly, decrypted_payload being a multipart element ought to work
-    # out nicely because Message::multipart_encrypted_to_chunks() runs the
-    # decrypted message through message_to_chunks() again to get any
-    # children. However, it does not work as intended because these inner
-    # payloads need not carry a MIME-Version header, yet they are fed to
-    # RMail as a top-level message, for which the MIME-Version header is
-    # required. This causes for the part not to be detected as multipart,
-    # hence being shown as an attachment. If we detect this is happening,
-    # we force the decrypted payload to be interpreted as MIME.
-    msg = RMail::Parser.read output
-    if msg.header.content_type =~ %r{^multipart/} && !msg.multipart?
-      output = "MIME-Version: 1.0\n" + output
-      output.force_encoding Encoding::ASCII_8BIT if output.respond_to? :force_encoding
+    if armor
+      msg = RMail::Message.new
+      # Look for Charset, they are put before the base64 crypted part
+      charsets = payload.body.split("\n").grep(/^Charset:/)
+      if !charsets.empty? and charsets[0] =~ /^Charset: (.+)$/
+        output = Iconv.easy_decode($encoding, $1, output)
+      end
+      msg.body = output
+    else
+      # This is gross. This decrypted payload could very well be a multipart
+      # element itself, as opposed to a simple payload. For example, a
+      # multipart/signed element, like those generated by Mutt when encrypting
+      # and signing a message (instead of just clearsigning the body).
+      # Supposedly, decrypted_payload being a multipart element ought to work
+      # out nicely because Message::multipart_encrypted_to_chunks() runs the
+      # decrypted message through message_to_chunks() again to get any
+      # children. However, it does not work as intended because these inner
+      # payloads need not carry a MIME-Version header, yet they are fed to
+      # RMail as a top-level message, for which the MIME-Version header is
+      # required. This causes for the part not to be detected as multipart,
+      # hence being shown as an attachment. If we detect this is happening,
+      # we force the decrypted payload to be interpreted as MIME.
       msg = RMail::Parser.read output
+      if msg.header.content_type =~ %r{^multipart/} && !msg.multipart?
+        output = "MIME-Version: 1.0\n" + output
+        output.force_encoding Encoding::ASCII_8BIT if output.respond_to? :force_encoding
+        msg = RMail::Parser.read output
+      end
     end
     notice = Chunk::CryptoNotice.new :valid, "This message has been decrypted for display"
     [notice, sig, msg]
diff --git a/lib/sup/message.rb b/lib/sup/message.rb
index a85cc0d..69ada67 100644
--- a/lib/sup/message.rb
+++ b/lib/sup/message.rb
@@ -26,7 +26,7 @@ class Message
 
   QUOTE_PATTERN = /^\s{0,4}[>|\}]/
   BLOCK_QUOTE_PATTERN = /^-----\s*Original Message\s*----+$/
-  SIG_PATTERN = /(^-- ?$)|(^\s*----------+\s*$)|(^\s*_________+\s*$)|(^\s*--~--~-)|(^\s*--\+\+\*\*==)/
+  SIG_PATTERN = /(^(- )*-- ?$)|(^\s*----------+\s*$)|(^\s*_________+\s*$)|(^\s*--~--~-)|(^\s*--\+\+\*\*==)/
 
   MAX_SIG_DISTANCE = 15 # lines from the end
   DEFAULT_SUBJECT = ""
@@ -512,6 +512,35 @@ private
         ## this ensures that the body is normalized to avoid non-displayable
         ## characters
         body = Iconv.easy_decode($encoding, m.charset || $encoding, m.decode) if m.body
+        lines = body.split("\n")
+
+        ## Check for inline-PGP
+        if body =~ /-----BEGIN PGP SIGNED MESSAGE-----/
+          sign_start = lines.index("-----BEGIN PGP SIGNED MESSAGE-----")
+          sign_end = lines.index("-----END PGP SIGNED MESSAGE-----") || lines.count
+          msg = RMail::Message.new
+          msg.body = lines[sign_start, sign_end+1].join("\n")
+
+          sign_end = lines.index("-----BEGIN PGP SIGNATURE-----") || sign_end
+          payload = RMail::Message.new
+          payload.body = lines[sign_start+1, sign_end-1].join("\n")
+          return [CryptoManager.verify(nil, msg, false), message_to_chunks(payload)].flatten.compact
+        end
+
+        if body =~ /-----BEGIN PGP MESSAGE-----/
+          signstart = lines.index("-----BEGIN PGP MESSAGE-----")
+          signend = lines.index("-----END PGP MESSAGE-----") || lines.count
+          msg = RMail::Message.new
+          msg.body = lines[signstart, signend+1].join("\n")
+          notice, sig, decryptedm = CryptoManager.decrypt msg, true
+          if decryptedm # managed to decrypt
+            children = message_to_chunks(decryptedm, true)
+            return [notice, sig].compact + children
+          else
+            return [notice]
+          end
+        end
+
         text_to_chunks((body || "").normalize_whitespace.split("\n"), encrypted)
       end
     end
-- 
1.6.5


[-- Attachment #3: Type: text/plain, Size: 143 bytes --]

_______________________________________________
Sup-devel mailing list
Sup-devel@rubyforge.org
http://rubyforge.org/mailman/listinfo/sup-devel

             reply	other threads:[~2010-02-18 11:40 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-02-18 11:40 Michael Stapelberg [this message]
2010-02-26 21:24 ` Rich Lane
2010-02-27 13:11   ` Michael Stapelberg
2010-02-27 18:05     ` Rich Lane
2010-03-01 13:45       ` Michael Stapelberg
2010-03-01 14:36         ` Christian Dietrich
2010-03-01 16:49           ` Michael Stapelberg
2010-03-01 17:46             ` Christian Dietrich
2010-03-09 16:43               ` [sup-devel] [PATCH] Implement inline GPG (updated) Michael Stapelberg
2010-03-10 21:23                 ` Michael Stapelberg
2010-03-12  4:43                   ` Rich Lane
2010-03-12 11:02                     ` Michael Stapelberg
2010-03-15  5:19                       ` Rich Lane

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1266493070-sup-7733@midna.zekjur.net \
    --to=michael+sup@stapelberg.de \
    --cc=sup-devel@rubyforge.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox