From: Michael Stapelberg <michael+sup@stapelberg.de>
To: Rich Lane <rlane@club.cc.cmu.edu>
Cc: sup-devel <sup-devel@rubyforge.org>
Subject: Re: [sup-devel] [PATCH] Implement inline GPG (updated)
Date: Fri, 12 Mar 2010 12:02:00 +0100 [thread overview]
Message-ID: <1268390058-sup-9413@midna.zekjur.net> (raw)
In-Reply-To: <1268368142-sup-4547@zyrg.net>
[-- Attachment #1: Type: text/plain, Size: 815 bytes --]
Hi Rich,
Excerpts from Rich Lane's message of Fr Mär 12 05:43:38 +0100 2010:
> Since the regexes only match whole lines, why not just do string
> comparisons? I'd also like those strings to be constants but I won't
> insist on that.
Good point, I changed that.
> The body assignment should be a ternary.
I avoided that because the line gets incredibly long then (91 characters
vs. 79 characters inside the if. Are you sure you want that ternary?
If so, please just change it yourself.
> I really dislike the flip-flop operator but it looks like the best way
> to do this. Please package those selects into a commented Enumerable
> method.
Done.
> Please factor your two cases in message_to_chunks into very well
> documented methods. message_to_chunks is already too complicated.
Done.
Best regards,
Michael
[-- Attachment #2: 0001-Implement-inline-GPG.patch --]
[-- Type: application/octet-stream, Size: 8476 bytes --]
From 827d72529b46d0930bf3ee721284a8ec543ecbc5 Mon Sep 17 00:00:00 2001
From: Michael Stapelberg <michael@stapelberg.de>
Date: Tue, 9 Mar 2010 17:40:48 +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 | 50 +++++++++++++++++++++++++++++++++++++++--
lib/sup/util.rb | 5 ++++
3 files changed, 91 insertions(+), 26 deletions(-)
diff --git a/lib/sup/crypto.rb b/lib/sup/crypto.rb
index 5ece6d9..abbcb98 100644
--- a/lib/sup/crypto.rb
+++ b/lib/sup/crypto.rb
@@ -97,18 +97,24 @@ EOS
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 .*$)/
@@ -123,7 +129,7 @@ EOS
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"
@@ -153,24 +159,34 @@ EOS
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 ebc73fc..30ccaf8 100644
--- a/lib/sup/message.rb
+++ b/lib/sup/message.rb
@@ -26,7 +26,13 @@ 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*--\+\+\*\*==)/
+
+ GPG_SIGNED_START = "-----BEGIN PGP SIGNED MESSAGE-----"
+ GPG_SIGNED_END = "-----END PGP SIGNED MESSAGE-----"
+ GPG_START = "-----BEGIN PGP MESSAGE-----"
+ GPG_END = "-----END PGP MESSAGE-----"
+ GPG_SIG_END = "-----BEGIN PGP SIGNATURE-----"
MAX_SIG_DISTANCE = 15 # lines from the end
DEFAULT_SUBJECT = ""
@@ -511,8 +517,46 @@ private
## if there's no charset, use the current encoding as the charset.
## 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
- text_to_chunks((body || "").normalize_whitespace.split("\n"), encrypted)
+ if m.body
+ body = Iconv.easy_decode($encoding, m.charset || $encoding, m.decode)
+ else
+ body = ""
+ end
+
+ ## Check for inline-PGP
+ chunks = inline_gpg_to_chunks body.split("\n")
+ return chunks if chunks
+
+ text_to_chunks(body.normalize_whitespace.split("\n"), encrypted)
+ end
+ end
+ end
+
+ ## looks for gpg signed (but not encrypted) inline messages inside the
+ ## message body (there is no extra header for inline GPG) or for encrypted
+ ## (and possible signed) inline GPG messages
+ def inline_gpg_to_chunks lines
+ gpg = lines.between(GPG_SIGNED_START, GPG_SIGNED_END)
+ if !gpg.empty?
+ msg = RMail::Message.new
+ msg.body = gpg.join("\n")
+
+ sig = lines.between(GPG_SIGNED_START, GPG_SIG_END)
+ payload = RMail::Message.new
+ payload.body = sig[1, sig.count-2].join("\n")
+ return [CryptoManager.verify(nil, msg, false), message_to_chunks(payload)].flatten.compact
+ end
+
+ gpg = lines.between(GPG_START, GPG_END)
+ if !gpg.empty?
+ msg = RMail::Message.new
+ msg.body = gpg.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
end
diff --git a/lib/sup/util.rb b/lib/sup/util.rb
index ab32d7c..fb9e0c3 100644
--- a/lib/sup/util.rb
+++ b/lib/sup/util.rb
@@ -459,6 +459,11 @@ module Enumerable
def max_of
map { |e| yield e }.max
end
+
+ ## returns all the entries which are equal to startline up to endline
+ def between startline, endline
+ select { |l| true if l == startline .. l == endline }
+ end
end
class Array
--
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
next prev parent reply other threads:[~2010-03-12 11:02 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-02-18 11:40 [sup-devel] [PATCH] Implement inline GPG Michael Stapelberg
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 [this message]
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=1268390058-sup-9413@midna.zekjur.net \
--to=michael+sup@stapelberg.de \
--cc=rlane@club.cc.cmu.edu \
--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