summaryrefslogtreecommitdiff
path: root/lib/nickserver/request_handler.rb
blob: 239ac5f9d38f10e9beddb5efa78a73922455d7b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
require 'nickserver/hkp/source'
require 'nickserver/couch_db/source'

module Nickserver
  class RequestHandler

    class Request
      def initialize(params, headers)
        @params = params || {}
        @headers = headers
      end

      def email
        param("address")
      end

      def fingerprint
        param("fingerprint")
      end

      def domain
        host_header = headers['Host']
        raise MissingHostHeader if host_header.nil?
        host_header.split(':')[0].strip.sub(/^nicknym\./, '')
      end

      protected

      def param(key)
        params[key] && params[key].first
      end

      attr_reader :params, :headers
    end

    def initialize(responder)
      @responder = responder
    end

    def respond_to(params, headers)
      request = Request.new params, headers
      response = handle request
      send_response response.status, response.content
    end

    protected

    def handle(request)
      handler = handler_for_request request
      handler.call request
    rescue RuntimeError => exc
      puts "Error: #{exc}"
      puts exc.backtrace
      ErrorResponse.new(exc.to_s)
    end

    def handler_for_request(request)
      if request.email
        EmailHandler.new
      elsif request.fingerprint
        FingerprintHandler.new
      else
        Proc.new { Nickserver::Response.new(404, "Not Found\n") }
      end
    end

    class EmailHandler

      def call(request)
        email = EmailAddress.new(request.email)
        if email.invalid?
          ErrorResponse.new("Not a valid address")
        else
          send_key(email, request)
        end
      end

      protected

      def send_key(email, request)
        if local_address?(email, request)
          source = Nickserver::CouchDB::Source.new
        else
          source = Nickserver::Hkp::Source.new
        end
        source.query(email)
      rescue MissingHostHeader
        ErrorResponse.new("HTTP request must include a Host header.")
      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?(email, request)
        email.domain?(Config.domain || request.domain)
      end
    end

    class FingerprintHandler

      def call(request)
        fingerprint = request.fingerprint
        if fingerprint.length == 40 && !fingerprint[/\H/]
          source = Nickserver::Hkp::Source.new
          source.get_key_by_fingerprint(fingerprint)
        else
          ErrorResponse.new('Fingerprint invalid: ' + fingerprint)
        end
      end

    end

    class ErrorResponse < Nickserver::Response
      def initialize(message)
        @status = 500
        @message = message + "\n"
      end
    end

    def send_response(status = 200, content = '')
      responder.respond status, content
    end

    attr_reader :responder

    class MissingHostHeader < StandardError
    end
  end
end