1# frozen_string_literal: true
2
3require "test_helper"
4require_relative "../sgx-bwmsgsv2"
5
6def panic(e)
7 $panic = e
8end
9
10class ComponentTest < Minitest::Test
11 def setup
12 SGXbwmsgsv2.instance_variable_set(:@written, [])
13
14 def SGXbwmsgsv2.write_to_stream(s)
15 @written ||= []
16 @written << s
17 end
18
19 REDIS.reset!
20 REDIS.set("catapult_jid-", "HERE")
21 REDIS.set("catapult_jid-+15550000000", "test@example.com")
22 REDIS.set("catapult_cred-test@example.com", [
23 'account', 'user', 'password', '+15550000000'
24 ])
25 end
26
27 def written
28 SGXbwmsgsv2.instance_variable_get(:@written)
29 end
30
31 def xmpp_error_name(error)
32 error.find_first(
33 "child::*[name()!='text']",
34 Blather::StanzaError::STANZA_ERR_NS
35 ).element_name
36 end
37
38 def xmpp_error_text(error)
39 error.find_first("ns:text", ns: Blather::StanzaError::STANZA_ERR_NS)&.text
40 end
41
42 def process_stanza(s)
43 SGXbwmsgsv2.send(:client).receive_data(s)
44 raise $panic if $panic
45 end
46
47 def test_message_unregistered
48 m = Blather::Stanza::Message.new("+15551234567@component", "a"*4096)
49 m.from = "unknown@example.com"
50 process_stanza(m)
51
52 assert_equal 1, written.length
53
54 stanza = Blather::XMPPNode.parse(written.first.to_xml)
55 assert stanza.error?
56 error = stanza.find_first("error")
57 assert_equal "auth", error["type"]
58 assert_equal "registration-required", xmpp_error_name(error)
59 end
60 em :test_message_unregistered
61
62 def test_message_too_long
63 req = stub_request(
64 :post,
65 "https://messaging.bandwidth.com/api/v2/users/account/messages"
66 ).with(body: {
67 from: "+15550000000",
68 to: "+15551234567",
69 text: "a"*4096,
70 applicationId: nil,
71 tag: " "
72 }).to_return(status: 400, body: JSON.dump(
73 description: "Bad text.",
74 fieldErrors: [{ description: "4096 not allowed" }]
75 ))
76
77 m = Blather::Stanza::Message.new("+15551234567@component", "a"*4096)
78 m.from = "test@example.com"
79 process_stanza(m)
80
81 assert_requested req
82 assert_equal 1, written.length
83
84 stanza = Blather::XMPPNode.parse(written.first.to_xml)
85 assert stanza.error?
86 error = stanza.find_first("error")
87 assert_equal "cancel", error["type"]
88 assert_equal "internal-server-error", xmpp_error_name(error)
89 assert_equal "Bad text. 4096 not allowed", xmpp_error_text(error)
90 end
91 em :test_message_too_long
92
93 def test_message_to_component_not_group
94 m = Blather::Stanza::Message.new("component", "a"*4096)
95 m.from = "test@example.com"
96 process_stanza(m)
97
98 assert_equal 1, written.length
99
100 stanza = Blather::XMPPNode.parse(written.first.to_xml)
101 assert stanza.error?
102 error = stanza.find_first("error")
103 assert_equal "cancel", error["type"]
104 assert_equal "item-not-found", xmpp_error_name(error)
105 end
106 em :test_message_to_component_not_group
107
108 def test_message_to_invalid_num
109 m = Blather::Stanza::Message.new("123@component", "a"*4096)
110 m.from = "test@example.com"
111 process_stanza(m)
112
113 assert_equal 1, written.length
114
115 stanza = Blather::XMPPNode.parse(written.first.to_xml)
116 assert stanza.error?
117 error = stanza.find_first("error")
118 assert_equal "cancel", error["type"]
119 assert_equal "item-not-found", xmpp_error_name(error)
120 end
121 em :test_message_to_invalid_num
122
123 def test_message_to_anonymous
124 m = Blather::Stanza::Message.new(
125 "1;phone-context=anonymous.phone-context.soprani.ca@component",
126 "a"*4096
127 )
128 m.from = "test@example.com"
129 process_stanza(m)
130
131 assert_equal 1, written.length
132
133 stanza = Blather::XMPPNode.parse(written.first.to_xml)
134 assert stanza.error?
135 error = stanza.find_first("error")
136 assert_equal "cancel", error["type"]
137 assert_equal "gone", xmpp_error_name(error)
138 end
139 em :test_message_to_anonymous
140
141 def test_blank_message
142 m = Blather::Stanza::Message.new("+15551234567@component", " ")
143 m.from = "test@example.com"
144 process_stanza(m)
145
146 assert_equal 1, written.length
147
148 stanza = Blather::XMPPNode.parse(written.first.to_xml)
149 assert stanza.error?
150 error = stanza.find_first("error")
151 assert_equal "modify", error["type"]
152 assert_equal "policy-violation", xmpp_error_name(error)
153 end
154 em :test_blank_message
155
156 def test_ibr_bad_tel
157 iq = Blather::Stanza::Iq::IBR.new(:set, "component")
158 iq.from = "newuser@example.com"
159 iq.phone = "5551234567"
160 process_stanza(iq)
161
162 assert_equal 1, written.length
163
164 stanza = Blather::XMPPNode.parse(written.first.to_xml)
165 assert stanza.error?
166 error = stanza.find_first("error")
167 assert_equal "cancel", error["type"]
168 assert_equal "item-not-found", xmpp_error_name(error)
169 end
170 em :test_ibr_bad_tel
171
172 def test_ibr_bad_creds
173 stub_request(
174 :get,
175 "https://messaging.bandwidth.com/api/v2/users/acct/media"
176 ).with(basic_auth: ["user", "pw"]).to_return(status: 401)
177
178 iq = Blather::Stanza::Iq::IBR.new(:set, "component")
179 iq.from = "newuser@example.com"
180 iq.phone = "+15551234567"
181 iq.nick = "acct"
182 iq.username = "user"
183 iq.password = "pw"
184 process_stanza(iq)
185
186 assert_equal 1, written.length
187
188 stanza = Blather::XMPPNode.parse(written.first.to_xml)
189 assert stanza.error?
190 error = stanza.find_first("error")
191 assert_equal "auth", error["type"]
192 assert_equal "not-authorized", xmpp_error_name(error)
193 end
194 em :test_ibr_bad_creds
195
196 def test_ibr_number_not_found
197 stub_request(
198 :get,
199 "https://messaging.bandwidth.com/api/v2/users/acct/media"
200 ).with(basic_auth: ["user", "pw"]).to_return(status: 404)
201
202 iq = Blather::Stanza::Iq::IBR.new(:set, "component")
203 iq.from = "newuser@example.com"
204 iq.phone = "+15551234567"
205 iq.nick = "acct"
206 iq.username = "user"
207 iq.password = "pw"
208 process_stanza(iq)
209
210 assert_equal 1, written.length
211
212 stanza = Blather::XMPPNode.parse(written.first.to_xml)
213 assert stanza.error?
214 error = stanza.find_first("error")
215 assert_equal "cancel", error["type"]
216 assert_equal "item-not-found", xmpp_error_name(error)
217 end
218 em :test_ibr_number_not_found
219
220 def test_ibr_other_error
221 stub_request(
222 :get,
223 "https://messaging.bandwidth.com/api/v2/users/acct/media"
224 ).with(basic_auth: ["user", "pw"]).to_return(status: 400)
225
226 iq = Blather::Stanza::Iq::IBR.new(:set, "component")
227 iq.from = "newuser@example.com"
228 iq.phone = "+15551234567"
229 iq.nick = "acct"
230 iq.username = "user"
231 iq.password = "pw"
232 process_stanza(iq)
233
234 assert_equal 1, written.length
235
236 stanza = Blather::XMPPNode.parse(written.first.to_xml)
237 assert stanza.error?
238 error = stanza.find_first("error")
239 assert_equal "modify", error["type"]
240 assert_equal "not-acceptable", xmpp_error_name(error)
241 end
242 em :test_ibr_other_error
243
244 def test_ibr_new
245 stub_request(
246 :get,
247 "https://messaging.bandwidth.com/api/v2/users/acct/media"
248 ).with(basic_auth: ["user", "pw"]).to_return(status: 200, body: "[]")
249
250 iq = Blather::Stanza::Iq::IBR.new(:set, "component")
251 iq.from = "test9@example.com"
252 iq.phone = "+15550000009"
253 iq.nick = "acct"
254 iq.username = "user"
255 iq.password = "pw"
256 process_stanza(iq)
257
258 assert_equal 1, written.length
259
260 stanza = Blather::XMPPNode.parse(written.first.to_xml)
261 refute stanza.error?
262 assert_equal(
263 ["acct", "user", "pw", "+15550000009"],
264 REDIS.get("catapult_cred-test9@example.com").sync
265 )
266 assert_equal "test9@example.com", REDIS.get("catapult_jid-+15550000009").sync
267 assert REDIS.get("catapult_jid-").sync
268 end
269 em :test_ibr_new
270
271 def test_ibr_update
272 stub_request(
273 :get,
274 "https://messaging.bandwidth.com/api/v2/users/acct/media"
275 ).with(basic_auth: ["user", "pw"]).to_return(status: 200, body: "[]")
276
277 iq = Blather::Stanza::Iq::IBR.new(:set, "component")
278 iq.from = "test@example.com"
279 iq.phone = "+15550000009"
280 iq.nick = "acct"
281 iq.username = "user"
282 iq.password = "pw"
283 process_stanza(iq)
284
285 assert_equal 1, written.length
286
287 stanza = Blather::XMPPNode.parse(written.first.to_xml)
288 refute stanza.error?
289 assert_equal(
290 ["acct", "user", "pw", "+15550000009"],
291 REDIS.get("catapult_cred-test@example.com").sync
292 )
293 assert_equal "test@example.com", REDIS.get("catapult_jid-+15550000009").sync
294 refute REDIS.get("catapult_jid-+15550000000").sync
295 end
296 em :test_ibr_update
297
298 def test_ibr_conflict
299 stub_request(
300 :get,
301 "https://messaging.bandwidth.com/api/v2/users/acct/media"
302 ).with(basic_auth: ["user", "pw"]).to_return(status: 200, body: "[]")
303
304 iq = Blather::Stanza::Iq::IBR.new(:set, "component")
305 iq.from = "test2@example.com"
306 iq.phone = "+15550000000"
307 iq.nick = "acct"
308 iq.username = "user"
309 iq.password = "pw"
310 process_stanza(iq)
311
312 assert_equal 1, written.length
313
314 stanza = Blather::XMPPNode.parse(written.first.to_xml)
315 assert stanza.error?
316 error = stanza.find_first("error")
317 assert_equal "cancel", error["type"]
318 assert_equal "conflict", xmpp_error_name(error)
319 assert_equal(
320 "Another user exists for +15550000000",
321 xmpp_error_text(error)
322 )
323 end
324 em :test_ibr_conflict
325
326 def test_ibr_remove
327 iq = Blather::Stanza::Iq::IBR.new(:set, "component")
328 iq.from = "test@example.com"
329 iq.remove!
330 process_stanza(iq)
331
332 refute REDIS.get("catapult_cred-test@example.com").sync
333
334 assert_equal 1, written.length
335
336 stanza = Blather::XMPPNode.parse(written.first.to_xml)
337 assert stanza.result?
338 end
339 em :test_ibr_remove
340
341 def test_ibr_form
342 stub_request(
343 :get,
344 "https://messaging.bandwidth.com/api/v2/users/acct/media"
345 ).with(basic_auth: ["user", "pw"]).to_return(status: 200, body: "[]")
346
347 iq = Blather::Stanza::Iq::IBR.new(:set, "component")
348 iq.from = "formuser@example.com"
349 form = Blather::Stanza::X.find_or_create(iq.query)
350 form.fields = [
351 {
352 var: "nick",
353 value: "acct"
354 },
355 {
356 var: "username",
357 value: "user"
358 },
359 {
360 var: "password",
361 value: "pw"
362 },
363 {
364 var: "phone",
365 value: "+15551234567"
366 }
367 ]
368 process_stanza(iq)
369
370 assert_equal(
371 ["acct", "user", "pw", "+15551234567"],
372 REDIS.get("catapult_cred-formuser@example.com").sync
373 )
374
375 assert_equal(
376 "formuser@example.com",
377 REDIS.get("catapult_jid-+15551234567").sync
378 )
379
380 assert_equal 1, written.length
381 stanza = Blather::XMPPNode.parse(written.first.to_xml)
382 assert stanza.result?
383 end
384 em :test_ibr_form
385
386 def test_ibr_get_form_registered
387 iq = Blather::Stanza::Iq::IBR.new(:get, "component")
388 iq.from = "test@example.com"
389 process_stanza(iq)
390
391 assert_equal 1, written.length
392 stanza = Blather::XMPPNode.parse(written.first.to_xml)
393 assert stanza.result?
394 assert stanza.registered?
395 assert_equal(
396 ["nick", "username", "password", "phone"],
397 stanza.form.fields.map(&:var)
398 )
399 assert stanza.instructions
400 assert stanza.nick
401 assert stanza.username
402 assert stanza.password
403 assert stanza.phone
404 refute stanza.email
405 end
406 em :test_ibr_get_form_registered
407
408 def test_port_out_pin
409 iq = Blather::Stanza::Iq::Command.new(:set, 'component').tap do |iq|
410 iq.from = 'test@example.com'
411 iq.node = 'set-port-out-pin'
412 iq.sessionid = 'test-session-123'
413 iq.action = :complete
414 iq.form.type = :submit
415 iq.form.fields = [
416 {
417 var: 'pin',
418 value: '1234'
419 },
420 {
421 var: 'confirm_pin',
422 value: '1234'
423 }
424 ]
425 end
426
427 BandwidthIris::TnOptions.stub :create_tn_option_order,
428 ->(client, data) { {order_id: 'test-order-123', processing_status: 'RECEIVED', error_list: {}} } do
429 BandwidthIris::TnOptions.stub :get_tn_option_order,
430 ->(client, order_id) { {order_id: order_id, order_status: 'COMPLETE', error_list: {}} } do
431
432 process_stanza(iq)
433
434 assert_equal 1, written.length
435
436 stanza = Blather::XMPPNode.parse(written.first.to_xml)
437 refute stanza.error?
438 end
439 end
440 end
441 em :test_port_out_pin
442
443 def test_port_out_pin_mismatch
444 iq = Blather::Stanza::Iq::Command.new(:set, 'component').tap do |iq|
445 iq.from = 'test@example.com'
446 iq.node = 'set-port-out-pin'
447 iq.sessionid = 'test-session-mismatch'
448 iq.action = :complete
449 iq.form.type = :submit
450 iq.form.fields = [
451 {
452 var: 'pin',
453 value: '1234'
454 },
455 {
456 var: 'confirm_pin',
457 value: '5678'
458 }
459 ]
460 end
461
462 process_stanza(iq)
463
464 assert_equal 1, written.length
465
466 stanza = Blather::XMPPNode.parse(written.first.to_xml)
467 assert_equal :error, stanza.type
468 error = stanza.find_first("error")
469 assert_equal "modify", error["type"]
470 assert_equal "bad-request", xmpp_error_name(error)
471 assert_equal "PIN confirmation does not match", xmpp_error_text(error)
472 end
473 em :test_port_out_pin_mismatch
474
475 def test_port_out_pin_validation
476 [
477 ['123', 'PIN must be 4-10 alphanumeric characters'],
478 ['12345678901', 'PIN must be 4-10 alphanumeric characters'],
479 ['123!', 'PIN must be 4-10 alphanumeric characters'],
480 ['pin with spaces', 'PIN must be 4-10 alphanumeric characters']
481 ].each do |invalid_pin, expected_error|
482 iq = Blather::Stanza::Iq::Command.new(:set, 'component').tap do |iq|
483 iq.from = 'test@example.com'
484 iq.node = 'set-port-out-pin'
485 iq.sessionid = "test-session-validation-#{invalid_pin.gsub(/[^a-zA-Z0-9]/, '')}"
486 iq.action = :complete
487 iq.form.type = :submit
488 iq.form.fields = [
489 {
490 var: 'pin',
491 value: invalid_pin
492 },
493 {
494 var: 'confirm_pin',
495 value: invalid_pin
496 }
497 ]
498 end
499
500 process_stanza(iq)
501
502 assert_equal 1, written.length, "Failed for PIN: #{invalid_pin}"
503
504 stanza = Blather::XMPPNode.parse(written.first.to_xml)
505 assert_equal :error, stanza.type, "Expected error for PIN: #{invalid_pin}"
506 error = stanza.find_first("error")
507 assert_equal "modify", error["type"]
508 assert_equal "bad-request", xmpp_error_name(error)
509 assert_equal expected_error, xmpp_error_text(error),
510 "Wrong error message for PIN: #{invalid_pin}"
511
512 SGXbwmsgsv2.instance_variable_set(:@written, [])
513 end
514 end
515 em :test_port_out_pin_validation
516end