]> git.cworth.org Git - sup/commitdiff
very preliminary gpg signature verification
authorwmorgan <wmorgan@5c8cc53c-5e98-4d25-b20a-d8db53a31250>
Fri, 14 Sep 2007 07:40:30 +0000 (07:40 +0000)
committerwmorgan <wmorgan@5c8cc53c-5e98-4d25-b20a-d8db53a31250>
Fri, 14 Sep 2007 07:40:30 +0000 (07:40 +0000)
git-svn-id: svn://rubyforge.org/var/svn/sup/trunk@574 5c8cc53c-5e98-4d25-b20a-d8db53a31250

bin/sup
lib/sup/message.rb
lib/sup/modes/thread-view-mode.rb

diff --git a/bin/sup b/bin/sup
index 6ffbac5c824637fe6b3e2f5e7ccf8970492e39bc..9180f7608d820e2dc1423473cea7de7bcf66a124 100644 (file)
--- a/bin/sup
+++ b/bin/sup
@@ -126,6 +126,8 @@ begin
     c.add :alternate_patina_color, Ncurses::COLOR_BLACK, Ncurses::COLOR_BLUE
     c.add :missing_message_color, Ncurses::COLOR_BLACK, Ncurses::COLOR_RED
     c.add :attachment_color, Ncurses::COLOR_CYAN, Ncurses::COLOR_BLACK
+    c.add :valid_cryptosig_color, Ncurses::COLOR_CYAN, Ncurses::COLOR_BLACK
+    c.add :invalid_cryptosig_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_RED, Ncurses::A_BOLD
     c.add :quote_patina_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK
     c.add :sig_patina_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK
     c.add :quote_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK
index 744485a6aa7dfb08edf9eb48f101d66496ccc8da..42ec88ae6059b325ac1e6182924d3f3fecdfcfb6 100644 (file)
@@ -112,6 +112,47 @@ EOS
     end
   end
 
+  class CryptoSignature
+    attr_reader :lines, :description
+
+    def initialize payload, signature
+      @payload = payload
+      @signature = signature
+      @status = nil
+      @description = nil
+      @lines = []
+    end
+
+    def valid?; status == :valid end
+
+    def status
+      return @status if @status
+      payload = Tempfile.new "redwood.payload"
+      signature = Tempfile.new "redwood.signature"
+
+      payload.write @payload.to_s.gsub(/(^|[^\r])\n/, "\\1\r\n")
+      payload.close
+
+      signature.write @signature.decode
+      signature.close
+
+      cmd = "gpg --quiet --batch --no-verbose --verify --logger-fd 1 #{signature.path} #{payload.path}"
+      #Redwood::log "gpg: running: #{cmd}"
+      gpg_output = `#{cmd}`
+      #Redwood::log "got output: #{gpg_output.inspect}"
+      @lines = gpg_output.split(/\n/)
+
+      @description =
+        if gpg_output =~ /^gpg: (.* signature from .*$)/
+          $1
+        else
+          "Unable to determine signature validity"
+        end
+
+      @status = ($? == 0 ? :valid : :invalid)
+    end
+  end
+
   QUOTE_PATTERN = /^\s{0,4}[>|\}]/
   BLOCK_QUOTE_PATTERN = /^-----\s*Original Message\s*----+$/
   QUOTE_START_PATTERN = /(^\s*Excerpts from)|(^\s*In message )|(^\s*In article )|(^\s*Quoting )|((wrote|writes|said|says)\s*:\s*$)/
@@ -338,10 +379,41 @@ private
   ## of the gruesome slaughterhouse and sausage factory that is a
   ## mime-encoded message, but need only see the delicious end
   ## product.
+
+  def multipart_signed_to_chunks m
+#    Redwood::log ">> multipart SIGNED: #{m.header['Content-Type']}: #{m.body.size}"
+    if m.body.size != 2
+      Redwood::log "warning: multipart/signed with #{m.body.size} parts (expecting 2)"
+      return
+    end
+
+    payload, signature = m.body
+    if payload.multipart? || signature.multipart?
+      Redwood::log "warning: multipart/signed with payload multipart #{payload.multipart?} and signature multipart #{signature.multipart?}"
+      return
+    end
+
+    if payload.header.content_type == "application/pgp-signature"
+      Redwood::log "warning: multipart/signed with payload content type #{payload.header.content_type}"
+      return
+    end
+
+    if signature.header.content_type != "application/pgp-signature"
+      Redwood::log "warning: multipart/signed with signature content type #{signature.header.content_type}"
+      return
+    end
+
+    [CryptoSignature.new(payload, signature), message_to_chunks(payload)].flatten
+  end
+        
   def message_to_chunks m, sibling_types=[]
     if m.multipart?
-      sibling_types = m.body.map { |p| p.header.content_type }
-      m.body.map { |p| message_to_chunks p, sibling_types }.flatten.compact # recurse
+      chunks = multipart_signed_to_chunks(m) if m.header.content_type == "multipart/signed"
+      unless chunks
+        sibling_types = m.body.map { |p| p.header.content_type }
+        chunks = m.body.map { |p| message_to_chunks p, sibling_types }.flatten.compact
+      end
+      chunks
     else
       filename =
         ## first, paw through the headers looking for a filename
index 643f6e2d5c4a4ff53bb816a13de3f8f74d74a40e..b1727798cb50105ea0453bb70886ea0a0ed30270 100644 (file)
@@ -179,7 +179,7 @@ class ThreadViewMode < LineCursorMode
       l = @layout[chunk]
       l.state = (l.state != :closed ? :closed : :open)
       cursor_down if l.state == :closed
-    when Message::Quote, Message::Signature
+    when Message::Quote, Message::Signature, Message::CryptoSignature
       return if chunk.lines.length == 1
       toggle_chunk_expansion chunk
     when Message::Attachment
@@ -510,6 +510,15 @@ private
       when :open
         [[[:sig_patina_color, "#{prefix}- (#{chunk.lines.length}-line signature)"]]] + chunk.lines.map { |line| [[:sig_color, "#{prefix}#{line}"]] }
       end
+    when Message::CryptoSignature
+      color = chunk.valid? ? :valid_cryptosig_color : :invalid_cryptosig_color
+      case state
+      when :closed
+        [[[color, "#{prefix}+ Cryptographic signature: #{chunk.description}"]]] 
+      when :open
+        [[[color, "#{prefix}- Cryptographic signature: #{chunk.description}"]]] +
+          chunk.lines.map { |line| [[color, "#{prefix}#{line}"]] }
+        end
     else
       raise "unknown chunk type #{chunk.class.name}"
     end