summaryrefslogtreecommitdiff
path: root/lib/nickserver
diff options
context:
space:
mode:
Diffstat (limited to 'lib/nickserver')
-rw-r--r--lib/nickserver/adapters.rb4
-rw-r--r--lib/nickserver/adapters/couch_db.rb12
-rw-r--r--lib/nickserver/adapters/local.rb8
-rw-r--r--lib/nickserver/adapters/remote.rb4
-rw-r--r--lib/nickserver/couch_db.rb4
-rw-r--r--lib/nickserver/couch_db/response.rb51
-rw-r--r--lib/nickserver/couch_db/source.rb34
-rw-r--r--lib/nickserver/hkp.rb4
-rw-r--r--lib/nickserver/hkp/fetch_key.rb2
-rw-r--r--lib/nickserver/hkp/fetch_key_info.rb2
-rw-r--r--lib/nickserver/hkp/key_info.rb2
-rw-r--r--lib/nickserver/hkp/parse_key_info.rb4
-rw-r--r--lib/nickserver/hkp/v_index_response.rb96
-rw-r--r--lib/nickserver/invalid_source.rb14
-rw-r--r--lib/nickserver/lookup.rb31
-rw-r--r--lib/nickserver/nickname.rb51
-rw-r--r--lib/nickserver/response.rb15
-rw-r--r--lib/nickserver/server.rb2
18 files changed, 334 insertions, 6 deletions
diff --git a/lib/nickserver/adapters.rb b/lib/nickserver/adapters.rb
new file mode 100644
index 0000000..c87cb63
--- /dev/null
+++ b/lib/nickserver/adapters.rb
@@ -0,0 +1,4 @@
+module Nickserver
+ module Adapters
+ end
+end
diff --git a/lib/nickserver/adapters/couch_db.rb b/lib/nickserver/adapters/couch_db.rb
new file mode 100644
index 0000000..e8a23ad
--- /dev/null
+++ b/lib/nickserver/adapters/couch_db.rb
@@ -0,0 +1,12 @@
+require 'nickserver/adapters'
+
+class Nickserver::Adapters::CouchDB
+
+
+ protected
+
+ def query_couch(nick)
+ yield 404, "{}"
+ end
+
+end
diff --git a/lib/nickserver/adapters/local.rb b/lib/nickserver/adapters/local.rb
new file mode 100644
index 0000000..d6210c3
--- /dev/null
+++ b/lib/nickserver/adapters/local.rb
@@ -0,0 +1,8 @@
+require 'nickserver/adapters'
+
+class Nickserver::Adapters::Local
+
+ def query(nick)
+ end
+
+end
diff --git a/lib/nickserver/adapters/remote.rb b/lib/nickserver/adapters/remote.rb
new file mode 100644
index 0000000..e12bd26
--- /dev/null
+++ b/lib/nickserver/adapters/remote.rb
@@ -0,0 +1,4 @@
+require 'nickserver/adapters'
+
+class Nickserver::Adapters::Remote
+end
diff --git a/lib/nickserver/couch_db.rb b/lib/nickserver/couch_db.rb
new file mode 100644
index 0000000..5c63fc1
--- /dev/null
+++ b/lib/nickserver/couch_db.rb
@@ -0,0 +1,4 @@
+module Nickserver
+ module CouchDB
+ end
+end
diff --git a/lib/nickserver/couch_db/response.rb b/lib/nickserver/couch_db/response.rb
new file mode 100644
index 0000000..c6afe03
--- /dev/null
+++ b/lib/nickserver/couch_db/response.rb
@@ -0,0 +1,51 @@
+require 'nickserver/couch_db'
+require 'json'
+
+module Nickserver::CouchDB
+ class Response
+
+ def initialize(nick, couch_response = {})
+ @nick = nick
+ @couch_status = couch_response[:status]
+ @json = JSON.load(couch_response[:body]) if couch_status == 200
+ end
+
+ def status
+ if ok? && empty? then 404
+ else couch_status
+ end
+ end
+
+ def content
+ key_response if ok? && !empty?
+ end
+
+ protected
+
+ def key_response
+ format address: nick.to_s, openpgp: key
+ end
+
+ def format(response)
+ response.to_json
+ end
+
+ def key
+ rows.first["value"]
+ end
+
+ def ok?
+ couch_status == 200
+ end
+
+ def empty?
+ rows.empty?
+ end
+
+ def rows
+ json["rows"]
+ end
+
+ attr_reader :couch_status, :json, :nick
+ end
+end
diff --git a/lib/nickserver/couch_db/source.rb b/lib/nickserver/couch_db/source.rb
new file mode 100644
index 0000000..fffa76e
--- /dev/null
+++ b/lib/nickserver/couch_db/source.rb
@@ -0,0 +1,34 @@
+#
+# This class allows querying couch for public keys.
+#
+require 'nickserver/couch_db/response'
+
+module Nickserver::CouchDB
+ class Source
+
+ VIEW = '/_design/Identity/_view/pgp_key_by_email'
+
+ def initialize(adapter)
+ @adapter = adapter
+ end
+
+ def query(nick)
+ adapter.get VIEW, query: query_for(nick) do |status, body|
+ yield Response.new nick, status: status, body: body
+ end
+ end
+
+ protected
+
+ def query_for(nick)
+ { reduce: "false", key: "\"#{nick}\"" }
+ end
+
+ def adapter
+ @adapter
+ # Nickserver::Adapters::Http.new(config)
+ end
+
+ attr_reader :config
+ end
+end
diff --git a/lib/nickserver/hkp.rb b/lib/nickserver/hkp.rb
new file mode 100644
index 0000000..bb82a20
--- /dev/null
+++ b/lib/nickserver/hkp.rb
@@ -0,0 +1,4 @@
+module Nickserver
+ module Hkp
+ end
+end
diff --git a/lib/nickserver/hkp/fetch_key.rb b/lib/nickserver/hkp/fetch_key.rb
index 44621d3..55eeefa 100644
--- a/lib/nickserver/hkp/fetch_key.rb
+++ b/lib/nickserver/hkp/fetch_key.rb
@@ -5,7 +5,7 @@ require 'em-http'
# http://tools.ietf.org/html/draft-shaw-openpgp-hkp-00
#
-module Nickserver; module HKP
+module Nickserver; module Hkp
class FetchKey
include EM::Deferrable
diff --git a/lib/nickserver/hkp/fetch_key_info.rb b/lib/nickserver/hkp/fetch_key_info.rb
index 2448bb1..b7481d0 100644
--- a/lib/nickserver/hkp/fetch_key_info.rb
+++ b/lib/nickserver/hkp/fetch_key_info.rb
@@ -4,7 +4,7 @@ require 'em-http'
# used to fetch an array of KeyInfo objects that match the given uid.
#
-module Nickserver; module HKP
+module Nickserver; module Hkp
class FetchKeyInfo
include EM::Deferrable
diff --git a/lib/nickserver/hkp/key_info.rb b/lib/nickserver/hkp/key_info.rb
index adb75d8..dc0443c 100644
--- a/lib/nickserver/hkp/key_info.rb
+++ b/lib/nickserver/hkp/key_info.rb
@@ -9,7 +9,7 @@ require 'cgi'
# format definition of machine readable index output is here:
# http://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-5.2
#
-module Nickserver; module HKP
+module Nickserver; module Hkp
class KeyInfo
attr_accessor :uids, :keyid, :algo, :keylen, :creationdate, :expirationdate, :flags
diff --git a/lib/nickserver/hkp/parse_key_info.rb b/lib/nickserver/hkp/parse_key_info.rb
index 8934829..d8abe4f 100644
--- a/lib/nickserver/hkp/parse_key_info.rb
+++ b/lib/nickserver/hkp/parse_key_info.rb
@@ -1,11 +1,11 @@
#
-# Simple parser for HKP KeyInfo responses.
+# 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; module Hkp
class ParseKeyInfo
# for this regexp to work, the source text must end in a trailing "\n",
diff --git a/lib/nickserver/hkp/v_index_response.rb b/lib/nickserver/hkp/v_index_response.rb
new file mode 100644
index 0000000..865d476
--- /dev/null
+++ b/lib/nickserver/hkp/v_index_response.rb
@@ -0,0 +1,96 @@
+require 'nickserver/hkp'
+require 'nickserver/hkp/key_info'
+
+#
+# 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::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
+
+ # hkp_response -- raw output from a vindex hkp query (machine readable)
+ def initialize(nick, hkp_response)
+ @nick = nick.to_s
+ @vindex_result = hkp_response[:body]
+ end
+
+ def status
+ if keys.empty?
+ error_status
+ else
+ 200
+ end
+ end
+
+ def keys
+ key_infos.reject { |key| error_for_key(key) }
+ end
+
+ def msg
+ if errors.any?
+ error_messages.join "\n"
+ else
+ "Could not fetch keyinfo."
+ end
+ end
+
+ protected
+
+ attr_reader :vindex_result, :nick
+
+ def error_status
+ if errors.any?
+ 500
+ else
+ 404
+ end
+ end
+
+ def errors
+ 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)
+ end.compact
+ end
+
+ def key_infos
+ all_key_infos.select do |key_info|
+ key_info.uids.include?(nick)
+ 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(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
+ end
+ end
+end
diff --git a/lib/nickserver/invalid_source.rb b/lib/nickserver/invalid_source.rb
new file mode 100644
index 0000000..dac245a
--- /dev/null
+++ b/lib/nickserver/invalid_source.rb
@@ -0,0 +1,14 @@
+#
+# This is a dummy source for invalid queries.
+# It simply always returns 500 and "Not a valid address"
+#
+
+module Nickserver
+ class InvalidSource
+
+ def query(nick)
+ yield 500, "Not a valid address"
+ end
+
+ end
+end
diff --git a/lib/nickserver/lookup.rb b/lib/nickserver/lookup.rb
new file mode 100644
index 0000000..105e77e
--- /dev/null
+++ b/lib/nickserver/lookup.rb
@@ -0,0 +1,31 @@
+require 'nickserver/invalid_source'
+
+module Nickserver
+ class Lookup
+
+ attr_reader :nick
+
+ def initialize(nick)
+ @nick = nick
+ end
+
+ def respond_with(responder)
+ query do |status, content|
+ responder.send_response status: status, content: content
+ end
+ end
+
+ protected
+
+ def query(&block)
+ source.query nick, &block
+ end
+
+ def source
+ if nick.invalid? then Nickserver::InvalidSource
+ elsif nick.local? then Nickserver::Config.local_source
+ else Nickserver::Config.remote_source
+ end
+ end
+ end
+end
diff --git a/lib/nickserver/nickname.rb b/lib/nickserver/nickname.rb
new file mode 100644
index 0000000..938d4a4
--- /dev/null
+++ b/lib/nickserver/nickname.rb
@@ -0,0 +1,51 @@
+module Nickserver
+ class Nickname
+
+ EmailAddress = begin
+ qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]'
+ dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]'
+ atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+'
+ quoted_pair = '\\x5c[\\x00-\\x7f]'
+ domain_literal = "\\x5b(?:#{dtext}|#{quoted_pair})*\\x5d"
+ quoted_string = "\\x22(?:#{qtext}|#{quoted_pair})*\\x22"
+ domain_ref = atom
+ sub_domain = "(?:#{domain_ref}|#{domain_literal})"
+ word = "(?:#{atom}|#{quoted_string})"
+ domain = "#{sub_domain}(?:\\x2e#{sub_domain})*"
+ local_part = "#{word}(?:\\x2e#{word})*"
+ addr_spec = "#{local_part}\\x40#{domain}"
+ /\A#{addr_spec}\z/n
+ end
+
+ LOCAL_DOMAIN = 'test.me'
+
+ def initialize(address)
+ @address = address.to_s
+ end
+
+ def valid?
+ address =~ EmailAddress
+ end
+
+ def invalid?
+ !valid?
+ end
+
+ def local?
+ address.end_with? LOCAL_DOMAIN
+ end
+
+ def remote?
+ !local?
+ end
+
+ def to_s
+ address
+ end
+
+ protected
+
+ attr_reader :address
+
+ end
+end
diff --git a/lib/nickserver/response.rb b/lib/nickserver/response.rb
new file mode 100644
index 0000000..c55d359
--- /dev/null
+++ b/lib/nickserver/response.rb
@@ -0,0 +1,15 @@
+module Nickserver
+ class Response
+
+ attr_reader :status, :message
+
+ def initialize(status, message)
+ @status = status
+ @message = message
+ end
+
+ def content
+ "#{status} #{message}"
+ end
+ end
+end
diff --git a/lib/nickserver/server.rb b/lib/nickserver/server.rb
index 32afdae..8329406 100644
--- a/lib/nickserver/server.rb
+++ b/lib/nickserver/server.rb
@@ -90,7 +90,7 @@ module Nickserver
fetcher = if local_address?(uid)
Nickserver::Couch::FetchKey.new
else
- Nickserver::HKP::FetchKey.new
+ Nickserver::Hkp::FetchKey.new
end
fetcher.get(uid).callback {|key|
yield key