Commit 83adf039eb86b7a04ca7fa929137f0f0dd3358bd:
    check signatures

Branch: refs/heads/secmail
Author: Sam Ruby <[email protected]>
Committer: Sam Ruby <[email protected]>
Pusher: rubys <[email protected]>

------------------------------------------------------------
www/secmail/models/attachment.rb                             | +++++++ 
www/secmail/public/secmail.css                               | ++++ 
www/secmail/views/actions/check-signature.json.rb            | +++++++++++++ 
www/secmail/views/app.js.rb                                  | + 
www/secmail/views/check-signature.js.rb                      | +++++++++++++ 
www/secmail/views/parts.js.rb                                | ++++++ 
------------------------------------------------------------
117 changes: 117 additions, 0 deletions.
------------------------------------------------------------


diff --git a/www/secmail/models/attachment.rb b/www/secmail/models/attachment.rb
index 83f98ff..4035515 100644
--- a/www/secmail/models/attachment.rb
+++ b/www/secmail/models/attachment.rb
@@ -27,6 +27,13 @@ def safe_name
     name.untaint
   end
 
+  def as_file
+    file = Tempfile.new([safe_name, '.pdf'], encoding: Encoding::BINARY)
+    file.write(body)
+    file.rewind
+    file
+  end
+
   def as_pdf
     file = Tempfile.new([safe_name, '.pdf'], encoding: Encoding::BINARY)
     file.write(body)
diff --git a/www/secmail/public/secmail.css b/www/secmail/public/secmail.css
index 657ce65..aa2d719 100644
--- a/www/secmail/public/secmail.css
+++ b/www/secmail/public/secmail.css
@@ -15,6 +15,10 @@
   background-color: yellow;
 }
 
+.signature {
+  background-color: #FC0;
+}
+
 .dragging {
   opacity: 0.5;
 }
diff --git a/www/secmail/views/actions/check-signature.json.rb 
b/www/secmail/views/actions/check-signature.json.rb
new file mode 100644
index 0000000..1565119
--- /dev/null
+++ b/www/secmail/views/actions/check-signature.json.rb
@@ -0,0 +1,50 @@
+#
+# check signature on an attachment
+#
+
+month, hash = @message.match(%r{/(\d+)/(\w+)}).captures
+
+mbox = Mailbox.new(month)
+message = mbox.find(hash)
+
+begin
+  # fetch attachment and signature
+  attachment = message.find(@attachment).as_file
+  signature  = message.find(@signature).as_file
+
+  # run gpg verify command
+  out, err, rc = Open3.capture3 'gpg', '--verify', signature.path,
+    attachment.path
+
+  # if key is not found, fetch and try again
+  if err.include? "gpg: Can't check signature: public key not found"
+    # extract and fetch key
+    keyid = err[/[RD]SA key ID (\w+)/,1].untaint
+    out2, err2, rc2 = Open3.capture3 'gpg', '--keyserver', 'pgpkeys.mit.edu',
+      '--recv-keys', keyid
+
+    # run gpg verify command again
+    out, err, rc = Open3.capture3 'gpg', '--verify', signature.path,
+      attachment.path
+
+    # if verify failed, concatenate fetch output
+    if rc.exitstatus != 0
+      out += out2
+      err += err2
+    end
+  end
+
+  # list of strings to ignore
+  ignore = [
+    /^gpg:\s+WARNING: This key is not certified with a trusted signature!$/,
+    /^gpg:\s+There is no indication that the signature belongs to the owner\.$/
+  ]
+
+  ignore.each {|re| err.gsub! re, ''}
+
+ensure
+  attachment.unlink if attachment
+  signature.unlink if signature
+end
+
+{output: out, error: err, rc: rc.exitstatus}
diff --git a/www/secmail/views/app.js.rb b/www/secmail/views/app.js.rb
index 3154739..fc30ea6 100644
--- a/www/secmail/views/app.js.rb
+++ b/www/secmail/views/app.js.rb
@@ -3,6 +3,7 @@
 
 require_relative 'index'
 require_relative 'parts'
+require_relative 'check-signature'
 
 require_relative 'forms/icla'
 require_relative 'forms/grant'
diff --git a/www/secmail/views/check-signature.js.rb 
b/www/secmail/views/check-signature.js.rb
new file mode 100644
index 0000000..0e1e611
--- /dev/null
+++ b/www/secmail/views/check-signature.js.rb
@@ -0,0 +1,49 @@
+class CheckSignature < React
+  def initialize
+    @signature = nil
+    @checked = nil
+  end
+
+  def render
+    if @signature
+      _div.alert @alert, class: @flag
+    end
+  end
+
+  def componentDidMount()
+    self.componentWillReceiveProps()
+  end
+
+  def componentWillReceiveProps()
+    @signature = @@attachments.find {|attachment|
+      attachment == @@selected + '.asc' or attachment == @@selected + '.sig'
+    }
+
+    if @signature and @signature != @checked
+      @flag = 'alert-info'
+      @alert = 'checking signature'
+
+      data = {
+        message: window.parent.location.pathname,
+        attachment: @@selected,
+        signature: @signature
+      }
+
+      HTTP.post('../../actions/check-signature', data).then {|response|
+        output = response.output + response.error
+
+        if output.include? 'Good signature'
+          @flag = 'alert-success'
+        else
+          @flag = 'alert-danger'
+        end
+
+        @alert = output
+        @checked = @signature
+      }.catch {|error|
+        @alert = error
+        @flag = 'alert-warning'
+      }
+    end
+  end
+end
diff --git a/www/secmail/views/parts.js.rb b/www/secmail/views/parts.js.rb
index 365d4c8..c371f20 100644
--- a/www/secmail/views/parts.js.rb
+++ b/www/secmail/views/parts.js.rb
@@ -37,6 +37,10 @@ def render
         options[:className] = 'dragging'
       elsif attachment == @selected
         options[:className] = 'selected'
+      elsif attachment == @selected + '.asc'
+        options[:className] = 'signature'
+      elsif attachment == @selected + '.sig'
+        options[:className] = 'signature'
       else
         options[:className] = nil
       end
@@ -59,6 +63,8 @@ def render
 
     if @selected and not @menu
 
+      _CheckSignature selected: @selected, attachments: @attachments
+
       # filing options
       _table.doctype do
         _tr do

Reply via email to