diff options
Diffstat (limited to 'lib/nickserver/hkp')
-rw-r--r-- | lib/nickserver/hkp/client.rb | 36 | ||||
-rw-r--r-- | lib/nickserver/hkp/key_info.rb | 100 | ||||
-rw-r--r-- | lib/nickserver/hkp/parse_key_info.rb | 46 | ||||
-rw-r--r-- | lib/nickserver/hkp/response.rb | 2 | ||||
-rw-r--r-- | lib/nickserver/hkp/source.rb | 29 | ||||
-rw-r--r-- | lib/nickserver/hkp/v_index_response.rb | 28 |
6 files changed, 117 insertions, 124 deletions
diff --git a/lib/nickserver/hkp/client.rb b/lib/nickserver/hkp/client.rb index d53daad..d632a36 100644 --- a/lib/nickserver/hkp/client.rb +++ b/lib/nickserver/hkp/client.rb @@ -1,18 +1,16 @@ require 'nickserver/hkp' - -# -# Client for the HKP protocol. -# -# This is not a complete implementation - only the parts we need. -# Instantiate with an adapter that will take care of the http requests. -# -# For each request we yield http_status and the response content just -# like the adapter does. - - -module Nickserver; module Hkp +require 'nickserver/config' + +module Nickserver::Hkp + # + # Client for the HKP protocol. + # + # This is not a complete implementation - only the parts we need. + # Instantiate with an adapter that will take care of the http requests. + # + # For each request we yield http_status and the response content just + # like the adapter does. class Client - def initialize(adapter) @adapter = adapter end @@ -20,7 +18,7 @@ module Nickserver; module Hkp # # used to fetch an array of KeyInfo objects that match the given email # - def get_key_infos_by_email(email, &block) + def get_key_infos_by_email(email) get op: 'vindex', search: email.to_s, fingerprint: 'on' end @@ -28,7 +26,7 @@ module Nickserver; module Hkp # fetches ascii armored OpenPGP public key from the keyserver # def get_key_by_fingerprint(fingerprint) - get op: 'get', search: "0x" + fingerprint + get op: 'get', search: '0x' + fingerprint end protected @@ -37,9 +35,9 @@ module Nickserver; module Hkp def get(query) # in practice, exact=on seems to have no effect - query = {exact: 'on', options: 'mr'}.merge query - response = adapter.get Config.hkp_url, query: query - return response + query = { exact: 'on', options: 'mr' }.merge query + response = adapter.get Nickserver::Config.hkp_url, query: query + response end end -end; end +end diff --git a/lib/nickserver/hkp/key_info.rb b/lib/nickserver/hkp/key_info.rb index d4ecf10..e1a9500 100644 --- a/lib/nickserver/hkp/key_info.rb +++ b/lib/nickserver/hkp/key_info.rb @@ -1,70 +1,102 @@ require 'cgi' require 'nickserver/hkp' -# -# Class to represent the key information result from a query to a key server -# (but not the key itself). -# -# The initialize method parses the hkp 'machine readable' output. -# -# format definition of machine readable index output is here: -# http://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-5.2 -# module Nickserver::Hkp + # + # Class to represent the key information result from a query to a key server + # (but not the key itself). + # + # The initialize method parses the hkp 'machine readable' output. + # + # format definition of machine readable index output is here: + # http://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-5.2 + # class KeyInfo - attr_accessor :uids, :keyid, :algo, :flags + attr_accessor :uids def initialize(hkp_record) uid_lines = hkp_record.split("\n") pub_line = uid_lines.shift - @keyid, @algo, @keylen_s, @creationdate_s, @expirationdate_s, @flags = pub_line.split(':')[1..-1] - @uids = [] - uid_lines.each do |uid_line| - uid, _creationdate, _expirationdate, _flags = uid_line.split(':')[1..-1] - # for now, ignore the expirationdate and flags of uids. sks does return them anyway - @uids << CGI.unescape(uid.sub(/.*<(.+)>.*/, '\1')) + @properties = pub_line.split(':')[1..-1] + @uids = extract_uids(uid_lines) + end + + CHECKS = %i[too_short? expired? revoked? disabled? outdated?].freeze + + def error + CHECKS.find do |check| + msg = check.to_s.chop.tr('_', ' ') + "key is #{msg}." if send(check) end end + def keyid + properties.first + end + + def algo + properties.second + end + def keylen - @keylen ||= @keylen_s.to_i + properties[2].to_i end def creationdate - @creationdate ||= begin - if @creationdate_s - Time.at(@creationdate_s.to_i) - end - end + created = properties[3] + Time.at(created.to_i) end def expirationdate - @expirationdate ||= begin - if @expirationdate_s - Time.at(@expirationdate_s.to_i) - end - end + expires = properties[4] + Time.at(expires.to_i) + end + + def flags + properties.last end def rsa? - @algo == "1" + algo == '1' end def dsa? - @algo == "17" + algo == '17' + end + + protected + + attr_reader :properties + + def extract_uids(uid_lines) + uid_lines.map do |uid_line| + # for now, ignore the expirationdate and flags of uids. + # sks does return them anyway + uid, _creationdate, _expirationdate, _flags = uid_line.split(':')[1..-1] + CGI.unescape(uid.sub(/.*<(.+)>.*/, '\1')) + end + end + + # CHECKS + + def too_short? + keylen < 2048 + end + + def expired? + flags =~ /e/ end def revoked? - @flags =~ /r/ + flags =~ /r/ end def disabled? - @flags =~ /d/ + flags =~ /d/ end - def expired? - @flags =~ /e/ + def outdated? + expirationdate && expirationdate < Time.now end end - end diff --git a/lib/nickserver/hkp/parse_key_info.rb b/lib/nickserver/hkp/parse_key_info.rb index 2f928a0..a6f170c 100644 --- a/lib/nickserver/hkp/parse_key_info.rb +++ b/lib/nickserver/hkp/parse_key_info.rb @@ -1,13 +1,12 @@ -# -# Simple parser for Hkp KeyInfo responses. -# -# Focus is on simple here. Trying to avoid state and sideeffects. -# Parsing a response with 12 keys and validating them takes 2ms. -# So no need for memoization and making things more complex. -# -module Nickserver; module Hkp +module Nickserver::Hkp + # + # Simple parser for Hkp KeyInfo responses. + # + # Focus is on simple here. Trying to avoid state and sideeffects. + # Parsing a response with 12 keys and validating them takes 2ms. + # So no need for memoization and making things more complex. + # class ParseKeyInfo - # for this regexp to work, the source text must end in a trailing "\n", # which the output of sks does. MATCH_PUB_KEY = /(^pub:.+?\n(^uid:.+?\n)+)/m @@ -40,14 +39,14 @@ module Nickserver; module Hkp protected def keys(uid) - key_infos(uid).reject { |key| error_for_key(key) } + key_infos(uid).reject(&:error) end def msg(uid) if errors(uid).any? error_messages(uid).join "\n" else - "Could not fetch keyinfo." + 'Could not fetch keyinfo.' end end @@ -63,13 +62,12 @@ module Nickserver; module Hkp end def errors(uid) - key_infos(uid).map{|key| error_for_key(key) }.compact + key_infos(uid).map(&:error).compact end def error_messages(uid) key_infos(uid).map do |key| - err = error_for_key(key) - error_message(uid, key, err) + error_message(uid, key) end.compact end @@ -91,22 +89,8 @@ module Nickserver; module Hkp status == 200 end - def error_message(uid, key, err) - "Ignoring key #{key.keyid} for #{uid}: #{err}" if err - end - - def error_for_key(key) - if key.keylen < 2048 - "key length is too short." - elsif key.expired? - "key expired." - elsif key.revoked? - "key revoked." - elsif key.disabled? - "key disabled." - elsif key.expirationdate && key.expirationdate < Time.now - "key expired" - end + def error_message(uid, key) + "Ignoring key #{key.keyid} for #{uid}: #{key.error}" if key.error end end -end; end +end diff --git a/lib/nickserver/hkp/response.rb b/lib/nickserver/hkp/response.rb index c52e25f..2cc69d3 100644 --- a/lib/nickserver/hkp/response.rb +++ b/lib/nickserver/hkp/response.rb @@ -1,6 +1,5 @@ module Nickserver::Hkp class Response - attr_reader :status, :content def initialize(uid, key) @@ -13,6 +12,5 @@ module Nickserver::Hkp def format_response(map) map.to_json end - end end diff --git a/lib/nickserver/hkp/source.rb b/lib/nickserver/hkp/source.rb index 82c94a0..d7c86a3 100644 --- a/lib/nickserver/hkp/source.rb +++ b/lib/nickserver/hkp/source.rb @@ -2,24 +2,21 @@ require 'nickserver/source' require 'nickserver/response' require 'nickserver/hkp/response' require 'nickserver/hkp/client' -require "nickserver/hkp/parse_key_info" -require "nickserver/hkp/key_info" - - -# -# Fetch keys via HKP -# http://tools.ietf.org/html/draft-shaw-openpgp-hkp-00 -# - -module Nickserver; module Hkp +require 'nickserver/hkp/parse_key_info' +require 'nickserver/hkp/key_info' + +module Nickserver::Hkp + # + # Fetch keys via HKP + # http://tools.ietf.org/html/draft-shaw-openpgp-hkp-00 + # class Source < Nickserver::Source - def query(nick) status, response = search(nick) if status == 200 best = pick_best_key(response) get_key_by_fingerprint(best.keyid, nick) - elsif status != 404 # 404 means no key found and we proceed + elsif status != 404 # 404 means no key found and we proceed Nickserver::Response.new(status, response) end end @@ -27,7 +24,7 @@ module Nickserver; module Hkp def search(nick) status, response = client.get_key_infos_by_email(nick) parser = ParseKeyInfo.new status, response - return parser.status_for(nick), parser.response_for(nick) + [parser.status_for(nick), parser.response_for(nick)] end def get_key_by_fingerprint(fingerprint, nick = nil) @@ -35,7 +32,7 @@ module Nickserver; module Hkp if status == 200 Response.new nick, response else - Nickserver::Response.new status, "HKP Request failed" + Nickserver::Response.new status, 'HKP Request failed' end end @@ -48,11 +45,11 @@ module Nickserver; module Hkp # that is signed by the oldest key. # def pick_best_key(key_info_list) - key_info_list.sort {|a,b| a.creationdate <=> b.creationdate}.last + key_info_list.sort_by(&:creationdate).last end def client @client ||= Client.new(adapter) end end -end; end +end diff --git a/lib/nickserver/hkp/v_index_response.rb b/lib/nickserver/hkp/v_index_response.rb index 865d476..a44af51 100644 --- a/lib/nickserver/hkp/v_index_response.rb +++ b/lib/nickserver/hkp/v_index_response.rb @@ -9,7 +9,6 @@ require 'nickserver/hkp/key_info' # So no need for memoization and making things more complex. module Nickserver::Hkp class VIndexResponse - # for this regexp to work, the source text must end in a trailing "\n", # which the output of sks does. MATCH_PUB_KEY = /(^pub:.+?\n(^uid:.+?\n)+)/m @@ -29,14 +28,14 @@ module Nickserver::Hkp end def keys - key_infos.reject { |key| error_for_key(key) } + key_infos.reject &:error end def msg if errors.any? error_messages.join "\n" else - "Could not fetch keyinfo." + 'Could not fetch keyinfo.' end end @@ -53,13 +52,12 @@ module Nickserver::Hkp end def errors - key_infos.map{|key| error_for_key(key) }.compact + key_infos.map { |key| error_for_key(key) }.compact end def error_messages key_infos.map do |key| - err = error_for_key(key) - error_message(key, err) + error_message(key) end.compact end @@ -75,22 +73,8 @@ module Nickserver::Hkp end end - def error_message(key, err) - "Ignoring key #{key.keyid} for #{nick}: #{err}" if err - end - - def error_for_key(key) - if key.keylen < 2048 - "key length is too short." - elsif key.expired? - "key expired." - elsif key.revoked? - "key revoked." - elsif key.disabled? - "key disabled." - elsif key.expirationdate && key.expirationdate < Time.now - "key expired" - end + def error_message(key) + "Ignoring key #{key.keyid} for #{nick}: #{key.error}" if key.error end end end |