lib/sup/crypto.rb in sup-0.8.1 vs lib/sup/crypto.rb in sup-0.9

- old
+ new

@@ -11,21 +11,19 @@ [:encrypt, "Encrypt only"] ) def initialize @mutex = Mutex.new - self.class.i_am_the_instance self bin = `which gpg`.chomp - @cmd = case bin when /\S/ - Redwood::log "crypto: detected gpg binary in #{bin}" + debug "crypto: detected gpg binary in #{bin}" "#{bin} --quiet --batch --no-verbose --logger-fd 1 --use-agent" else - Redwood::log "crypto: no gpg binary detected" + debug "crypto: no gpg binary detected" nil end end def have_crypto?; !@cmd.nil? end @@ -114,40 +112,55 @@ payload_fn.close output = run_gpg "--decrypt #{payload_fn.path}" if $?.success? - decrypted_payload, sig_lines = - if output =~ /\A(.*?)((^gpg: .*$)+)\Z/m - [$1, $2] + decrypted_payload, sig_lines = if output =~ /\A(.*?)((^gpg: .*$)+)\Z/m + [$1, $2] + else + [output, nil] + end + + sig = if sig_lines # encrypted & signed + if sig_lines =~ /^gpg: (Good signature from .*$)/ + Chunk::CryptoNotice.new :valid, $1, sig_lines.split("\n") else - [output, nil] + Chunk::CryptoNotice.new :invalid, $1, sig_lines.split("\n") end - - sig = - if sig_lines # encrypted & signed - if sig_lines =~ /^gpg: (Good signature from .*$)/ - Chunk::CryptoNotice.new :valid, $1, sig_lines.split("\n") - else - Chunk::CryptoNotice.new :invalid, $1, sig_lines.split("\n") - end - end + 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(decrypted_payload) + if msg.header.content_type =~ %r{^multipart/} and not msg.multipart? + decrypted_payload = "MIME-Version: 1.0\n" + decrypted_payload + msg = RMail::Parser.read(decrypted_payload) + end notice = Chunk::CryptoNotice.new :valid, "This message has been decrypted for display" - [RMail::Parser.read(decrypted_payload), sig, notice] + [notice, sig, msg] else - notice = Chunk::CryptoNotice.new :invalid, "This message could not be decrypted", output.split("\n") - [nil, nil, notice] + Chunk::CryptoNotice.new :invalid, "This message could not be decrypted", output.split("\n") end end private def unknown_status lines=[] Chunk::CryptoNotice.new :unknown, "Unable to determine validity of cryptographic signature", lines end - + def cant_find_binary ["Can't find gpg binary in path."] end ## here's where we munge rmail output into the format that signed/encrypted @@ -156,12 +169,10 @@ payload.to_s.gsub(/(^|[^\r])\n/, "\\1\r\n").gsub(/^MIME-Version: .*\r\n/, "") end def run_gpg args cmd = "#{@cmd} #{args} 2> /dev/null" - #Redwood::log "crypto: running: #{cmd}" output = `#{cmd}` - #Redwood::log "crypto: output: #{output.inspect}" unless $?.success? output end end end