From cf71abde47df7f827431b014c44b6db9c80f4d9a Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Wed, 29 Jun 2022 11:48:12 -0500 Subject: [PATCH 1/2] Refactor IBR set code to use the IBR helpers --- sgx-bwmsgsv2.rb | 62 +++++++++++------------------------------- test/test_component.rb | 61 +++++++++++++++++++++++++++++++++++++++++ test/test_helper.rb | 13 +++++++++ 3 files changed, 90 insertions(+), 46 deletions(-) diff --git a/sgx-bwmsgsv2.rb b/sgx-bwmsgsv2.rb index 2929832af8f8241bed049aa9968639607380be39..6a1f89000a6edfd05ab07661936931c4f953fdc4 100755 --- a/sgx-bwmsgsv2.rb +++ b/sgx-bwmsgsv2.rb @@ -524,58 +524,28 @@ module SGXbwmsgsv2 } end - def self.creds_from_registration_query(qn) - xn = qn.children.find { |v| v.element_name == "x" } - - if xn - xn.children.each_with_object({}) do |field, h| - next if field.element_name != "field" - - val = field.children.find { |v| - v.element_name == "value" - } - - case field['var'] - when 'nick' - h[:user_id] = val.text - when 'username' - h[:api_token] = val.text - when 'password' - h[:api_secret] = val.text - when 'phone' - h[:phone_num] = val.text - else - # TODO: error - puts "?: #{field['var']}" - end - end + def self.creds_from_registration_query(i) + if i.query.find_first("./ns:x", ns: "jabber:x:data") + [ + i.form.field("nick")&.value, + i.form.field("username")&.value, + i.form.field("password")&.value, + i.form.field("phone")&.value + ] else - qn.children.each_with_object({}) do |field, h| - case field.element_name - when "nick" - h[:user_id] = field.text - when "username" - h[:api_token] = field.text - when "password" - h[:api_secret] = field.text - when "phone" - h[:phone_num] = field.text - end - end - end.values_at(:user_id, :api_token, :api_secret, :phone_num) + [i.nick, i.username, i.password, i.phone] + end end - def self.process_registration(i, qn) - EMPromise.resolve( - qn.children.find { |v| v.element_name == "remove" } - ).then { |rn| - if rn + def self.process_registration(i) + EMPromise.resolve(nil).then { + if i.remove? @registration_repo.delete(i.from).then do write_to_stream i.reply EMPromise.reject(:done) end else - creds_from_registration_query(qn) + creds_from_registration_query(i) end }.then { |user_id, api_token, api_secret, phone_num| if phone_num && phone_num[0] == '+' @@ -690,12 +660,12 @@ module SGXbwmsgsv2 return orig end - iq '/iq/ns:query', ns: 'jabber:iq:register' do |i, qn| + ibr do |i| puts "IQ: #{i.inspect}" case i.type when :set - process_registration(i, qn) + process_registration(i) when :get bare_jid = i.from.stripped @registration_repo.find(bare_jid).then { |creds| diff --git a/test/test_component.rb b/test/test_component.rb index 1c6864dc17750a50fef903080d070714f7c0dcd8..35beb76cdc259216d15e9694b54a97bed1d94c4f 100644 --- a/test/test_component.rb +++ b/test/test_component.rb @@ -16,6 +16,7 @@ class ComponentTest < Minitest::Test @written << s end + REDIS.reset! REDIS.set("catapult_cred-test@example.com", [ 'account', 'user', 'password', '+15550000000' ]) @@ -265,4 +266,64 @@ class ComponentTest < Minitest::Test ) end em :test_ibr_conflict + + def test_ibr_remove + iq = Blather::Stanza::Iq::IBR.new(:set, "component") + iq.from = "test@example.com" + iq.remove! + process_stanza(iq) + + refute REDIS.get("catapult_cred-test@example.com").sync + + assert_equal 1, written.length + + stanza = Blather::XMPPNode.parse(written.first.to_xml) + assert stanza.result? + end + em :test_ibr_remove + + def test_ibr_form + stub_request( + :get, + "https://messaging.bandwidth.com/api/v2/users/acct/media" + ).with(basic_auth: ["user", "pw"]).to_return(status: 200, body: "[]") + + iq = Blather::Stanza::Iq::IBR.new(:set, "component") + iq.from = "formuser@example.com" + form = Blather::Stanza::X.find_or_create(iq.query) + form.fields = [ + { + var: "nick", + value: "acct" + }, + { + var: "username", + value: "user" + }, + { + var: "password", + value: "pw" + }, + { + var: "phone", + value: "+15551234567" + } + ] + process_stanza(iq) + + assert_equal( + ["acct", "user", "pw", "+15551234567"], + REDIS.get("catapult_cred-formuser@example.com").sync + ) + + assert_equal( + "formuser@example.com", + REDIS.get("catapult_jid-+15551234567").sync + ) + + assert_equal 1, written.length + stanza = Blather::XMPPNode.parse(written.first.to_xml) + assert stanza.result? + end + em :test_ibr_form end diff --git a/test/test_helper.rb b/test/test_helper.rb index acde8af58ac4c0ed2968f69b9469af8442b3a39a..0b4d5bfd989c4a874f42509f0e86b129f954b992 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -38,6 +38,10 @@ class FakeRedis @values = values end + def reset!(values={}) + @values = values + end + def set(key, value, *) @values[key] = value EMPromise.resolve("OK") @@ -47,6 +51,10 @@ class FakeRedis set(key, value) end + def del(*keys) + keys.each { |key| @values.delete(key) } + end + def mget(*keys) EMPromise.all(keys.map(&method(:get))) end @@ -109,6 +117,11 @@ class FakeRedis def lrange(key, sindex, eindex) get(key).then { |v| v ? v[sindex..eindex] : [] } end + + def rpush(key, *values) + @values[key] ||= [] + values.each { |v| @values[key].push(v) } + end end REDIS = FakeRedis.new From e14400228ae7692d5069581f9b9e18b2c2cc787c Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Wed, 29 Jun 2022 11:58:28 -0500 Subject: [PATCH 2/2] Refactor IBR get/form to use the IBR helpers --- sgx-bwmsgsv2.rb | 43 +++++++++++------------------------------- test/test_component.rb | 22 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/sgx-bwmsgsv2.rb b/sgx-bwmsgsv2.rb index 6a1f89000a6edfd05ab07661936931c4f953fdc4..a4f25ecc65dc298c1b1270f5487c62e8e189dc0c 100755 --- a/sgx-bwmsgsv2.rb +++ b/sgx-bwmsgsv2.rb @@ -590,22 +590,10 @@ module SGXbwmsgsv2 end def self.registration_form(orig, existing_number=nil) - msg = Nokogiri::XML::Node.new 'query', orig.document - msg['xmlns'] = 'jabber:iq:register' - - if existing_number - msg.add_child( - Nokogiri::XML::Node.new( - 'registered', msg.document - ) - ) - end + orig.registered = !!existing_number # TODO: update "User Id" x2 below (to "accountId"?), and others? - n1 = Nokogiri::XML::Node.new( - 'instructions', msg.document - ) - n1.content = "Enter the information from your Account "\ + orig.instructions = "Enter the information from your Account "\ "page as well as the Phone Number\nin your "\ "account you want to use (ie. '+12345678901')"\ ".\nUser Id is nick, API Token is username, "\ @@ -614,18 +602,12 @@ module SGXbwmsgsv2 "https://gitlab.com/soprani.ca/sgx-bwmsgsv2 ."\ "\nCopyright (C) 2017-2020 Denver Gingerich "\ "and others, licensed under AGPLv3+." - n2 = Nokogiri::XML::Node.new 'nick', msg.document - n3 = Nokogiri::XML::Node.new 'username', msg.document - n4 = Nokogiri::XML::Node.new 'password', msg.document - n5 = Nokogiri::XML::Node.new 'phone', msg.document - n5.content = existing_number.to_s - msg.add_child(n1) - msg.add_child(n2) - msg.add_child(n3) - msg.add_child(n4) - msg.add_child(n5) - - x = Blather::Stanza::X.new :form, [ + orig.nick = "" + orig.username = "" + orig.password = "" + orig.phone = existing_number.to_s + + orig.form.fields = [ { required: true, type: :"text-single", label: 'User Id', var: 'nick' @@ -644,20 +626,17 @@ module SGXbwmsgsv2 value: existing_number.to_s } ] - x.title = 'Register for '\ + orig.form.title = 'Register for '\ 'Soprani.ca Gateway to XMPP - Bandwidth API V2' - x.instructions = "Enter the details from your Account "\ + orig.form.instructions = "Enter the details from your Account "\ "page as well as the Phone Number\nin your "\ "account you want to use (ie. '+12345678901')"\ ".\n\nThe source code for this gateway is at "\ "https://gitlab.com/soprani.ca/sgx-bwmsgsv2 ."\ "\nCopyright (C) 2017-2020 Denver Gingerich "\ "and others, licensed under AGPLv3+." - msg.add_child(x) - - orig.add_child(msg) - return orig + orig end ibr do |i| diff --git a/test/test_component.rb b/test/test_component.rb index 35beb76cdc259216d15e9694b54a97bed1d94c4f..4e2da80839c773676f60daf8d4233ec09658b237 100644 --- a/test/test_component.rb +++ b/test/test_component.rb @@ -326,4 +326,26 @@ class ComponentTest < Minitest::Test assert stanza.result? end em :test_ibr_form + + def test_ibr_get_form_registered + iq = Blather::Stanza::Iq::IBR.new(:get, "component") + iq.from = "test@example.com" + process_stanza(iq) + + assert_equal 1, written.length + stanza = Blather::XMPPNode.parse(written.first.to_xml) + assert stanza.result? + assert stanza.registered? + assert_equal( + ["nick", "username", "password", "phone"], + stanza.form.fields.map(&:var) + ) + assert stanza.instructions + assert stanza.nick + assert stanza.username + assert stanza.password + assert stanza.phone + refute stanza.email + end + em :test_ibr_get_form_registered end