summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAzul <azul@riseup.net>2016-04-10 14:22:12 +0200
committerAzul <azul@riseup.net>2016-04-10 17:31:24 +0200
commit78f11d66a8521492a2fbca78c9e9c9e99ebc4a3e (patch)
tree3d4b1737b972268baccf6e535d858113288a4eab
parent8bf870a11aa713ac91b22d790c5fcb129734406e (diff)
bugfix: 404 if no key matches, fixes #6789
I also separated the parsing of the hkp response from FetchKeyInfo. This way FetchKeyInfo has the EM specific code that has sideeffects and the logic is in a class without sideeffects and (almost) without state. The only state we keep is the KeyInfo array that contains all the information the server returns. This way we avoid parsing the response multiple times.
-rw-r--r--lib/nickserver.rb5
-rw-r--r--lib/nickserver/hkp/fetch_key_info.rb56
-rw-r--r--lib/nickserver/hkp/parse_key_info.rb93
3 files changed, 102 insertions, 52 deletions
diff --git a/lib/nickserver.rb b/lib/nickserver.rb
index 951dae9..eb7eddb 100644
--- a/lib/nickserver.rb
+++ b/lib/nickserver.rb
@@ -5,9 +5,10 @@ require "nickserver/email_address"
require "nickserver/couch/fetch_key"
-require "nickserver/hkp/key_info"
-require "nickserver/hkp/fetch_key_info"
require "nickserver/hkp/fetch_key"
+require "nickserver/hkp/fetch_key_info"
+require "nickserver/hkp/parse_key_info"
+require "nickserver/hkp/key_info"
require "nickserver/server"
require "nickserver/daemon"
diff --git a/lib/nickserver/hkp/fetch_key_info.rb b/lib/nickserver/hkp/fetch_key_info.rb
index 2cfff43..bc12488 100644
--- a/lib/nickserver/hkp/fetch_key_info.rb
+++ b/lib/nickserver/hkp/fetch_key_info.rb
@@ -8,23 +8,16 @@ module Nickserver; module HKP
class FetchKeyInfo
include EM::Deferrable
- # 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
-
def search(uid)
# in practice, exact=on seems to have no effect
params = {:op => 'vindex', :search => uid, :exact => 'on', :options => 'mr', :fingerprint => 'on'}
EventMachine::HttpRequest.new(Config.hkp_url).get(:query => params).callback {|http|
- if http.response_header.status != 200
- self.fail http.response_header.status, "Could net fetch keyinfo."
+ parser = ParseKeyInfo.new http.response_header, http.response
+ keys = parser.keys(uid)
+ if keys.any?
+ self.succeed keys
else
- keys, errors = parse(uid, http.response)
- if keys.empty?
- self.fail 500, errors.join("\n")
- else
- self.succeed keys
- end
+ self.fail parser.status(uid), parser.msg(uid)
end
}.errback {|http|
self.fail 500, http.error
@@ -32,43 +25,6 @@ module Nickserver; module HKP
self
end
- #
- # input:
- # uid -- uid to search for
- # vindex_result -- raw output from a vindex hkp query (machine readable)
- #
- # returns:
- # an array of:
- # [0] -- array of eligible keys (as HKPKeyInfo objects) matching uid.
- # [1] -- array of error messages
- #
- # keys are eliminated from eligibility for a number of reasons, including expiration,
- # revocation, uid match, key length, and so on...
- #
- def parse(uid, vindex_result)
- keys = []
- errors = []
- now = Time.now
- vindex_result.scan(MATCH_PUB_KEY).each do |match|
- key_info = KeyInfo.new(match[0])
- if key_info.uids.include?(uid)
- if key_info.keylen < 2048
- errors << "Ignoring key #{key_info.keyid} for #{uid}: key length is too short."
- elsif key_info.expired?
- errors << "Ignoring key #{key_info.keyid} for #{uid}: key expired."
- elsif key_info.revoked?
- errors << "Ignoring key #{key_info.keyid} for #{uid}: key revoked."
- elsif key_info.disabled?
- errors << "Ignoring key #{key_info.keyid} for #{uid}: key disabled."
- elsif key_info.expirationdate && key_info.expirationdate < now
- errors << "Ignoring key #{key_info.keyid} for #{uid}: key expired"
- else
- keys << key_info
- end
- end
- end
- [keys, errors]
- end
end
-end; end \ No newline at end of file
+end; end
diff --git a/lib/nickserver/hkp/parse_key_info.rb b/lib/nickserver/hkp/parse_key_info.rb
new file mode 100644
index 0000000..2bfcb7e
--- /dev/null
+++ b/lib/nickserver/hkp/parse_key_info.rb
@@ -0,0 +1,93 @@
+module Nickserver; module HKP
+ 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
+
+ # header -- header of the hkp response
+ # vindex_result -- raw output from a vindex hkp query (machine readable)
+ def initialize(header, vindex_result)
+ @header = header
+ @vindex_result = vindex_result
+ end
+
+ def status(uid)
+ if header.status == 200 && keys(uid).any?
+ 200
+ else
+ error_status(uid)
+ end
+ end
+
+ def keys(uid)
+ key_infos(uid).reject { |key| error_for_key(key) }
+ end
+
+ def msg(uid)
+ if errors(uid).any?
+ error_messages(uid).join "\n"
+ else
+ "Could not fetch keyinfo."
+ end
+ end
+
+ protected
+
+ attr_reader :header
+ attr_reader :vindex_result
+
+ def error_status(uid)
+ if header.status != 200
+ header.status
+ else
+ if errors(uid).any?
+ 500
+ else
+ 404
+ end
+ end
+ end
+
+ def errors(uid)
+ key_infos(uid).map{|key| error_for_key(key) }.compact
+ end
+
+ def error_messages(uid)
+ key_infos(uid).map do |key|
+ err = error_for_key(key)
+ error_message(uid, key, err)
+ end.compact
+ end
+
+ def key_infos(uid)
+ all_key_infos.select do |key_info|
+ key_info.uids.include?(uid)
+ end
+ end
+
+ def all_key_infos
+ @all_key_infos ||= vindex_result.scan(MATCH_PUB_KEY).map do |match|
+ KeyInfo.new(match[0])
+ end
+ 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
+ end
+ end
+end; end