[DRE-commits] [ruby-mail-gpg] 01/05: New upstream version 0.3.0
Georg Faerber
georg-alioth-guest at moszumanska.debian.org
Wed Dec 28 01:14:57 UTC 2016
This is an automated email from the git hooks/post-receive script.
georg-alioth-guest pushed a commit to branch master
in repository ruby-mail-gpg.
commit c07bba92a0c7c04eb136a6cc069d0252772e7b3e
Author: Georg Faerber <georg at riseup.net>
Date: Wed Dec 28 01:26:01 2016 +0100
New upstream version 0.3.0
---
History.txt | 8 +++
README.md | 12 ++++
lib/hkp.rb | 95 ++++++++++++++++++++++++++++----
lib/mail/gpg.rb | 38 +++++--------
lib/mail/gpg/inline_decrypted_message.rb | 4 +-
lib/mail/gpg/inline_signed_message.rb | 3 +-
lib/mail/gpg/version.rb | 2 +-
mail-gpg.gemspec | 2 +-
test/hkp_test.rb | 90 ++++++++++++++++++++++++++----
test/inline_signed_message_test.rb | 2 +-
test/message_test.rb | 2 +
11 files changed, 204 insertions(+), 54 deletions(-)
diff --git a/History.txt b/History.txt
index 99e4dff..f44f50b 100644
--- a/History.txt
+++ b/History.txt
@@ -1,3 +1,11 @@
+== 0.3.0 2016-12-27
+
+* [MIGHT BREAK THINGS] All mail headers will preserved now, if you want to
+ suppress headers you'll have to remove them yourself from now on.
+* Strip "headers" when stripping inline signature (patch by @duckdalbe)
+* support hkps URI scheme
+* bugfix for verifying the "encapsulated" variant of pgp/mime (patch by @duckdalbe)
+
== 0.2.9 2016-11-15
* add missing require to test case (patch by @ge-fa)
diff --git a/README.md b/README.md
index dc0885c..453ba26 100644
--- a/README.md
+++ b/README.md
@@ -151,6 +151,18 @@ You can specify the keyserver url when initializing the class:
hkp = Hkp.new("hkp://my-key-server.de")
```
+Or, if you want to override how ssl certificates should be treated in case of
+TLS-secured keyservers (the default is `VERIFY_PEER`):
+
+```
+hkp = Hkp.new(keyserver: "hkps://another.key-server.com",
+ ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
+```
+
+If no port is specified in hkp or hkps URIs (as in the examples above), port
+11371 will be used for hkp and port 443 for hkps URIs. Standard `http` or
+`https` URIs with or without explicitly set ports work as well.
+
If no url is given, this gem will try to determine the default keyserver
url from the system's gpg config (using `gpgconf` if available or by
parsing the `gpg.conf` file). As a last resort, the server-pool at
diff --git a/lib/hkp.rb b/lib/hkp.rb
index a9e4ee1..fab40fc 100644
--- a/lib/hkp.rb
+++ b/lib/hkp.rb
@@ -1,8 +1,66 @@
-require 'open-uri'
require 'gpgme'
+require 'openssl'
+require 'net/http'
-# simple HKP client for public key retrieval
+# simple HKP client for public key search and retrieval
class Hkp
+
+ class TooManyRedirects < StandardError; end
+
+ class InvalidResponse < StandardError; end
+
+
+ class Client
+
+ MAX_REDIRECTS = 3
+
+ def initialize(server, ssl_verify_mode: OpenSSL::SSL::VERIFY_PEER)
+ uri = URI server
+ @host = uri.host
+ @port = uri.port
+ @use_ssl = false
+ @ssl_verify_mode = ssl_verify_mode
+
+ # set port and ssl flag according to URI scheme
+ case uri.scheme.downcase
+ when 'hkp'
+ # use the HKP default port unless another port has been given
+ @port ||= 11371
+ when /\A(hkp|http)s\z/
+ # hkps goes through 443 by default
+ @port ||= 443
+ @use_ssl = true
+ end
+ @port ||= 80
+ end
+
+
+ def get(path, redirect_depth = 0)
+ Net::HTTP.start @host, @port, use_ssl: @use_ssl,
+ verify_mode: @ssl_verify_mode do |http|
+
+ request = Net::HTTP::Get.new path
+ response = http.request request
+
+ case response.code.to_i
+ when 200
+ return response.body
+ when 301, 302
+ if redirect_depth >= MAX_REDIRECTS
+ raise TooManyRedirects
+ else
+ http_get response['location'], redirect_depth + 1
+ end
+ else
+ raise InvalidResponse, response.code
+ end
+
+ end
+ end
+
+ end
+
+
def initialize(options = {})
if String === options
options = { keyserver: options }
@@ -15,6 +73,7 @@ class Hkp
!!@options[:raise_errors]
end
+ #
# hkp.search 'user at host.com'
# will return an array of arrays, one for each matching key found, containing
# the key id as the first elment and any further info returned by the key
@@ -24,27 +83,33 @@ class Hkp
# and what info they return besides the key id
def search(name)
[].tap do |results|
- open("#{@keyserver}/pks/lookup?options=mr&search=#{URI.escape name}") do |f|
- f.each_line do |l|
- components = l.strip.split(':')
- if components.shift == 'pub'
- results << components
- end
+ result = hkp_client.get "/pks/lookup?options=mr&search=#{URI.escape name}"
+
+ result.each_line do |l|
+ components = l.strip.split(':')
+ if components.shift == 'pub'
+ results << components
end
- end
+ end if result
end
+
+ rescue
+ raise $! if raise_errors?
+ nil
end
+
# returns the key data as returned from the server as a string
def fetch(id)
- open("#{@keyserver}/pks/lookup?options=mr&op=get&search=0x#{URI.escape id}") do |f|
- return clean_key f.read
- end
+ result = hkp_client.get "/pks/lookup?options=mr&op=get&search=0x#{URI.escape id}"
+ return clean_key(result) if result
+
rescue Exception
raise $! if raise_errors?
nil
end
+
# fetches key data by id and imports the found key(s) into GPG, returning the full hex fingerprints of the
# imported key(s) as an array. Given there are no collisions with the id given / the server has returned
# exactly one key this will be a one element array.
@@ -57,6 +122,11 @@ class Hkp
end
private
+
+ def hkp_client
+ @hkp_client ||= Client.new @keyserver, ssl_verify_mode: @options[:ssl_verify_mode]
+ end
+
def clean_key(key)
if key =~ /(-----BEGIN PGP PUBLIC KEY BLOCK-----.*-----END PGP PUBLIC KEY BLOCK-----)/m
return $1
@@ -83,3 +153,4 @@ class Hkp
end
end
+
diff --git a/lib/mail/gpg.rb b/lib/mail/gpg.rb
index 20070a7..fdc97d3 100644
--- a/lib/mail/gpg.rb
+++ b/lib/mail/gpg.rb
@@ -100,27 +100,16 @@ module Mail
false
end
- STANDARD_HEADERS = %w(from to cc bcc reply_to subject in_reply_to return_path message_id)
- MORE_HEADERS = %w(Auto-Submitted OpenPGP References)
-
private
def self.construct_mail(cleartext_mail, options, &block)
Mail.new do
self.perform_deliveries = cleartext_mail.perform_deliveries
- STANDARD_HEADERS.each do |field|
- if h = cleartext_mail.header[field]
- self.header[field] = h.value
- end
- end
+ Mail::Gpg.copy_headers cleartext_mail, self
+ # necessary?
if cleartext_mail.message_id
header['Message-ID'] = cleartext_mail['Message-ID'].value
end
- cleartext_mail.header.fields.each do |field|
- if MORE_HEADERS.include?(field.name) or field.name =~ /^(List|X)-/
- header[field.name] = field.value
- end
- end
instance_eval &block
end
end
@@ -135,16 +124,10 @@ module Mail
raise EncodingError, "RFC 3136 first part not a valid version part '#{encrypted_mail.parts[0]}'"
end
decrypted = DecryptedPart.new(encrypted_mail.parts[1], options)
- Mail.new(decrypted) do
- %w(from to cc bcc subject reply_to in_reply_to).each do |field|
- send field, encrypted_mail.send(field)
- end
- # copy header fields
- # headers from the encrypted part (which are already set by Mail.new
- # above) will be preserved.
- encrypted_mail.header.fields.each do |field|
- header[field.name] = field.value if field.name =~ /^X-/ && header[field.name].nil?
- end
+ Mail.new(decrypted.raw_source) do
+ # headers from the encrypted part (set by the initializer above) take
+ # precedence over those from the outer mail.
+ Mail::Gpg.copy_headers encrypted_mail, self, overwrite: false
verify_result decrypted.verify_result if options[:verify]
end
end
@@ -196,6 +179,15 @@ module Mail
return result
end
+ # copies all header fields from mail in first argument to that given last
+ def self.copy_headers(from, to, overwrite: true)
+ from.header.fields.each do |field|
+ if overwrite || to.header[field.name].nil?
+ to.header[field.name] = field.value
+ end
+ end
+ end
+
# check if PGP/MIME encrypted (RFC 3156)
def self.encrypted_mime?(mail)
diff --git a/lib/mail/gpg/inline_decrypted_message.rb b/lib/mail/gpg/inline_decrypted_message.rb
index 265ff9e..75e1d6d 100644
--- a/lib/mail/gpg/inline_decrypted_message.rb
+++ b/lib/mail/gpg/inline_decrypted_message.rb
@@ -15,9 +15,7 @@ module Mail
def self.setup(cipher_mail, options = {})
if cipher_mail.multipart?
self.new do
- cipher_mail.header.fields.each do |field|
- header[field.name] = field.value
- end
+ Mail::Gpg.copy_headers cipher_mail, self
cipher_mail.parts.each do |part|
p = VerifiedPart.new do |p|
if part.has_content_type? && /application\/(?:octet-stream|pgp-encrypted)/ =~ part.mime_type
diff --git a/lib/mail/gpg/inline_signed_message.rb b/lib/mail/gpg/inline_signed_message.rb
index b9a6959..2658f41 100644
--- a/lib/mail/gpg/inline_signed_message.rb
+++ b/lib/mail/gpg/inline_signed_message.rb
@@ -62,7 +62,8 @@ module Mail
signed_text.gsub! INLINE_SIG_RE, ''
signed_text.strip!
end
- signed_text
+ # Strip possible inline-"headers" (e.g. "Hash: SHA256", or "Comment: something").
+ signed_text.gsub(/(.*^-----BEGIN PGP SIGNED MESSAGE-----\n)(.*?)^$(.+)/m, '\1\3')
end
end
diff --git a/lib/mail/gpg/version.rb b/lib/mail/gpg/version.rb
index 8d9623b..3be5872 100644
--- a/lib/mail/gpg/version.rb
+++ b/lib/mail/gpg/version.rb
@@ -1,5 +1,5 @@
module Mail
module Gpg
- VERSION = "0.2.9"
+ VERSION = "0.3.0"
end
end
diff --git a/mail-gpg.gemspec b/mail-gpg.gemspec
index b57f095..8c0e6ac 100644
--- a/mail-gpg.gemspec
+++ b/mail-gpg.gemspec
@@ -24,6 +24,6 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "test-unit", "~> 3.0"
spec.add_development_dependency "rake"
spec.add_development_dependency "actionmailer", ">= 3.2.0"
- spec.add_development_dependency "pry-nav"
+ spec.add_development_dependency "byebug"
spec.add_development_dependency "shoulda-context", '~> 1.1'
end
diff --git a/test/hkp_test.rb b/test/hkp_test.rb
index 4e55652..c907f2b 100644
--- a/test/hkp_test.rb
+++ b/test/hkp_test.rb
@@ -1,34 +1,100 @@
require 'test_helper'
+require 'byebug'
require 'hkp'
class HkpTest < Test::Unit::TestCase
- context "keyserver setup" do
+ context "hpk client" do
+ {
+ "http://pool.sks-keyservers.net:11371" => {
+ host: 'pool.sks-keyservers.net',
+ ssl: false,
+ port: 11371
+ },
+ "https://hkps.pool.sks-keyservers.net" => {
+ host: 'hkps.pool.sks-keyservers.net',
+ ssl: true,
+ port: 443
+ },
+ "hkp://pool.sks-keyservers.net" => {
+ host: 'pool.sks-keyservers.net',
+ ssl: false,
+ port: 11371
+ },
+ "hkps://hkps.pool.sks-keyservers.net" => {
+ host: 'hkps.pool.sks-keyservers.net',
+ ssl: true,
+ port: 443
+ },
+ }.each do |url, data|
- context "with url specified" do
+ context "with server #{url}" do
- setup do
- @hkp = Hkp.new("hkp://my-key-server.net")
- end
+ context 'client setup' do
- should "use specified keyserver" do
- assert url = @hkp.instance_variable_get("@keyserver")
- assert_equal "hkp://my-key-server.net", url
- end
+ setup do
+ @client = Hkp::Client.new url
+ end
+
+ should "have correct port" do
+ assert_equal data[:port], @client.instance_variable_get("@port")
+ end
+
+ should "have correct ssl setting" do
+ assert_equal data[:ssl], @client.instance_variable_get("@use_ssl")
+ end
+
+ should "have correct host" do
+ assert_equal data[:host], @client.instance_variable_get("@host")
+ end
+
+ end
+
+ if ENV['ONLINE_TESTS']
+
+ context 'key search' do
+ setup do
+ @hkp = Hkp.new keyserver: url,
+ ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE
+ end
+
+ should 'find key' do
+ assert result = @hkp.search('jk at jkraemer.net')
+ assert result.size > 0
+ end
+
+ should 'fetch key' do
+ assert result = @hkp.fetch('584C8BEE17CAC560')
+ assert_match 'PGP PUBLIC KEY BLOCK', result
+ end
+
+ end
+
+ end
+
+ end
end
+ end
- context "without url specified" do
-
+ context 'key search' do
+
+ context "without keyserver url" do
setup do
@hkp = Hkp.new
end
- should "have found a non-empty keyserver" do
+ should "have a non-empty keyserver" do
assert url = @hkp.instance_variable_get("@keyserver")
assert !url.blank?
end
+ if ENV['ONLINE_TESTS']
+ should 'find key' do
+ assert result = @hkp.search('jk at jkraemer.net')
+ assert result.size > 0
+ end
+ end
end
end
diff --git a/test/inline_signed_message_test.rb b/test/inline_signed_message_test.rb
index c384359..1df9741 100644
--- a/test/inline_signed_message_test.rb
+++ b/test/inline_signed_message_test.rb
@@ -19,7 +19,7 @@ class InlineSignedMessageTest < Test::Unit::TestCase
should 'strip signature from signed text' do
body = self.class.inline_sign(@mail, 'i am signed')
assert stripped_body = Mail::Gpg::InlineSignedMessage.strip_inline_signature(body)
- assert_equal "-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA1\n\ni am signed\n-----END PGP SIGNED MESSAGE-----", stripped_body
+ assert_equal "-----BEGIN PGP SIGNED MESSAGE-----\n\ni am signed\n-----END PGP SIGNED MESSAGE-----", stripped_body
end
should 'not change unsigned text' do
diff --git a/test/message_test.rb b/test/message_test.rb
index 8932ecf..41a684d 100644
--- a/test/message_test.rb
+++ b/test/message_test.rb
@@ -80,6 +80,7 @@ class MessageTest < Test::Unit::TestCase
@mail.header['List-Owner'] = 'test-owner at lists.example.org'
@mail.header['List-Post'] = '<mailto:test at lists.example.org> (Subscribers only)'
@mail.header['List-Unsubscribe'] = 'bar'
+ @mail.header['Date'] = 'Sun, 25 Dec 2016 16:56:52 -0500'
@mail.header['OpenPGP'] = 'id=0x0123456789abcdef0123456789abcdefdeadbeef (present on keyservers); (Only encrypted and signed emails are accepted)'
@mail.deliver
end
@@ -91,6 +92,7 @@ class MessageTest < Test::Unit::TestCase
assert_equal 'test-owner at lists.example.org', @mails.first.header['List-Owner'].value
assert_equal '<mailto:test at lists.example.org> (Subscribers only)', @mails.first.header['List-Post'].value
assert_equal 'bar', @mails.first.header['List-Unsubscribe'].value
+ assert_equal 'Sun, 25 Dec 2016 16:56:52 -0500', @mails.first.header['Date'].value
assert_equal 'id=0x0123456789abcdef0123456789abcdefdeadbeef (present on keyservers); (Only encrypted and signed emails are accepted)', @mails.first.header['OpenPGP'].value
end
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-mail-gpg.git
More information about the Pkg-ruby-extras-commits
mailing list