[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