1#!/usr/bin/env ruby
2#
3# Copyright (C) 2017 Denver Gingerich <denver@ossguy.com>
4#
5# This file is part of sgx-catapult.
6#
7# sgx-catapult is free software: you can redistribute it and/or modify it under
8# the terms of the GNU Affero General Public License as published by the Free
9# Software Foundation, either version 3 of the License, or (at your option) any
10# later version.
11#
12# sgx-catapult is distributed in the hope that it will be useful, but WITHOUT
13# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
15# details.
16#
17# You should have received a copy of the GNU Affero General Public License along
18# with sgx-catapult. If not, see <http://www.gnu.org/licenses/>.
19
20$stdout.sync = true
21
22puts "Soprani.ca/MMS Proxy for XMPP - Catapult\n"\
23 "==>> last commit of this version is " + `git rev-parse HEAD` + "\n"
24
25require 'goliath'
26require 'net/http'
27require 'redis/connection/hiredis'
28require 'uri'
29require 'webrick'
30
31if ARGV.size != 3
32 puts "Usage: mpx-catapult.rb <http_listen_port> "\
33 "<redis_hostname> <redis_port>"
34 exit 0
35end
36
37t = Time.now
38puts "LOG %d.%09d: starting...\n\n" % [t.to_i, t.nsec]
39
40class WebhookHandler < Goliath::API
41 def response(env)
42 puts 'ENV: ' + env.to_s
43 puts 'path: ' + env['REQUEST_PATH']
44 puts 'method: ' + env['REQUEST_METHOD']
45 puts 'BODY: ' + Rack::Request.new(env).body.read
46
47 cred_key = "catapult_cred-" + WEBrick::HTTPUtils.unescape(
48 env['REQUEST_PATH'].split('/', 3)[1])
49
50 # TODO: connect at start of program instead
51 conn = Hiredis::Connection.new
52 begin
53 conn.connect(ARGV[1], ARGV[2].to_i)
54 rescue => e
55 puts 'ERROR: Redis connection failed: ' + e.inspect
56 return [
57 500,
58 {'Content-Type' => 'text/plain'},
59 e.inspect
60 ]
61 end
62
63 conn.write ["EXISTS", cred_key]
64 if conn.read == 0
65 conn.disconnect
66
67 puts 'ERROR: invalid path rqst: ' + env['REQUEST_PATH']
68 return [
69 404,
70 {'Content-Type' => 'text/plain'},
71 'not found'
72 ]
73 end
74
75 conn.write ["LRANGE", cred_key, 0, 2]
76 user_id, api_token, api_secret = conn.read
77 conn.disconnect
78
79 uri = URI.parse('https://api.catapult.inetwork.com')
80 http = Net::HTTP.new(uri.host, uri.port)
81 http.use_ssl = true
82 request = ''
83 if env['REQUEST_METHOD'] == 'GET'
84 request = Net::HTTP::Get.new('/v1/users/' + user_id +
85 '/media/' +env['REQUEST_PATH'].split('/', 3)[2])
86 elsif env['REQUEST_METHOD'] == 'HEAD'
87 request = Net::HTTP::Head.new('/v1/users/' + user_id +
88 '/media/' +env['REQUEST_PATH'].split('/', 3)[2])
89 else
90 puts 'ERROR: received non-HEAD/-GET request'
91 return [
92 500,
93 {'Content-Type' => 'text/plain'},
94 e.inspect
95 ]
96 end
97 request.basic_auth api_token, api_secret
98 response = http.request(request)
99
100 puts 'API response to send: ' + response.to_s + ' with code ' +
101 response.code + ', body <omitted_due_to_length>'
102
103 if response.code != '200'
104 puts 'ERROR: unexpected return code ' + response.code
105
106 if response.code == '404'
107 return [
108 404,
109 {'Content-Type' => 'text/plain'},
110 'not found'
111 ]
112 end
113
114 return [
115 response.code,
116 {'Content-Type' => 'text/plain'},
117 'unexpected error'
118 ]
119 end
120
121 # TODO: maybe need to reflect more headers (multi-part?)
122 [200, {'Content-Length' => response['content-length']},
123 response.body]
124 end
125end
126
127EM.run do
128 server = Goliath::Server.new('0.0.0.0', ARGV[0].to_i)
129 server.api = WebhookHandler.new
130 server.app = Goliath::Rack::Builder.build(server.api.class, server.api)
131 server.logger = Log4r::Logger.new('goliath')
132 server.logger.add(Log4r::StdoutOutputter.new('console'))
133 server.logger.level = Log4r::INFO
134 server.start
135end