CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/spec/lib/rex/proto/nuuo/client_spec.rb
Views: 1904
1
# -*- coding:binary -*-
2
3
RSpec.describe Rex::Proto::Nuuo::Client do
4
subject(:client) {
5
described_class.new({
6
protocol: protocol,
7
user_session: client_user_session,
8
username: client_username,
9
password: client_password
10
})
11
}
12
let(:protocol) {'tcp'}
13
let(:client_user_session) {nil}
14
let(:client_username) {nil}
15
let(:client_password) {nil}
16
17
describe '#connect' do
18
context 'given temp is false' do
19
context 'when there is no connection' do
20
it 'returns a tcp connection' do
21
tcp_connection = double('tcp_connection')
22
allow(Rex::Socket::Tcp).to receive(:create).and_return(tcp_connection)
23
24
expect(client.connect).to eq(tcp_connection)
25
end
26
27
it 'saves the tcp connection' do
28
tcp_connection = double('tcp_connection')
29
allow(Rex::Socket::Tcp).to receive(:create).and_return(tcp_connection)
30
31
client.connect
32
expect(client.connection).to eq(tcp_connection)
33
end
34
end
35
36
context 'when there is saved connection' do
37
it 'returns the saved tcp connection' do
38
tcp_connection = double('tcp_connection')
39
client.connection = tcp_connection
40
41
expect(client.connect).to eq(tcp_connection)
42
end
43
end
44
end
45
46
context 'given temp is true' do
47
context 'when there is a saved connection' do
48
it 'returns a new connection' do
49
tcp_connection0 = double('tcp_connection')
50
tcp_connection1 = double('tcp_connection')
51
allow(Rex::Socket::Tcp).to receive(:create).and_return(tcp_connection1)
52
53
client.connection = tcp_connection0
54
expect(client.connect(temp: true)).to eq(tcp_connection1)
55
end
56
57
it 'does not overwrite existing connection' do
58
tcp_connection0 = double('tcp_connection')
59
tcp_connection1 = double('tcp_connection')
60
allow(Rex::Socket::Tcp).to receive(:create).and_return(tcp_connection1)
61
62
client.connection = tcp_connection0
63
client.connect(temp: true)
64
expect(client.connection).to eq(tcp_connection0)
65
end
66
end
67
68
context 'when there is no saved connection' do
69
it 'returns a new connection' do
70
tcp_connection = double('tcp_connection')
71
allow(Rex::Socket::Tcp).to receive(:create).and_return(tcp_connection)
72
73
expect(client.connect(temp: true)).to eq(tcp_connection)
74
end
75
76
it 'does not save the connection' do
77
tcp_connection = double('tcp_connection')
78
allow(Rex::Socket::Tcp).to receive(:create).and_return(tcp_connection)
79
80
client.connect(temp: true)
81
expect(client.connection).to be_nil
82
end
83
end
84
end
85
86
end
87
88
describe '#close' do
89
context 'given there is a connection' do
90
it 'calls shutdown on the connection' do
91
tcp_connection = double('tcp_connection')
92
allow(tcp_connection).to receive(:shutdown) {true}
93
allow(tcp_connection).to receive(:closed?) {false}
94
allow(tcp_connection).to receive(:close) {true}
95
client.connection = tcp_connection
96
97
expect(tcp_connection).to receive(:shutdown)
98
client.close
99
end
100
101
it 'calls closed on the connection' do
102
tcp_connection = double('tcp_connection')
103
allow(tcp_connection).to receive(:shutdown) {true}
104
allow(tcp_connection).to receive(:closed?) {false}
105
allow(tcp_connection).to receive(:close) {true}
106
client.connection = tcp_connection
107
108
expect(tcp_connection).to receive(:close)
109
client.close
110
end
111
end
112
end
113
114
describe '#send_recv' do
115
context 'given no connection is passed in' do
116
it 'calls send_request without connection' do
117
allow(client).to receive(:send_request) do |*args|
118
expect(args[1]).to be_nil
119
end
120
allow(client).to receive(:read_response)
121
122
client.send_recv('test')
123
end
124
125
it 'calls read_resposne without connection' do
126
allow(client).to receive(:read_response) do |*args|
127
expect(args[0]).to be_nil
128
end
129
allow(client).to receive(:send_request)
130
131
client.send_recv('test')
132
end
133
end
134
135
context 'given a connection is passed in' do
136
it 'uses the passed in connection' do
137
tcp_connection = double('tcp_connection')
138
passed_connection = double('passed_connection')
139
client.connection = tcp_connection
140
141
allow(passed_connection).to receive(:put)
142
allow(client).to receive(:read_response)
143
144
expect(passed_connection).to receive(:put)
145
client.send_recv('test', passed_connection)
146
end
147
end
148
end
149
150
describe '#read_response' do
151
let(:res) {"NUCM/1.0 200\r\nTest:test\r\nContent-Length:1\r\n\r\na"}
152
it 'returns a Response object' do
153
tcp_connection = double('tcp_connection')
154
allow(tcp_connection).to receive('closed?') {false}
155
allow(tcp_connection).to receive('get_once') {res}
156
client.connection = tcp_connection
157
158
expect(client.read_response).to be_a_kind_of(Rex::Proto::Nuuo::Response)
159
end
160
end
161
162
describe '#request_ping' do
163
subject(:ping_request) {
164
opts = {'user_session' => user_session}
165
client.request_ping(opts)
166
}
167
let(:user_session) {nil}
168
169
it 'returns a PING client request' do
170
expect(ping_request.to_s).to start_with('PING')
171
end
172
173
context 'given a user_session option' do
174
let(:user_session) {'test'}
175
176
context 'when the client does not have a session' do
177
it 'uses the user_session option' do
178
expect(ping_request.to_s).to match('User-Session-No: test')
179
end
180
end
181
182
context 'when the client has a session' do
183
let(:client_user_session) {'client'}
184
185
it 'overrides the client session value' do
186
expect(ping_request.to_s).to match('User-Session-No: test')
187
end
188
end
189
end
190
191
192
context 'given no user_session is provided' do
193
context 'when the client does not have a session' do
194
it 'does not have a User-Session-No header' do
195
expect(ping_request.to_s).to_not match('User-Session-No:')
196
end
197
end
198
199
context 'when the client has a session' do
200
let(:client_user_session) {'client'}
201
202
it 'uses the client session' do
203
expect(ping_request.to_s).to match('User-Session-No: client')
204
end
205
end
206
end
207
208
end
209
210
describe '#request_sendlicfile' do
211
subject(:sendlicfile_request) {
212
opts = {
213
'file_name' => filename,
214
'data' => data
215
}
216
client.request_sendlicfile(opts).to_s
217
}
218
let(:filename) {'TestFile'}
219
let(:data) {'testdata'}
220
221
it 'returns a SENDLICFILE client request' do
222
expect(sendlicfile_request).to start_with('SENDLICFILE')
223
end
224
225
context 'given file_name' do
226
it 'sets the FileName header with the value' do
227
expect(sendlicfile_request).to match("[^\r\n]\r\nFileName: TestFile\r\n")
228
end
229
end
230
231
context 'given no file_name' do
232
let(:filename) {nil}
233
234
it 'creates an empty FileName header' do
235
expect(sendlicfile_request).to match("[^\r\n]\r\nFileName: \r\n")
236
end
237
end
238
239
context 'given data' do
240
it 'sets the body to the data contents' do
241
expect(sendlicfile_request).to end_with("\r\n\r\ntestdata")
242
end
243
244
it 'sets the Content-Length header with data length' do
245
expect(sendlicfile_request).to match("[^\r\n]\r\nContent-Length: 8\r\n")
246
end
247
end
248
249
context 'given no data' do
250
let(:data) {nil}
251
it 'creates an empty body' do
252
expect(sendlicfile_request).to end_with("\r\n\r\n")
253
end
254
255
it 'set Content-Length header to 0' do
256
expect(sendlicfile_request).to match("[^\r\n]\r\nContent-Length: 0\r\n")
257
end
258
end
259
end
260
261
describe '#request_getconfig' do
262
subject(:getconfig_request) {
263
opts = {
264
'file_name' => filename,
265
'file_type' => filetype
266
}
267
client.request_getconfig(opts).to_s
268
}
269
let(:filename) {'TestName'}
270
let(:filetype) {2}
271
272
it 'returns a GETCONFIG client request' do
273
expect(getconfig_request).to start_with('GETCONFIG')
274
end
275
276
context 'given file_name' do
277
it 'sets the FileName header' do
278
expect(getconfig_request).to match("[^\r\n]\r\nFileName: TestName\r\n")
279
end
280
end
281
282
context 'given no file_name' do
283
let(:filename) {nil}
284
it 'creates an empty FileName header' do
285
expect(getconfig_request).to match("[^\r\n]\r\nFileName: \r\n")
286
end
287
end
288
289
context 'given a file_type' do
290
it 'sets the FileType header' do
291
expect(getconfig_request).to match("[^\r\n]\r\nFileType: 2\r\n")
292
end
293
end
294
295
context 'given no file_type' do
296
let(:filetype) {nil}
297
it 'defaults to 1' do
298
expect(getconfig_request).to match("[^\r\n]\r\nFileType: 1\r\n")
299
end
300
end
301
end
302
303
describe '#request_commitconfig' do
304
subject(:commitconfig_request) {
305
opts = {
306
'file_name' => filename,
307
'file_type' => filetype,
308
'data' => data
309
}
310
client.request_commitconfig(opts).to_s
311
}
312
let(:filename) {'TestName'}
313
let(:filetype) {2}
314
let(:data) {'testdata'}
315
316
it 'returns a COMMITCONFIG client request' do
317
expect(commitconfig_request).to start_with('COMMITCONFIG')
318
end
319
320
context 'given file_name' do
321
it 'sets the FileName header' do
322
expect(commitconfig_request).to match("[^\r\n]\r\nFileName: TestName\r\n")
323
end
324
end
325
326
context 'given no file_name' do
327
let(:filename) {nil}
328
329
it 'creates an empty FileName header' do
330
expect(commitconfig_request).to match("[^\r\n]\r\nFileName: \r\n")
331
end
332
end
333
334
context 'given file_type' do
335
it 'sets the FileType header' do
336
expect(commitconfig_request).to match("[^\r\n]\r\nFileType: 2\r\n")
337
end
338
end
339
340
context 'given no file_type' do
341
let(:filetype) {nil}
342
343
it 'creates an empty FileType header' do
344
expect(commitconfig_request).to match("[^\r\n]\r\nFileType: 1\r\n")
345
end
346
end
347
348
context 'given data' do
349
it 'sets the request body to the data' do
350
expect(commitconfig_request).to end_with("\r\n\r\ntestdata")
351
end
352
353
it 'sets Content-Length to data length' do
354
expect(commitconfig_request).to match("[^\r\n]\r\nContent-Length: 8\r\n")
355
end
356
end
357
358
context 'given no data' do
359
let(:data) {nil}
360
361
it 'creates an empty request body' do
362
expect(commitconfig_request).to end_with("\r\n\r\n")
363
end
364
365
it 'creates Content-Length header with 0' do
366
expect(commitconfig_request).to match("[^\r\n]\r\nContent-Length: 0\r\n")
367
end
368
end
369
end
370
371
describe '#request_userlogin' do
372
subject(:userlogin_request) {
373
opts = {
374
'server_version' => server_version,
375
'username' => username,
376
'password' => password
377
}
378
client.request_userlogin(opts).to_s
379
}
380
let(:server_version) {'1.1.1'}
381
let(:username) {'user'}
382
let(:password) {'pass'}
383
384
it 'returns a USERLOGIN client request' do
385
expect(userlogin_request).to start_with('USERLOGIN')
386
end
387
388
context 'given server_version' do
389
it 'sets Version header with value' do
390
expect(userlogin_request).to match("[^\r\n]\r\nVersion: 1.1.1\r\n")
391
end
392
end
393
394
context 'given no server_version' do
395
let(:server_version) {nil}
396
397
it 'creates an empty Version header' do
398
expect(userlogin_request).to match("[^\r\n]\r\nVersion: \r\n")
399
end
400
end
401
402
context 'when client has username' do
403
let(:client_username) {'client_user'}
404
405
context 'given username' do
406
it 'sets the Username header with opts username' do
407
expect(userlogin_request).to match("[^\r\n]\r\nUsername: user\r\n")
408
end
409
end
410
411
context 'given no username' do
412
let(:username) {nil}
413
414
it 'creates an Username header with client username' do
415
expect(userlogin_request).to match("[^\r\n]\r\nUsername: client_user\r\n")
416
end
417
end
418
end
419
420
context 'when client has no username' do
421
context 'given username' do
422
it 'sets the Username header with value' do
423
expect(userlogin_request).to match("[^\r\n]\r\nUsername: user\r\n")
424
end
425
end
426
427
context 'given no username' do
428
let(:username) {nil}
429
430
it 'creates an empty Username header' do
431
expect(userlogin_request).to match("[^\r\n]\r\nUsername: \r\n")
432
end
433
end
434
end
435
436
context 'when client has password' do
437
let(:client_password) {'client_pass'}
438
439
context 'given password' do
440
it 'sets body with password' do
441
expect(userlogin_request).to end_with("\r\n\r\npass")
442
end
443
444
it 'sets Password-Length header' do
445
expect(userlogin_request).to match("[^\r\n]\r\nPassword-Length: 4\r\n")
446
end
447
end
448
449
context 'given no password' do
450
let(:password) {nil}
451
452
it 'sets body to client password' do
453
expect(userlogin_request).to end_with("\r\n\r\nclient_pass")
454
end
455
456
it 'creates Password-Length with client password length' do
457
expect(userlogin_request).to match("[^\r\n]\r\nPassword-Length: 11\r\n")
458
end
459
end
460
end
461
462
context 'when client has no password' do
463
context 'given password' do
464
it 'sets body with password' do
465
expect(userlogin_request).to end_with("\r\n\r\npass")
466
end
467
468
it 'sets Password-Length header' do
469
expect(userlogin_request).to match("[^\r\n]\r\nPassword-Length: 4\r\n")
470
end
471
end
472
473
context 'given no password' do
474
let(:password) {nil}
475
476
it 'sets empty body' do
477
expect(userlogin_request).to end_with("\r\n\r\n")
478
end
479
480
it 'creates Password-Length with 0' do
481
expect(userlogin_request).to match("[^\r\n]\r\nPassword-Length: 0\r\n")
482
end
483
end
484
end
485
486
end
487
488
describe '#request_getopenalarm' do
489
subject(:getopenalarm_request) {
490
opts = {
491
'device_id' => device_id,
492
'source_server' => source_server,
493
'last_one' => last_one
494
}
495
client.request_getopenalarm(opts).to_s
496
}
497
let(:device_id) {nil}
498
let(:source_server) {nil}
499
let(:last_one) {nil}
500
501
it 'returns a GETOPENALARM client request' do
502
expect(getopenalarm_request).to start_with('GETOPENALARM')
503
end
504
505
context 'given device_id' do
506
let(:device_id) {2}
507
508
it 'sets DeviceID header with value' do
509
expect(getopenalarm_request).to match("[^\r\n]\r\nDeviceID: 2\r\n")
510
end
511
end
512
513
context 'given no device_id' do
514
it 'sets DeviceID header to 1' do
515
expect(getopenalarm_request).to match("[^\r\n]\r\nDeviceID: 1\r\n")
516
end
517
end
518
519
context 'given source_server' do
520
let(:source_server) {2}
521
522
it 'sets SourceServer header with value' do
523
expect(getopenalarm_request).to match("[^\r\n]\r\nSourceServer: 2\r\n")
524
end
525
end
526
527
context 'given no source_server' do
528
it 'set SourceServer header to 1' do
529
expect(getopenalarm_request).to match("[^\r\n]\r\nSourceServer: 1\r\n")
530
end
531
end
532
533
context 'given last_one' do
534
let(:last_one) {2}
535
536
it 'sets LastOne header with value' do
537
expect(getopenalarm_request).to match("[^\r\n]\r\nLastOne: 2\r\n")
538
end
539
end
540
541
context 'given no last_one' do
542
it 'sets LastOne to 1' do
543
expect(getopenalarm_request).to match("[^\r\n]\r\nLastOne: 1\r\n")
544
end
545
end
546
end
547
end
548
549