diff options
| -rw-r--r-- | lib/nickserver/couch_db/source.rb | 12 | ||||
| -rw-r--r-- | lib/nickserver/em_server.rb | 51 | ||||
| -rw-r--r-- | lib/nickserver/hkp/source.rb | 8 | ||||
| -rw-r--r-- | lib/nickserver/request_handler.rb | 85 | ||||
| -rw-r--r-- | lib/nickserver/server.rb | 107 | ||||
| -rw-r--r-- | lib/nickserver/source.rb | 13 | ||||
| -rw-r--r-- | test/unit/request_handler_test.rb | 41 | 
7 files changed, 201 insertions, 116 deletions
| diff --git a/lib/nickserver/couch_db/source.rb b/lib/nickserver/couch_db/source.rb index 874fe4f..b30fdfc 100644 --- a/lib/nickserver/couch_db/source.rb +++ b/lib/nickserver/couch_db/source.rb @@ -1,18 +1,15 @@  #  # This class allows querying couch for public keys.  # +require 'nickserver/source'  require 'nickserver/couch_db/response'  require 'nickserver/config'  module Nickserver::CouchDB -  class Source +  class Source < Nickserver::Source      VIEW = '/_design/Identity/_view/pgp_key_by_email' -    def initialize(adapter) -      @adapter = adapter -    end -      def query(nick)        adapter.get url, query: query_for(nick) do |status, body|          yield Response.new(nick, status: status, body: body) @@ -29,11 +26,6 @@ module Nickserver::CouchDB        { reduce: "false", key: "\"#{nick}\"" }      end -    def adapter -      @adapter -      # Nickserver::Adapters::Http.new(config) -    end -      attr_reader :config    end  end diff --git a/lib/nickserver/em_server.rb b/lib/nickserver/em_server.rb new file mode 100644 index 0000000..bcec4cd --- /dev/null +++ b/lib/nickserver/em_server.rb @@ -0,0 +1,51 @@ +require 'eventmachine' +silence_warnings do +  require 'evma_httpserver' +end +require 'nickserver/request_handler' + +module Nickserver +  class EmServer < EM::Connection +    include EM::HttpServer + +    def self.start(options = {}) +      EventMachine.run do +        EM.start_server options[:host], options[:port], self +      end +    end + +    def post_init +      super +      no_environment_strings +    end + +    def process_http_request +      handler.respond_to params, @http_headers +    end + +    def send_response(options = {}) +      response = EM::DelegatedHttpResponse.new(self) +      response.status = options[:status] +      response.content_type options[:content_type] +      response.content = options[:content] +      silence_warnings do +        response.send_response +      end +    end + +    private + +    def handler +      @handler ||= RequestHandler.new(self, Nickserver::Adapters::EmHttp.new) +    end + +    def params +      if @http_query_string +        CGI.parse(@http_query_string) +      elsif @http_post_content +        CGI.parse(@http_post_content) +      end +    end + +  end +end diff --git a/lib/nickserver/hkp/source.rb b/lib/nickserver/hkp/source.rb index cae3e01..8b2a62b 100644 --- a/lib/nickserver/hkp/source.rb +++ b/lib/nickserver/hkp/source.rb @@ -11,11 +11,7 @@ require "nickserver/hkp/key_info"  #  module Nickserver; module Hkp -  class Source - -    def initialize(adapter) -      @adapter = adapter -    end +  class Source < Nickserver::Source      def query(nick, &block)        search(nick) do |status, response| @@ -37,8 +33,6 @@ module Nickserver; module Hkp      protected -    attr_reader :adapter -      #      # for now, just pick the newest key.      # diff --git a/lib/nickserver/request_handler.rb b/lib/nickserver/request_handler.rb new file mode 100644 index 0000000..26b6ec1 --- /dev/null +++ b/lib/nickserver/request_handler.rb @@ -0,0 +1,85 @@ +module Nickserver +  class RequestHandler + +    def initialize(responder, adapter) +      @responder = responder +      @adapter = adapter +    end + +    def respond_to(params, headers) +      uid = get_uid_from_params(params) +      if uid.nil? +        send_not_found +      elsif uid !~ EmailAddress +        send_error("Not a valid address") +      else +        send_key(uid, headers) +      end +    rescue RuntimeError => exc +      puts "Error: #{exc}" +      puts exc.backtrace +      send_error(exc.to_s) +    end + +    protected + +    def get_uid_from_params(params) +      if params && params["address"] && params["address"].any? +        return params["address"].first +      else +        return nil +      end +    end + +    def send_key(uid, headers) +      if local_address?(uid, headers) +        source = Nickserver::CouchDB::Source.new(adapter) +      else +        source = Nickserver::Hkp::Source.new(adapter) +      end +      source.query(uid) do |response| +        send_response(status: response.status, content: response.content) +      end +    end + +    # +    # Return true if the user address is for a user of this service provider. +    # e.g. if the provider is example.org, then alice@example.org returns true. +    # +    # If 'domain' is not configured, we rely on the Host header of the HTTP request. +    # +    def local_address?(uid, headers) +      uid_domain = uid.sub(/^.*@(.*)$/, "\\1") +      if Config.domain +        return uid_domain == Config.domain +      else +        # no domain configured, use Host header +        host_header = headers.split(/\0/).grep(/^Host: /).first +        if host_header.nil? +          send_error("HTTP request must include a Host header.") +        else +          host = host_header.split(':')[1].strip.sub(/^nicknym\./, '') +          return uid_domain == host +        end +      end +    end +    def send_error(msg = "not supported") +      send_response(status: 500, content: "500 #{msg}\n") +    end + +    def send_not_found(msg = "Not Found") +      send_response(status: 404, content: "404 #{msg}\n") +    end + +    def send_response(opts = {}) +      responder.send_response default_response.merge(opts) +    end + +    def default_response +      {status: 200, content_type: 'text/plain', content: ''} +    end + +    attr_reader :responder, :adapter + +  end +end diff --git a/lib/nickserver/server.rb b/lib/nickserver/server.rb index 2453f94..174d6ac 100644 --- a/lib/nickserver/server.rb +++ b/lib/nickserver/server.rb @@ -1,9 +1,6 @@  require 'kernel_ext' -require 'eventmachine' -silence_warnings do -  require 'evma_httpserver' -end  require 'json' +require 'nickserver/em_server'  require 'nickserver/couch_db/source'  require 'nickserver/hkp/source'  require 'nickserver/adapters/em_http' @@ -15,8 +12,7 @@ require 'nickserver/adapters/em_http'  # For info on EM::HttpServer, see https://github.com/eventmachine/evma_httpserver  #  module Nickserver -  class Server < EM::Connection -    include EM::HttpServer +  class Server      #      # Starts the Nickserver. Must be run inside an EM.run block. @@ -28,105 +24,18 @@ module Nickserver      #      def self.start(opts={})        Nickserver::Config.load -      options = {host: '127.0.0.1', port: Nickserver::Config.port.to_i}.merge(opts) +      options = { +        host: '127.0.0.1', +        port: Nickserver::Config.port.to_i +      }.merge(opts) +        unless defined?(TESTING)          puts "Starting nickserver #{options[:host]}:#{options[:port]}"        end -      EM.start_server options[:host], options[:port], Nickserver::Server -    end - -    def post_init -      super -      no_environment_strings -    end -    def process_http_request -      uid = get_uid_from_request -      if uid.nil? -        send_not_found -      elsif uid !~ EmailAddress -        send_error("Not a valid address") -      else -        send_key(uid) -      end -    rescue RuntimeError => exc -      puts "Error: #{exc}" -      puts exc.backtrace -      send_error(exc.to_s) +      Nickserver::EmServer.start(options)      end -    private - -    def send_error(msg = "not supported") -      send_response(status: 500, content: "500 #{msg}\n") -    end - -    def send_not_found(msg = "Not Found") -      send_response(status: 404, content: "404 #{msg}\n") -    end - -    def send_response(opts = {}) -      options = {status: 200, content_type: 'text/plain', content: ''}.merge(opts) -      response = EM::DelegatedHttpResponse.new(self) -      response.status = options[:status] -      response.content_type options[:content_type] -      response.content = options[:content] -      silence_warnings do -        response.send_response -      end -    end - -    def get_uid_from_request -      if @http_query_string -        params = CGI.parse(@http_query_string) -      elsif @http_post_content -        params = CGI.parse(@http_post_content) -      end -      if params && params["address"] && params["address"].any? -        return params["address"].first -      else -        return nil -      end -    end - -    def send_key(uid) -      if local_address?(uid) -        source = Nickserver::CouchDB::Source.new(adapter) -      else -        source = Nickserver::Hkp::Source.new(adapter) -      end -      source.query(uid) do |response| -        send_response(status: response.status, content: response.content) -      end -    end - -    # -    # Return true if the user address is for a user of this service provider. -    # e.g. if the provider is example.org, then alice@example.org returns true. -    # -    # If 'domain' is not configured, we rely on the Host header of the HTTP request. -    # -    def local_address?(uid) -      uid_domain = uid.sub(/^.*@(.*)$/, "\\1") -      if Config.domain -        return uid_domain == Config.domain -      else -        # no domain configured, use Host header -        host_header = @http_headers.split(/\0/).grep(/^Host: /).first -        if host_header.nil? -          send_error("HTTP request must include a Host header.") -        else -          host = host_header.split(':')[1].strip.sub(/^nicknym\./, '') -          return uid_domain == host -        end -      end -    rescue # XXX what are we rescueing here? -      return false -    end - -    def adapter -      @adapter ||= Nickserver::Adapters::EmHttp.new -    end    end  end diff --git a/lib/nickserver/source.rb b/lib/nickserver/source.rb new file mode 100644 index 0000000..b8135da --- /dev/null +++ b/lib/nickserver/source.rb @@ -0,0 +1,13 @@ +module Nickserver +  class Source + +    def initialize(adapter) +      @adapter = adapter +    end + +    protected + +    attr_reader :adapter + +  end +end diff --git a/test/unit/request_handler_test.rb b/test/unit/request_handler_test.rb new file mode 100644 index 0000000..c9d316f --- /dev/null +++ b/test/unit/request_handler_test.rb @@ -0,0 +1,41 @@ +require 'test_helper' +require 'nickserver/request_handler' + +class Nickserver::RequestHandlerTest < Minitest::Test + +  def test_empty_query +    handle +    assert_response status: 404, content: "404 Not Found\n" +  end + +  def test_invalid_query +    handle address: ['asdf'] +    assert_response status: 500, content: "500 Not a valid address\n" +  end + +  protected + +  def handle(params = {}, headers = {}) +    @params = Hash[ params.map{ |k,v| [k.to_s, v] } ] +    @headers = headers +  end + +  def assert_response(args) +    args[:content_type] ||= 'text/plain' +    responder.expect :send_response, nil, [args] +    handler.respond_to @params, @headers +    responder.verify +  end + +  def handler +    Nickserver::RequestHandler.new responder, adapter +  end + +  def responder +    @responder ||= Minitest::Mock.new +  end + +  def adapter +    @adapter ||= Minitest::Mock.new +  end +end | 
