summaryrefslogtreecommitdiff
path: root/bin/api
blob: 1a47d14d4790885599eb0d37dd2baa2fcba9552e (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
#!/usr/bin/env ruby

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'

  gem "erb", "~> 4.0"
  gem "grpc", "~> 1.0"
  gem "json", "~> 2.0"
  gem "logger", "~> 1.0"
  gem "rack", "~> 3.0"
  gem "rackup", "~> 2.0"
  gem "securerandom", "~> 0.1"
  gem "webrick", "~> 1.0"
end

lib_path = Pathname.new(__FILE__).parent.parent.join('lib').realpath.to_s
$LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)

require 'authx'

GRPC.logger = Logger.new($stderr, level: :debug)
$scheme = ENV.fetch("SCHEME", "http")
$port = ENV.fetch("PORT", 8284).to_i
$host = ENV.fetch("HOST", "localhost:#{$port}")

class Project
  class << self
    def all
      @projects ||= []
    end

    def create!(attributes)
      new({ id: SecureRandom.uuid }.merge(attributes)).tap do |item|
        all << item
      end
    end
  end

  def initialize(attributes = {})
    @attributes = attributes
  end

  def to_h
    @attributes
  end
end

class API
  def call(env)
    request = Rack::Request.new(env)
    path = env['PATH_INFO']
    case env['REQUEST_METHOD']
    when 'GET'
      case path
      when '/projects.json'
        return json_ok(Project.all.map(&:to_h))
      else
        return json_not_found
      end
    when 'POST'
      case path
      when "/projects"
        if authorized?(request, :create_project)
          return json_created(Project.create!(JSON.parse(request.body.read, symbolize_names: true)))
        else
          return json_unauthorized(:create_project)
        end
      else
        return json_not_found
      end
    end
    json_not_found
  end

  private

  def authorized?(request, permission)
    # TODO:: Check the JWT for the appropriate claim
    # Connect to the Authz RPC endpoint Ability.allowed?(subject, permission, resource)
    client = ::Authx::Rpc::Ability::Stub.new('localhost:50051', :this_channel_is_insecure) # TODO:: memorize client
    reply = client.allowed(::Authx::Rpc::AllowRequest.new(subject: "", permission: permission, resource: ""))
    puts "***" * 10
    puts reply.inspect
    puts "***" * 10
    reply&.result
  end

  def json_not_found
    http_response(code: 404)
  end

  def json_ok(body)
    http_response(code: 200, body: JSON.pretty_generate(body))
  end

  def json_created(body)
    http_response(code: 201, body: JSON.pretty_generate(body.to_h))
  end

  def json_unauthorized(permission)
    http_response(code: 401, body: JSON.pretty_generate({
      error: {
        code: 401,
        message: "`#{permission}` is required",
      }
    }))
  end

  def http_response(code:, headers: { 'Content-Type' => 'application/json' }, body: nil)
    [
      code,
      headers.merge({ 'X-Backend-Server' => 'REST' }),
      [body].compact
    ]
  end
end

if __FILE__ == $0
  app = Rack::Builder.new do
    use Rack::CommonLogger
    use Rack::Reloader
    run API.new
  end.to_app

  Rackup::Server.start(app: app, Port: $port)
end