# frozen_string_literal: true require "blather/client" require "dhall" require_relative "em_promise" CONFIG = Dhall::Coder.load(ARGV[0]) def node(name, parent, ns: nil) Niceogiri::XML::Node.new( name, parent.document, ns || parent.class.registered_ns ) end def escape_jid(localpart) # TODO: proper XEP-0106 Sec 4.3, ie. pre-escaped localpart .to_s .gsub("\\", "\\\\5c") .gsub(" ", "\\\\20") .gsub("\"", "\\\\22") .gsub("&", "\\\\26") .gsub("'", "\\\\27") .gsub("/", "\\\\2f") .gsub(":", "\\\\3a") .gsub("<", "\\\\3c") .gsub(">", "\\\\3e") .gsub("@", "\\\\40") end def unescape_jid(localpart) localpart .to_s .gsub("\\20", " ") .gsub("\\22", "\"") .gsub("\\26", "&") .gsub("\\27", "'") .gsub("\\2f", "/") .gsub("\\3a", ":") .gsub("\\3c", "<") .gsub("\\3e", ">") .gsub("\\40", "@") .gsub("\\5c", "\\") end def proxy_jid(jid) Blather::JID.new( escape_jid(jid.stripped), CONFIG["component"]["jid"], jid.resource ) end def unproxy_jid(jid) parsed = Blather::JID.new(unescape_jid(jid.node)) Blather::JID.new(parsed.node, parsed.domain, jid.resource) end class IBR < Blather::Stanza::Iq::Query register :ibr, nil, "jabber:iq:register" def registered=(reg) query.at_xpath("./ns:registered", ns: self.class.registered_ns)&.remove query << node("registered", self) if reg end def registered? !!query.at_xpath("./ns:registered", ns: self.class.registered_ns) end [ "instructions", "username", "nick", "password", "name", "first", "last", "last", "email", "address", "city", "state", "zip", "phone", "url", "date" ].each do |tag| define_method("#{tag}=") do |v| query.at_xpath("./ns:#{tag}", ns: self.class.registered_ns)&.remove query << (i = node(tag, self)) i.content = v end define_method(tag) do query.at_xpath("./ns:#{tag}", ns: self.class.registered_ns)&.content end end end Blather::DSL.append_features(self.class) when_ready do EM.add_periodic_timer(3600) do ping = Blather::Stanza::Iq::Ping.new(:get, CONFIG["server"]["host"]) ping.from = CONFIG["component"]["jid"] self << ping end end # workqueue_count MUST be 0 or else Blather uses threads! setup( CONFIG["component"]["jid"], CONFIG["component"]["secret"], CONFIG["server"]["host"], CONFIG["server"]["port"], nil, nil, workqueue_count: 0 ) message :error? do |m| puts "MESSAGE ERROR: #{m.inspect}" end ibr :get? do |iq| fwd = iq.dup fwd.from = proxy_jid(iq.from) fwd.to = Blather::JID.new(nil, CONFIG["sgx"], iq.to.resource) fwd.id = "JMPGET%#{iq.id}" self << fwd end ibr :result? do |iq| if iq.id.start_with?("JMPGET") reply = iq.reply reply.instructions = "Please enter the phone number you wish to register with JMP.chat" reply.registered = iq.registered? reply.phone = iq.phone else reply = iq.dup end reply.id = iq.id.sub(/JMP[GS]ET%/, "") reply.from = Blather::JID.new( nil, CONFIG["component"]["jid"], iq.from.resource ) reply.to = unproxy_jid(iq.to) self << reply end ibr :error? do |iq| reply = iq.dup reply.id = iq.id.sub(/JMP[GS]ET%/, "") reply.from = Blather::JID.new( nil, CONFIG["component"]["jid"], iq.from.resource ) reply.to = unproxy_jid(iq.to) self << reply end ibr :set? do |iq| fwd = iq.dup CONFIG["creds"].each do |k, v| fwd.public_send("#{k}=", v) end fwd.from = proxy_jid(iq.from) fwd.to = Blather::JID.new(nil, CONFIG["sgx"], iq.to.resource) fwd.id = "JMPSET%#{iq.id}" self << fwd end