commit 4a998b4e42b9af1c5d89b4fee6e467378e1185df
parent c62aec33a8c98ceb90d052e211574fa54d701bd7
Author: Matthieu Rakotojaona <matthieu.rakotojaona@gmail.com>
Date: Wed, 28 Jan 2015 22:44:39 +0100
Merge pull request #387 from rakoo/gpg-verify
Add key binding for fetching key and re-verifying message
Diffstat:
4 files changed, 65 insertions(+), 4 deletions(-)
diff --git a/lib/sup/crypto.rb b/lib/sup/crypto.rb
@@ -16,6 +16,9 @@ class CryptoManager
[:encrypt, "Encrypt only"]
)
+ KEY_PATTERN = /(-----BEGIN PGP PUBLIC KEY BLOCK.*-----END PGP PUBLIC KEY BLOCK)/m
+ KEYSERVER_URL = "http://pool.sks-keyservers.net:11371/pks/lookup"
+
HookManager.register "gpg-options", <<EOS
Runs before gpg is called, allowing you to modify the options (most
likely you would want to add something to certain commands, like
@@ -212,9 +215,10 @@ EOS
unknown = false
all_output_lines = []
all_trusted = true
+ unknown_fingerprint = nil
verify_result.signatures.each do |signature|
- output_lines, trusted = sig_output_lines signature
+ output_lines, trusted, unknown_fingerprint = sig_output_lines signature
all_output_lines << output_lines
all_output_lines.flatten!
all_trusted &&= trusted
@@ -242,6 +246,8 @@ EOS
end
elsif !unknown
Chunk::CryptoNotice.new(:invalid, summary_line, all_output_lines)
+ elsif unknown_fingerprint
+ Chunk::CryptoNotice.new(:unknown_key, "Unable to determine validity of cryptographic signature", all_output_lines, unknown_fingerprint)
else
unknown_status all_output_lines
end
@@ -351,6 +357,31 @@ EOS
[notice, sig, msg]
end
+ def retrieve fingerprint
+ require 'net/http'
+ uri = URI($config[:keyserver_url] || KEYSERVER_URL)
+ unless uri.scheme == "http" and not uri.host.nil?
+ return "Invalid url: #{uri}"
+ end
+
+ fingerprint = "0x" + fingerprint unless fingerprint[0..1] == "0x"
+ params = {op: "get", search: fingerprint}
+ uri.query = URI.encode_www_form(params)
+
+ begin
+ res = Net::HTTP.get_response(uri)
+ rescue SocketError # Host doesn't exist or we couldn't connect
+ end
+ return "Couldn't get key from keyserver at this address: #{uri}" unless res.is_a?(Net::HTTPSuccess)
+
+ match = KEY_PATTERN.match(res.body)
+ return "No key found" unless match && match.length > 0
+
+ GPGME::Key.import(match[0])
+
+ return nil
+ end
+
private
def unknown_status lines=[]
@@ -394,6 +425,7 @@ private
rescue EOFError
from_key = nil
first_sig = "No public key available for #{signature.fingerprint}"
+ unknown_fpr = signature.fingerprint
end
time_line = "Signature made " + signature.timestamp.strftime("%a %d %b %Y %H:%M:%S %Z") +
@@ -422,7 +454,7 @@ private
output_lines << HookManager.run("sig-output",
{:signature => signature, :from_key => from_key})
end
- return output_lines, trusted
+ return output_lines, trusted, unknown_fpr
end
def key_type key, fpr
diff --git a/lib/sup/message.rb b/lib/sup/message.rb
@@ -279,6 +279,12 @@ class Message
end
end
+ def reload_from_source!
+ @chunks = nil
+ load_from_source!
+ end
+
+
def error_message
<<EOS
#@snippet...
diff --git a/lib/sup/message_chunks.rb b/lib/sup/message_chunks.rb
@@ -307,12 +307,13 @@ EOS
end
class CryptoNotice
- attr_reader :lines, :status, :patina_text
+ attr_reader :lines, :status, :patina_text, :unknown_fingerprint
- def initialize status, description, lines=[]
+ def initialize status, description, lines=[], unknown_fingerprint=nil
@status = status
@patina_text = description
@lines = lines
+ @unknown_fingerprint = unknown_fingerprint
end
def patina_color
diff --git a/lib/sup/modes/thread_view_mode.rb b/lib/sup/modes/thread_view_mode.rb
@@ -89,6 +89,7 @@ EOS
k.add :toggle_wrap, "Toggle wrapping of text", 'w'
k.add :goto_uri, "Goto uri under cursor", 'g'
+ k.add :fetch_and_verify, "Fetch the PGP key on poolserver and re-verify message", "v"
k.add_multi "(a)rchive/(d)elete/mark as (s)pam/mark as u(N)read:", '.' do |kk|
kk.add :archive_and_kill, "Archive this thread and kill buffer", 'a'
@@ -793,6 +794,27 @@ EOS
BufferManager.flash "No URI found." unless found
end
+ def fetch_and_verify
+ message = @message_lines[curpos]
+ crypto_chunk = message.chunks.select {|chunk| chunk.is_a?(Chunk::CryptoNotice)}.first
+ return unless crypto_chunk
+ return unless crypto_chunk.unknown_fingerprint
+
+ BufferManager.flash "Retrieving key #{crypto_chunk.unknown_fingerprint} ..."
+
+ error = CryptoManager.retrieve crypto_chunk.unknown_fingerprint
+
+ if error
+ BufferManager.flash "Couldn't retrieve key: #{error.to_s}"
+ else
+ BufferManager.flash "Key #{crypto_chunk.unknown_fingerprint} successfully retrieved !"
+ end
+
+ # Re-trigger gpg verification
+ message.reload_from_source!
+ update
+ end
+
private
def initial_state_for m