summaryrefslogtreecommitdiff
path: root/lib/nickserver/hkp/parse_key_info.rb
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 /lib/nickserver/hkp/parse_key_info.rb
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.
Diffstat (limited to 'lib/nickserver/hkp/parse_key_info.rb')
-rw-r--r--lib/nickserver/hkp/parse_key_info.rb93
1 files changed, 93 insertions, 0 deletions
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