lib/sup/crypto.rb in sup-0.13.2.1 vs lib/sup/crypto.rb in sup-0.14.0
- old
+ new
@@ -1,8 +1,6 @@
begin
- # gpgme broke its API in 2.0, so make sure we have the old version for now.
- gem 'gpgme', '=1.0.8'
require 'gpgme'
rescue LoadError
end
module Redwood
@@ -62,32 +60,43 @@
# test if the gpgme gem is available
@gpgme_present =
begin
begin
- GPGME.check_version({:protocol => GPGME::PROTOCOL_OpenPGP})
+ begin
+ GPGME.check_version({:protocol => GPGME::PROTOCOL_OpenPGP})
+ rescue TypeError
+ GPGME.check_version(nil)
+ end
true
rescue GPGME::Error
false
+ rescue ArgumentError
+ # gpgme 2.0.0 raises this due to the hash->string conversion
+ false
end
rescue NameError
false
end
unless @gpgme_present
- @not_working_reason = ['gpgme gem not present',
+ @not_working_reason = ['gpgme gem not present',
'Install the gpgme gem in order to use signed and encrypted emails']
return
end
# if gpg2 is available, it will start gpg-agent if required
if (bin = `which gpg2`.chomp) =~ /\S/
- GPGME.set_engine_info GPGME::PROTOCOL_OpenPGP, bin, nil
+ if GPGME.respond_to?('set_engine_info')
+ GPGME.set_engine_info GPGME::PROTOCOL_OpenPGP, bin, nil
+ else
+ GPGME.gpgme_set_engine_info GPGME::PROTOCOL_OpenPGP, bin, nil
+ end
else
# check if the gpg-options hook uses the passphrase_callback
# if it doesn't then check if gpg agent is present
- gpg_opts = HookManager.run("gpg-options",
+ gpg_opts = HookManager.run("gpg-options",
{:operation => "sign", :options => {}}) || {}
if gpg_opts[:passphrase_callback].nil?
if ENV['GPG_AGENT_INFO'].nil?
@not_working_reason = ["Environment variable 'GPG_AGENT_INFO' not set, is gpg-agent running?",
"If gpg-agent is running, try $ export `cat ~/.gpg-agent-info`"]
@@ -108,26 +117,33 @@
end
end
end
def have_crypto?; @not_working_reason.nil? end
+ def not_working_reason; @not_working_reason end
def sign from, to, payload
return unknown_status(@not_working_reason) unless @not_working_reason.nil?
gpg_opts = {:protocol => GPGME::PROTOCOL_OpenPGP, :armor => true, :textmode => true}
gpg_opts.merge!(gen_sign_user_opts(from))
- gpg_opts = HookManager.run("gpg-options",
+ gpg_opts = HookManager.run("gpg-options",
{:operation => "sign", :options => gpg_opts}) || gpg_opts
begin
- sig = GPGME.detach_sign(format_payload(payload), gpg_opts)
+ if GPGME.respond_to?('detach_sign')
+ sig = GPGME.detach_sign(format_payload(payload), gpg_opts)
+ else
+ crypto = GPGME::Crypto.new
+ gpg_opts[:mode] = GPGME::SIG_MODE_DETACH
+ sig = crypto.sign(format_payload(payload), gpg_opts).read
+ end
rescue GPGME::Error => exc
raise Error, gpgme_exc_msg(exc.message)
end
- # if the key (or gpg-agent) is not available GPGME does not complain
+ # if the key (or gpg-agent) is not available GPGME does not complain
# but just returns a zero length string. Let's catch that
if sig.length == 0
raise Error, gpgme_exc_msg("GPG failed to generate signature: check that gpg-agent is running and your key is available.")
end
@@ -143,24 +159,30 @@
def encrypt from, to, payload, sign=false
return unknown_status(@not_working_reason) unless @not_working_reason.nil?
gpg_opts = {:protocol => GPGME::PROTOCOL_OpenPGP, :armor => true, :textmode => true}
if sign
- gpg_opts.merge!(gen_sign_user_opts(from))
+ gpg_opts.merge!(gen_sign_user_opts(from))
gpg_opts.merge!({:sign => true})
end
gpg_opts = HookManager.run("gpg-options",
{:operation => "encrypt", :options => gpg_opts}) || gpg_opts
recipients = to + [from]
recipients = HookManager.run("gpg-expand-keys", { :recipients => recipients }) || recipients
begin
- cipher = GPGME.encrypt(recipients, format_payload(payload), gpg_opts)
+ if GPGME.respond_to?('encrypt')
+ cipher = GPGME.encrypt(recipients, format_payload(payload), gpg_opts)
+ else
+ crypto = GPGME::Crypto.new
+ gpg_opts[:recipients] = recipients
+ cipher = crypto.encrypt(format_payload(payload), gpg_opts).read
+ end
rescue GPGME::Error => exc
raise Error, gpgme_exc_msg(exc.message)
end
- # if the key (or gpg-agent) is not available GPGME does not complain
+ # if the key (or gpg-agent) is not available GPGME does not complain
# but just returns a zero length string. Let's catch that
if cipher.length == 0
raise Error, gpgme_exc_msg("GPG failed to generate cipher text: check that gpg-agent is running and your key is available.")
end
@@ -260,11 +282,15 @@
gpg_opts = {:protocol => GPGME::PROTOCOL_OpenPGP}
gpg_opts = HookManager.run("gpg-options",
{:operation => "decrypt", :options => gpg_opts}) || gpg_opts
ctx = GPGME::Ctx.new(gpg_opts)
cipher_data = GPGME::Data.from_str(format_payload(payload))
- plain_data = GPGME::Data.empty
+ if GPGME::Data.respond_to?('empty')
+ plain_data = GPGME::Data.empty
+ else
+ plain_data = GPGME::Data.empty!
+ end
begin
ctx.decrypt_verify(cipher_data, plain_data)
rescue GPGME::Error => exc
return Chunk::CryptoNotice.new(:invalid, "This message could not be decrypted", gpgme_exc_msg(exc.message))
end
@@ -273,11 +299,11 @@
rescue ArgumentError => exc
sig = unknown_status [gpgme_exc_msg(exc.message)]
end
plain_data.seek(0, IO::SEEK_SET)
output = plain_data.read
- output.force_encoding Encoding::ASCII_8BIT if output.respond_to? :force_encoding
+ output.transcode(Encoding::ASCII_8BIT, output.encoding)
## TODO: test to see if it is still necessary to do a 2nd run if verify
## fails.
#
## check for a valid signature in an extra run because gpg aborts if the
@@ -288,11 +314,11 @@
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)
+ output.transcode($encoding, $1)
end
msg.body = output
else
# It appears that some clients use Windows new lines - CRLF - but RMail
# splits the body and header on "\n\n". So to allow the parse below to
@@ -312,11 +338,11 @@
# 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
+ output.fix_encoding
msg = RMail::Parser.read output
end
end
notice = Chunk::CryptoNotice.new :valid, "This message has been decrypted for display"
[notice, sig, msg]
@@ -328,11 +354,11 @@
Chunk::CryptoNotice.new :unknown, "Unable to determine validity of cryptographic signature", lines
end
def gpgme_exc_msg msg
err_msg = "Exception in GPGME call: #{msg}"
- info err_msg
+ #info err_msg
err_msg
end
## here's where we munge rmail output into the format that signed/encrypted
## PGP/GPG messages should be
@@ -360,10 +386,10 @@
elsif signature.to_s
first_sig = signature.to_s.sub(/from [0-9A-F]{16} /, 'from "') + '"'
else
first_sig = "Unknown error or empty signature"
end
- rescue EOFError
+ rescue EOFError
from_key = nil
first_sig = "No public key available for #{signature.fingerprint}"
end
time_line = "Signature made " + signature.timestamp.strftime("%a %d %b %Y %H:%M:%S %Z") +