mpx-catapult.rb

  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
 20puts "Soprani.ca/MMS Proxy for XMPP - Catapult        v0.003"
 21
 22require 'goliath'
 23require 'net/http'
 24require 'redis/connection/hiredis'
 25require 'uri'
 26
 27if ARGV.size != 3 then
 28	puts "Usage: mpx-catapult.rb <http_listen_port> " +
 29		"<redis_hostname> <redis_port>"
 30	exit 0
 31end
 32
 33class WebhookHandler < Goliath::API
 34	def response(env)
 35		puts 'ENV: ' + env.to_s
 36		puts 'path: ' + env['REQUEST_PATH']
 37		puts 'method: ' + env['REQUEST_METHOD']
 38		puts 'BODY: ' + Rack::Request.new(env).body.read
 39
 40		cred_key = "catapult_cred-"+env['REQUEST_PATH'].split('/', 3)[1]
 41
 42		# TODO: connect at start of program instead
 43		conn = Hiredis::Connection.new
 44		begin
 45			conn.connect(ARGV[1], ARGV[2].to_i)
 46		rescue => e
 47			puts 'ERROR: Redis connection failed: ' + e.inspect
 48			return [500, {'Content-Type' => 'text/plain'},
 49				e.inspect]
 50		end
 51
 52		conn.write ["EXISTS", cred_key]
 53		if conn.read == 0
 54			conn.disconnect
 55
 56			puts 'ERROR: invalid path rqst: ' + env['REQUEST_PATH']
 57			return [404, {'Content-Type' => 'text/plain'},
 58				'not found']
 59		end
 60
 61		conn.write ["LRANGE", cred_key, 0, 3]
 62		# we don't actually use users_num, but easier to read so left in
 63		user_id, api_token, api_secret, users_num = conn.read
 64		conn.disconnect
 65
 66		uri = URI.parse('https://api.catapult.inetwork.com')
 67		http = Net::HTTP.new(uri.host, uri.port)
 68		http.use_ssl = true
 69		request = ''
 70		if env['REQUEST_METHOD'] == 'GET'
 71			request = Net::HTTP::Get.new('/v1/users/' + user_id +
 72				'/media/' +env['REQUEST_PATH'].split('/', 3)[2])
 73		elsif env['REQUEST_METHOD'] == 'HEAD'
 74			request = Net::HTTP::Head.new('/v1/users/' + user_id +
 75				'/media/' +env['REQUEST_PATH'].split('/', 3)[2])
 76		else
 77			puts 'ERROR: received non-HEAD/-GET request'
 78			return [500, {'Content-Type' => 'text/plain'},
 79				e.inspect]
 80		end
 81		request.basic_auth api_token, api_secret
 82		response = http.request(request)
 83
 84		puts 'API response to send: ' + response.to_s + ' with code ' +
 85			response.code + ', body <omitted_due_to_length>'
 86
 87		if response.code != '200'
 88			puts 'ERROR: unexpected return code ' + response.code
 89
 90			if response.code == '404'
 91				return [404, {'Content-Type' => 'text/plain'},
 92					'not found']
 93			end
 94
 95			return [response.code, {'Content-Type' => 'text/plain'},
 96				'unexpected error']
 97		end
 98
 99		# TODO: maybe need to reflect more headers (multi-part?)
100		[200, {'Content-Length' => response['content-length']},
101			response.body]
102	end
103end
104
105EM.run do
106	server = Goliath::Server.new('0.0.0.0', ARGV[0].to_i)
107	server.api = WebhookHandler.new
108	server.app = Goliath::Rack::Builder.build(server.api.class, server.api)
109	server.logger = Log4r::Logger.new('goliath')
110	server.logger.add(Log4r::StdoutOutputter.new('console'))
111	server.logger.level = Log4r::INFO
112	server.start
113end