summaryrefslogtreecommitdiff
path: root/application.rb
blob: 6e700fdfd7fd2905250210a312c9226db2a74596 (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
require 'json'
require 'net/http'
require 'uri'
require 'base64'

USER = "pdp8"
WWW_DOMAIN = "pdp8.info"
WWW_URL = "https://#{WWW_DOMAIN}"
SOCIAL_DOMAIN = "social.#{WWW_DOMAIN}"

ACCOUNT = "#{USER}@#{SOCIAL_DOMAIN}"
SOCIAL_URL = "https://#{SOCIAL_DOMAIN}"
ACTOR = URI.join(SOCIAL_URL, USER)

MATRIX = "@#{USER}:matrix.#{WWW_DOMAIN}"

OUTBOX = File.join(File.dirname(__FILE__), "outbox")
INBOX = File.join(File.dirname(__FILE__), "inbox")

class Application
  def call(env)
    code = 404
    type = "application/activity+json"

    case env['REQUEST_METHOD']

    when 'POST'
      case env["REQUEST_URI"]

      when "/inbox" # receive from server
        if verify(env)
          input = JSON.parse(env["rack.input"].gets)
          # p input["type"]
          code = 200
          response = "OK"
        else
          code = 401
          response = "not verified"
        end

      when "/outbox"
        input = JSON.parse(env["rack.input"].gets)
        case input["type"]
        when "Create"
        end

      end

    when 'GET'

      case env["REQUEST_URI"]

      when "/.well-known/webfinger?resource=acct:#{ACCOUNT}"
        type = "application/jrd+json"
        response = File.read("webfinger")
        code = 200

      when "/#{USER}"
        response = File.read("pdp8")
        code = 200

      when "/outbox"
        response = ordered_collection OUTBOX
        code = 200

      when "/inbox"
        type = "application/activity+json"
        response = ordered_collection INBOX
        code = 200

        # when "/following"
        # when "/followers"
        # when "/liked"
      end

    end
    [code, { "Content-Type" => type }, [response]]
  end

  def ordered_collection dir
    posts = Dir[File.join(dir, "*.json")].sort.reverse.collect { |f| p f; JSON.parse(File.read f) }
    {
      "@context" => "https://www.w3.org/ns/activitystreams",
      "summary" => "pdp8 outbox",
      "type" => "OrderedCollection",
      "totalItems" => posts.size,
      "orderedItems" => posts,
    }.to_json
  end

  def verify(env)
    begin
      signature_header = {}
      env["HTTP_SIGNATURE"].split(',').each do |pair|
        k, v = pair.split('=')
        signature_header[k] = v.gsub('"', '')
      end
      key_id    = signature_header['keyId']
      headers   = signature_header['headers']
      signature = Base64.urlsafe_decode64(signature_header['signature'].encode("ascii-8bit"))
      uri = URI(key_id)
      res = Net::HTTP.get_response(uri)
      actor = JSON.parse(res.body)
      key = OpenSSL::PKey::RSA.new(actor['publicKey']['publicKeyPem'])

      comparison_string = headers.split(' ').map do |signed_header_name|
        if signed_header_name == '(request-target)'
          '(request-target): post /inbox'
        else
          "#{signed_header_name}: #{env["HTTP_" + signed_header_name.upcase]}"
        end
      end.join("\n")
      if key.verify(OpenSSL::Digest::SHA256.new, signature, comparison_string.encode("ascii-8bit"))
        true
      else
        false
      end
    rescue
      false
    end
  end
end