sgx-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
 20require 'blather/client/dsl'
 21
 22if ARGV.size != 4 then
 23	puts "Usage: sgx-catapult.rb <component_jid> <component_password> " +
 24		"<server_hostname> <server_port>"
 25	exit 0
 26end
 27
 28module SGXcatapult
 29	extend Blather::DSL
 30
 31	def self.run
 32		client.run
 33	end
 34
 35	setup ARGV[0], ARGV[1], ARGV[2], ARGV[3]
 36
 37	message :chat?, :body do |m|
 38		begin
 39			puts "#{m.from.to_s} -> #{m.to.to_s} #{m.body}"
 40			msg = Blather::Stanza::Message.new(m.from, 'thx for "' +
 41				m.body + '"')
 42			msg.from = m.to
 43			write_to_stream msg
 44		rescue => e
 45			# TODO: do something better with this info
 46			say m.from, e.inspect
 47		end
 48	end
 49
 50	iq do |i|
 51		puts "IQ: #{i.inspect}"
 52
 53		if i.type == :set
 54			puts "received set, likely for jabber:iq:register"
 55
 56			# TODO: resilient error handling; what if no query node?
 57
 58			qn = i.children.find { |v| v.element_name == "query" }
 59			# TODO: add below check - as-written has unmatched end
 60	i		#if qn.namespace.href != 'jabber:iq:register'
 61			#	# TODO: error
 62			#	puts "weird xmlns: " + qn.namespace.href
 63			#	next
 64			#end
 65
 66			xn = qn.children.find { |v| v.element_name == "x" }
 67
 68			if xn.nil?
 69				puts "id: " + qn.children.find {
 70					|v| v.element_name == "nick" }
 71				puts "token: " + qn.children.find {
 72					|v| v.element_name == "username" }
 73				puts "secret: " + qn.children.find {
 74					|v| v.element_name == "password" }
 75				puts "phone num: " + qn.children.find {
 76					|v| v.element_name == "phone" }
 77				next
 78			end
 79
 80			for field in xn.children
 81				if field.element_name == "field"
 82					val = field.children.find { |v|
 83						v.element_name == "value" }
 84
 85					case field['var']
 86					when 'nick'
 87						puts "id: " + val.text
 88					when 'username'
 89						puts "token: " + val.text
 90					when 'password'
 91						puts "secret: " + val.text
 92					when 'phone'
 93						puts "phone num: " + val.text
 94					when 'FORM_TYPE'
 95						puts "FORM_TYPE: " + val.text
 96					else
 97						# TODO: error
 98						puts "weird var: " +field['var']
 99					end
100				end
101			end
102
103			# success (for now)
104			msg = Blather::Stanza::Iq.new
105			msg.id = i.id
106			msg.to = i.from
107			msg.type = 'result'
108
109			puts "RESPONSE3: #{msg.inspect}"
110			write_to_stream msg
111			puts "SENT"
112
113			# TODO: implement this (verify/save data, return result)
114			next
115		end
116
117		query_node = i.children.find { |v| v.element_name == "query" }
118		if query_node.namespace.href ==
119			'http://jabber.org/protocol/disco#items'
120
121			msg = Blather::Stanza::Iq::DiscoItems.new
122			msg.id = i.id
123			msg.to = i.from
124			msg.type = 'result'
125
126			puts "RESPONSE0: #{msg.inspect}"
127			write_to_stream msg
128			puts "SENT"
129		elsif query_node.namespace.href ==
130			'http://jabber.org/protocol/disco#info'
131
132			msg = Blather::Stanza::Iq::DiscoInfo.new
133			msg.id = i.id
134			msg.to = i.from
135			msg.type = 'result'
136
137			msg.identities = [{:name =>
138				'Soprani.ca Gateway to XMPP - Catapult',
139				:type => 'sms-ctplt', :category => 'gateway'}]
140			msg.features = ["jabber:iq:register",
141				"jabber:iq:gateway", "jabber:iq:private",
142				"http://jabber.org/protocol/disco#info",
143				"http://jabber.org/protocol/commands",
144				"http://jabber.org/protocol/muc"]
145			puts "RESPONSE1: #{msg.inspect}"
146			write_to_stream msg
147			puts "SENT"
148		elsif query_node.namespace.href == 'jabber:iq:register'
149			orig = Blather::Stanza::Iq.new
150			orig.id = i.id
151			orig.to = i.from
152			orig.type = 'result'
153
154			msg = Nokogiri::XML::Node.new 'query',orig.document
155			msg['xmlns'] = 'jabber:iq:register'
156			n1 = Nokogiri::XML::Node.new 'instructions',msg.document
157			n1.content= "Enter the information from your Account " +
158				"page as well as the Phone Number\nin your " +
159				"account you want to use (ie. '+12345678901')" +
160				".\nUser Id is nick, API Token is username, " +
161				"API Secret is password, Phone Number is phone"+
162				".\n\nThe source code for this gateway is at " +
163				"https://github.com/ossguy/sgx-catapult ." +
164				"\nCopyright (C) 2017  Denver Gingerich, " +
165				"licensed under AGPLv3+."
166			n2 = Nokogiri::XML::Node.new 'nick',msg.document
167			n3 = Nokogiri::XML::Node.new 'username',msg.document
168			n4 = Nokogiri::XML::Node.new 'password',msg.document
169			n5 = Nokogiri::XML::Node.new 'phone',msg.document
170			msg.add_child(n1)
171			msg.add_child(n2)
172			msg.add_child(n3)
173			msg.add_child(n4)
174			msg.add_child(n5)
175
176			x = Nokogiri::XML::Node.new 'x',orig.document
177			x['xmlns'] = 'jabber:x:data'
178			x['type'] = 'form'
179			msg.add_child(x)
180
181			title = Nokogiri::XML::Node.new 'title',orig.document
182			title.content= 'Register for ' +
183				'Soprani.ca Gateway to XMPP - Catapult'
184			x.add_child(title)
185
186			instr = Nokogiri::XML::Node.new 'instructions',
187				orig.document
188			instr.content= "Enter the details from your Account " +
189				"page as well as the Phone Number\nin your " +
190				"account you want to use (ie. '+12345678901')" +
191				".\n\nThe source code for this gateway is at " +
192				"https://github.com/ossguy/sgx-catapult ." +
193				"\nCopyright (C) 2017  Denver Gingerich, " +
194				"licensed under AGPLv3+."
195			x.add_child(instr)
196
197			f1 = Nokogiri::XML::Node.new 'field',orig.document
198			f1['type'] = 'hidden'
199			f1['var'] = 'FORM_TYPE'
200			v1 = Nokogiri::XML::Node.new 'value',orig.document
201			v1.content= 'jabber:iq:register'
202			f1.add_child(v1)
203			x.add_child(f1)
204
205			f2 = Nokogiri::XML::Node.new 'field',orig.document
206			f2['type'] = 'text-single'
207			f2['label'] = 'User Id'
208			f2['var'] = 'nick'
209			v2 = Nokogiri::XML::Node.new 'required',orig.document
210			f2.add_child(v2)
211			x.add_child(f2)
212
213			f3 = Nokogiri::XML::Node.new 'field',orig.document
214			f3['type'] = 'text-single'
215			f3['label'] = 'API Token'
216			f3['var'] = 'username'
217			v3 = Nokogiri::XML::Node.new 'required',orig.document
218			f3.add_child(v3)
219			x.add_child(f3)
220
221			f4 = Nokogiri::XML::Node.new 'field',orig.document
222			f4['type'] = 'text-private'
223			f4['label'] = 'API Secret'
224			f4['var'] = 'password'
225			v4 = Nokogiri::XML::Node.new 'required',orig.document
226			f4.add_child(v4)
227			x.add_child(f4)
228
229			f5 = Nokogiri::XML::Node.new 'field',orig.document
230			f5['type'] = 'text-single'
231			f5['label'] = 'Phone Number'
232			f5['var'] = 'phone'
233			v5 = Nokogiri::XML::Node.new 'required',orig.document
234			f5.add_child(v5)
235			x.add_child(f5)
236
237			orig.add_child(msg)
238			puts "RESPONSE2: #{orig.inspect}"
239			write_to_stream orig
240			puts "SENT"
241		end
242	end
243
244	subscription(:request?) do |s|
245		# TODO: fix these - they don't actual work; write does not exist
246		#write(s.approve!)
247		#write(s.request!)
248	end
249end
250
251[:INT, :TERM].each do |sig|
252	trap(sig) {
253		puts 'Shutting down gateway...'
254		SGXcatapult.shutdown
255		puts 'Gateway has terminated.'
256
257		EM.stop
258	}
259end
260
261EM.run do
262	SGXcatapult.run
263end