1#!/usr/bin/env ruby
2#
3# Copyright (C) 2017 Denver Gingerich <denver@ossguy.com>
4# Copyright (C) 2017 Stephen Paul Weber <singpolyma@singpolyma.net>
5#
6# This file is part of sgx-catapult.
7#
8# sgx-catapult is free software: you can redistribute it and/or modify it under
9# the terms of the GNU Affero General Public License as published by the Free
10# Software Foundation, either version 3 of the License, or (at your option) any
11# later version.
12#
13# sgx-catapult is distributed in the hope that it will be useful, but WITHOUT
14# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
16# details.
17#
18# You should have received a copy of the GNU Affero General Public License along
19# with sgx-catapult. If not, see <http://www.gnu.org/licenses/>.
20
21$stdout.sync = true
22
23puts "Soprani.ca/MMS Proxy for XMPP - Catapult\n"\
24 "==>> last commit of this version is " + `git rev-parse HEAD` + "\n"
25
26require 'em-hiredis'
27require 'em-http-request'
28require 'goliath'
29require 'uri'
30
31require_relative 'em_promise'
32
33t = Time.now
34puts "LOG %d.%09d: starting...\n\n" % [t.to_i, t.nsec]
35
36EM.next_tick do
37 REDIS = EM::Hiredis.connect
38end
39
40class WebhookHandler < Goliath::API
41 def media_request(env, user_id, token, secret, method, media_id)
42 if ![:get, :head].include?(method)
43 env.logger.debug 'ERROR: received non-HEAD/-GET request'
44 return EMPromise.reject(405)
45 end
46
47 EM::HttpRequest.new(
48 "https://api.catapult.inetwork.com/v1/users/"\
49 "#{user_id}/media/#{media_id}"
50 ).public_send(
51 method,
52 head: {
53 'Authorization' => [token, secret]
54 }
55 ).then { |http|
56 env.logger.debug "API response code to send: " +
57 http.response_header.status.to_s
58
59 case http.response_header.status
60 when 200
61 http
62 else
63 EMPromise.reject(http.response_header.status)
64 end
65 }
66 end
67
68 def response(env)
69 env.logger.debug 'ENV: ' + env.to_s
70 env.logger.debug 'path: ' + env['REQUEST_PATH']
71 env.logger.debug 'method: ' + env['REQUEST_METHOD']
72 env.logger.debug 'BODY: ' + Rack::Request.new(env).body.read
73
74 jid, media_id = env['REQUEST_PATH'].split('/')[-2..-1]
75 cred_key = "catapult_cred-#{URI.unescape(jid)}"
76
77 REDIS.lrange(cred_key, 0, 2).then { |creds|
78 if creds.length < 3
79 EMPromise.reject(404)
80 else
81 media_request(
82 env,
83 *creds,
84 env['REQUEST_METHOD'].downcase.to_sym,
85 media_id
86 )
87 end
88 }.then { |http|
89 clength = http.response_header['content-length']
90 [200, {'Content-Length' => clength}, http.response]
91 }.catch { |code|
92 if code.is_a?(Integer)
93 EMPromise.reject(code)
94 else
95 env.logger.error("ERROR: #{code.inspect}")
96 EMPromise.reject(500)
97 end
98 }.catch { |code|
99 [
100 code,
101 {'Content-Type' => 'text/plain;charset=utf-8'},
102 case code
103 when 404
104 "not found\n"
105 when 405
106 "only HEAD and GET are allowed\n"
107 else
108 "unexpected error\n"
109 end
110 ]
111 }.sync
112 end
113end