metasploit_data_models 0.17.3 → 0.18.0.pre.compatibility

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +8 -8
  2. data/CONTRIBUTING.md +164 -0
  3. data/README.md +6 -2
  4. data/app/models/mdm/host.rb +18 -0
  5. data/app/models/mdm/service.rb +12 -1
  6. data/app/models/metasploit_data_models/search/operation/port/number.rb +25 -0
  7. data/app/models/metasploit_data_models/search/operation/port/range.rb +79 -0
  8. data/app/models/metasploit_data_models/search/operation/range.rb +56 -0
  9. data/app/models/metasploit_data_models/search/operator/multitext.rb +73 -0
  10. data/app/models/metasploit_data_models/search/operator/port/list.rb +67 -0
  11. data/app/models/metasploit_data_models/search/visitor/attribute.rb +2 -1
  12. data/app/models/metasploit_data_models/search/visitor/includes.rb +3 -2
  13. data/app/models/metasploit_data_models/search/visitor/joins.rb +5 -3
  14. data/app/models/metasploit_data_models/search/visitor/method.rb +3 -2
  15. data/app/models/metasploit_data_models/search/visitor/where.rb +8 -2
  16. data/config/locales/en.yml +17 -1
  17. data/lib/metasploit_data_models.rb +1 -9
  18. data/lib/metasploit_data_models/version.rb +29 -6
  19. data/metasploit_data_models.gemspec +2 -2
  20. data/spec/app/models/metasploit_data_models/search/operation/port/number_spec.rb +41 -0
  21. data/spec/app/models/metasploit_data_models/search/operation/port/range_spec.rb +140 -0
  22. data/spec/app/models/metasploit_data_models/search/operation/range_spec.rb +235 -0
  23. data/spec/app/models/metasploit_data_models/search/operator/multitext_spec.rb +162 -0
  24. data/spec/app/models/metasploit_data_models/search/operator/port/list_spec.rb +164 -0
  25. data/spec/app/models/metasploit_data_models/search/visitor/attribute_spec.rb +48 -26
  26. data/spec/app/models/metasploit_data_models/search/visitor/includes_spec.rb +10 -7
  27. data/spec/app/models/metasploit_data_models/search/visitor/joins_spec.rb +44 -30
  28. data/spec/app/models/metasploit_data_models/search/visitor/method_spec.rb +16 -0
  29. data/spec/app/models/metasploit_data_models/search/visitor/relation_spec.rb +273 -65
  30. data/spec/app/models/metasploit_data_models/search/visitor/where_spec.rb +42 -2
  31. data/spec/factories/mdm/services.rb +1 -2
  32. data/spec/lib/metasploit_data_models/version_spec.rb +141 -0
  33. data/spec/support/shared/examples/metasploit_data_models/search/visitor/where/visit/with_metasploit_model_search_group_base.rb +1 -1
  34. metadata +27 -11
  35. data/lib/metasploit_data_models/models.rb +0 -21
  36. data/lib/metasploit_data_models/validators.rb +0 -19
@@ -12,6 +12,40 @@ describe MetasploitDataModels::Search::Visitor::Attribute do
12
12
  visitor.visit(node)
13
13
  end
14
14
 
15
+ #
16
+ # Shared examples
17
+ #
18
+
19
+ shared_examples_for 'operator.klass.arel_table[operator.attribute]' do |options = {}|
20
+ options.assert_valid_keys(:node_class)
21
+
22
+ node_class = options.fetch(:node_class)
23
+
24
+ context "with #{node_class}" do
25
+ it { should be_a Arel::Attributes::Attribute }
26
+
27
+ context '#name' do
28
+ subject(:name) do
29
+ visit.name
30
+ end
31
+
32
+ it "should be #{node_class}#attribute" do
33
+ name.should == node.attribute
34
+ end
35
+ end
36
+
37
+ context '#relation' do
38
+ subject(:relation) do
39
+ visit.relation
40
+ end
41
+
42
+ it "should be Class#arel_table for #{node_class}#klass" do
43
+ relation.should == node.klass.arel_table
44
+ end
45
+ end
46
+ end
47
+ end
48
+
15
49
  context 'with Metasploit::Model::Search::Operator::Association' do
16
50
  let(:attribute_operator) do
17
51
  double('Attribute Operator')
@@ -40,37 +74,25 @@ describe MetasploitDataModels::Search::Visitor::Attribute do
40
74
  end
41
75
  end
42
76
 
43
- context 'with Metasploit::Model::Search::Operator::Attribute' do
44
- let(:node) do
77
+ it_should_behave_like 'operator.klass.arel_table[operator.attribute]',
78
+ node_class: Metasploit::Model::Search::Operator::Attribute do
79
+ let(:node) {
45
80
  Metasploit::Model::Search::Operator::Attribute.new(
46
81
  # needs to be a real column so look up on AREL table works
47
- :attribute => :name,
82
+ attribute: :name,
48
83
  # needs to be a real class so Class#arel_table works
49
- :klass => Mdm::Host
84
+ klass: Mdm::Host
50
85
  )
51
- end
52
-
53
- it { should be_a Arel::Attributes::Attribute }
54
-
55
- context 'name' do
56
- subject(:name) do
57
- visit.name
58
- end
59
-
60
- it 'should be Metasploit::Model::Search::Operator::Attribute#attribute' do
61
- name.should == node.attribute
62
- end
63
- end
64
-
65
- context 'relation' do
66
- subject(:relation) do
67
- visit.relation
68
- end
86
+ }
87
+ end
69
88
 
70
- it 'should be Class#arel_table for Metasploit::Model::Search::Operator::Attribute#klass' do
71
- relation.should == node.klass.arel_table
72
- end
73
- end
89
+ it_should_behave_like 'operator.klass.arel_table[operator.attribute]',
90
+ node_class: MetasploitDataModels::Search::Operator::Port::List do
91
+ let(:node) {
92
+ Metasploit::Model::Search::Operator::Attribute.new(
93
+ klass: Mdm::Service
94
+ )
95
+ }
74
96
  end
75
97
  end
76
98
  end
@@ -15,7 +15,8 @@ describe MetasploitDataModels::Search::Visitor::Includes do
15
15
  children_classes = [
16
16
  Metasploit::Model::Search::Group::Intersection,
17
17
  Metasploit::Model::Search::Group::Union,
18
- Metasploit::Model::Search::Operation::Union
18
+ Metasploit::Model::Search::Operation::Group::Intersection,
19
+ Metasploit::Model::Search::Operation::Group::Union
19
20
  ]
20
21
 
21
22
  children_classes.each do |children_class|
@@ -48,12 +49,6 @@ describe MetasploitDataModels::Search::Visitor::Includes do
48
49
  end
49
50
  end
50
51
 
51
- context 'with Metasploit::Model::Search::Operation::Union' do
52
- let(:node) do
53
-
54
- end
55
- end
56
-
57
52
  context 'with Metasploit::Model::Search::Operator::Association' do
58
53
  let(:association) do
59
54
  FactoryGirl.generate :metasploit_model_search_operator_association_association
@@ -78,6 +73,14 @@ describe MetasploitDataModels::Search::Visitor::Includes do
78
73
  it { should == [] }
79
74
  end
80
75
 
76
+ context 'with MetasploitDataModels::Search::Operator::Port::List' do
77
+ let(:node) do
78
+ MetasploitDataModels::Search::Operator::Port::List.new
79
+ end
80
+
81
+ it { should == [] }
82
+ end
83
+
81
84
  context 'with Metasploit::Model::Search::Query#tree' do
82
85
  let(:node) do
83
86
  query.tree
@@ -12,48 +12,55 @@ describe MetasploitDataModels::Search::Visitor::Joins do
12
12
  visitor.visit(node)
13
13
  end
14
14
 
15
- context 'with Metasploit::Model::Search::Group::Intersection' do
16
- let(:children) do
17
- 2.times.collect { |n|
18
- double("Child #{n}")
19
- }
20
- end
15
+ intersection_classes = [
16
+ Metasploit::Model::Search::Group::Intersection,
17
+ Metasploit::Model::Search::Operation::Group::Intersection
18
+ ]
21
19
 
22
- let(:node) do
23
- Metasploit::Model::Search::Group::Intersection.new(
24
- :children => children
25
- )
26
- end
20
+ intersection_classes.each do |intersection_class|
21
+ context "with #{intersection_class}" do
22
+ let(:children) do
23
+ 2.times.collect { |n|
24
+ double("Child #{n}")
25
+ }
26
+ end
27
+
28
+ let(:node) do
29
+ intersection_class.new(
30
+ :children => children
31
+ )
32
+ end
27
33
 
28
- it 'should visit each child' do
29
- # needed for call to visit subject
30
- visitor.should_receive(:visit).with(node).and_call_original
34
+ it 'should visit each child' do
35
+ # needed for call to visit subject
36
+ visitor.should_receive(:visit).with(node).and_call_original
31
37
 
32
- children.each do |child|
33
- visitor.should_receive(:visit).with(child).and_return([])
38
+ children.each do |child|
39
+ visitor.should_receive(:visit).with(child).and_return([])
40
+ end
41
+
42
+ visit
34
43
  end
35
44
 
36
- visit
37
- end
45
+ it 'should return Array of all child visits' do
46
+ child_visits = []
38
47
 
39
- it 'should return Array of all child visits' do
40
- child_visits = []
48
+ visitor.should_receive(:visit).with(node).and_call_original
41
49
 
42
- visitor.should_receive(:visit).with(node).and_call_original
50
+ children.each_with_index do |child, i|
51
+ child_visit = ["Visited Child #{i}"]
52
+ visitor.stub(:visit).with(child).and_return(child_visit)
53
+ child_visits.concat(child_visit)
54
+ end
43
55
 
44
- children.each_with_index do |child, i|
45
- child_visit = ["Visited Child #{i}"]
46
- visitor.stub(:visit).with(child).and_return(child_visit)
47
- child_visits.concat(child_visit)
56
+ visit.should == child_visits
48
57
  end
49
-
50
- visit.should == child_visits
51
58
  end
52
59
  end
53
60
 
54
61
  union_classes = [
55
62
  Metasploit::Model::Search::Group::Union,
56
- Metasploit::Model::Search::Operation::Union
63
+ Metasploit::Model::Search::Operation::Group::Union
57
64
  ]
58
65
 
59
66
  union_classes.each do |union_class|
@@ -237,7 +244,7 @@ describe MetasploitDataModels::Search::Visitor::Joins do
237
244
  end
238
245
  end
239
246
 
240
- context "with Metasploit::Model::Search::Operator::Attribute" do
247
+ context 'with Metasploit::Model::Search::Operator::Attribute' do
241
248
  let(:node) do
242
249
  Metasploit::Model::Search::Operator::Attribute.new
243
250
  end
@@ -245,6 +252,14 @@ describe MetasploitDataModels::Search::Visitor::Joins do
245
252
  it { should == [] }
246
253
  end
247
254
 
255
+ context 'with MetasploitDataModels::Search::Operator::Port::List' do
256
+ let(:node) do
257
+ MetasploitDataModels::Search::Operator::Port::List.new
258
+ end
259
+
260
+ it { should == [] }
261
+ end
262
+
248
263
  context 'with Metasploit::Model::Search::Query#tree' do
249
264
  let(:node) do
250
265
  query.tree
@@ -263,7 +278,6 @@ describe MetasploitDataModels::Search::Visitor::Joins do
263
278
  Mdm::Host
264
279
  }
265
280
 
266
-
267
281
  context 'with name' do
268
282
  let(:name) do
269
283
  FactoryGirl.generate :mdm_host_name
@@ -24,6 +24,14 @@ describe MetasploitDataModels::Search::Visitor::Method do
24
24
  it { should == :and }
25
25
  end
26
26
 
27
+ context 'with Metasploit::Model::Search::Operation::Group::Intersection' do
28
+ let(:node_class) do
29
+ Metasploit::Model::Search::Operation::Group::Intersection
30
+ end
31
+
32
+ it { should == :and }
33
+ end
34
+
27
35
  context 'with Metasploit::Model::Search::Group::Union' do
28
36
  let(:node_class) do
29
37
  Metasploit::Model::Search::Group::Union
@@ -31,5 +39,13 @@ describe MetasploitDataModels::Search::Visitor::Method do
31
39
 
32
40
  it { should == :or }
33
41
  end
42
+
43
+ context 'with Metasploit::Model::Search::Operation::Group::Union' do
44
+ let(:node_class) do
45
+ Metasploit::Model::Search::Operation::Group::Union
46
+ end
47
+
48
+ it { should == :or }
49
+ end
34
50
  end
35
51
  end
@@ -12,10 +12,14 @@ describe MetasploitDataModels::Search::Visitor::Relation do
12
12
  "name:\"#{value}\""
13
13
  end
14
14
 
15
+ let(:klass) {
16
+ Mdm::Host
17
+ }
18
+
15
19
  let(:query) do
16
20
  Metasploit::Model::Search::Query.new(
17
21
  :formatted => formatted,
18
- :klass => Mdm::Host
22
+ :klass => klass
19
23
  )
20
24
  end
21
25
 
@@ -152,81 +156,285 @@ describe MetasploitDataModels::Search::Visitor::Relation do
152
156
  end
153
157
 
154
158
  context 'matching record' do
155
- context 'with Mdm::Host' do
156
- #
157
- # lets
158
- #
159
- # Don't use factories to prevent prefix aliasing when sequences go from 1 to 10 or 10 to 100
160
- #
161
-
162
- let(:matching_record_name) {
163
- 'mdm_host_name_a'
164
- }
165
-
166
- let(:matching_service_name) {
167
- 'mdm_service_name_a'
168
- }
169
-
170
- let(:non_matching_record_name) {
171
- 'mdm_host_name_b'
172
- }
173
-
174
- let(:non_matching_service_name) {
175
- 'mdm_service_name_b'
176
- }
177
-
178
- #
179
- # let!s
180
- #
181
-
182
- let!(:matching_record) do
183
- FactoryGirl.build(
184
- :mdm_host,
185
- name: matching_record_name
186
- )
187
- end
159
+ context 'Metasploit::Model::Search::Query#klass' do
160
+ context 'with Mdm::Service' do
161
+ let(:klass) {
162
+ Mdm::Service
163
+ }
188
164
 
189
- let!(:matching_service) do
190
- FactoryGirl.create(
191
- :mdm_service,
192
- host: matching_record,
193
- name: matching_service_name
194
- )
195
- end
165
+ let(:matching_ports) {
166
+ [
167
+ 1,
168
+ 2
169
+ ]
170
+ }
196
171
 
197
- let!(:non_matching_record) do
198
- FactoryGirl.build(
199
- :mdm_host,
200
- name: non_matching_record_name
201
- )
202
- end
172
+ let(:matching_records) {
173
+ matching_record_by_port.values
174
+ }
175
+
176
+ let(:non_matching_port) {
177
+ 3
178
+ }
179
+
180
+ #
181
+ # let!s
182
+ #
183
+
184
+ let!(:matching_record_by_port) {
185
+ matching_ports.each_with_object({}) { |matching_port, matching_record_by_port|
186
+ matching_record_by_port[matching_port] = FactoryGirl.create(
187
+ :mdm_service,
188
+ port: matching_port
189
+ )
190
+ }
191
+ }
192
+
193
+ let!(:non_matching_record) {
194
+ FactoryGirl.create(
195
+ :mdm_service,
196
+ port: non_matching_port
197
+ )
198
+ }
199
+
200
+ context 'with port' do
201
+ context 'with single port number' do
202
+ let(:formatted) {
203
+ "port:#{matching_port}"
204
+ }
205
+
206
+ let(:matching_port) {
207
+ matching_ports.sample
208
+ }
209
+
210
+ let(:matching_record) {
211
+ matching_record_by_port[matching_port]
212
+ }
213
+
214
+ it 'should find only record with that port number' do
215
+ expect(visit).to match_array([matching_record])
216
+ end
217
+ end
218
+
219
+ context 'with port range' do
220
+ let(:formatted) {
221
+ "port:#{matching_ports.min}-#{matching_ports.max}"
222
+ }
223
+
224
+ it 'should find all records with port numbers within the range' do
225
+ expect(visit).to match_array(matching_records)
226
+ end
227
+ end
228
+
229
+ context 'with comma separated port numbers' do
230
+ let(:formatted) {
231
+ "port:#{matching_ports.join(',')}"
232
+ }
233
+
234
+ it 'should find all records with the port numbers' do
235
+ expect(visit).to match_array(matching_records)
236
+ end
237
+ end
238
+
239
+ context 'with overlapping comma separated port number and range' do
240
+ let(:matching_port) {
241
+ matching_ports.sample
242
+ }
243
+
244
+ let(:formatted) {
245
+ %Q{port:#{matching_port},#{matching_ports.min}-#{matching_ports.max}}
246
+ }
203
247
 
204
- let!(:non_matching_service) do
205
- FactoryGirl.create(
206
- :mdm_service,
207
- host: non_matching_record,
208
- name: non_matching_service_name
209
- )
248
+ it 'should find all records with the matching ports once' do
249
+ expect(visit).to match_array(matching_records)
250
+ end
251
+ end
252
+ end
253
+
254
+ context 'with all operators' do
255
+ let(:formatted) {
256
+ %Q{port:#{matching_port}}
257
+ }
258
+ end
210
259
  end
211
260
 
212
- it_should_behave_like 'MetasploitDataModels::Search::Visitor::Relation#visit matching record',
213
- :attribute => :name
261
+ context 'with Mdm::Host' do
262
+ #
263
+ # lets
264
+ #
214
265
 
215
- it_should_behave_like 'MetasploitDataModels::Search::Visitor::Relation#visit matching record',
216
- association: :services,
217
- attribute: :name
266
+ let(:klass) {
267
+ Mdm::Host
268
+ }
218
269
 
219
- context 'with all operators' do
220
- let(:formatted) {
221
- %Q{name:"#{matching_record_name}" services.name:"#{matching_service_name}"}
270
+ #
271
+ # Don't use factories to prevent prefix aliasing when sequences go from 1 to 10 or 10 to 100
272
+ #
273
+
274
+ let(:matching_record_os_flavor) {
275
+ 'mdm_host_os_flavor_a'
222
276
  }
223
277
 
224
- it 'should find only matching record' do
225
- if visit.to_a != [matching_record]
226
- true
278
+ let(:matching_record_os_name) {
279
+ 'mdm_host_os_name_a'
280
+ }
281
+
282
+ let(:matching_record_os_sp) {
283
+ 'mdm_host_os_sp_a'
284
+ }
285
+
286
+ let(:matching_service_name) {
287
+ 'mdm_service_name_a'
288
+ }
289
+
290
+ let(:matching_record_name) {
291
+ 'mdm_host_name_a'
292
+ }
293
+
294
+ let(:matching_service_name) {
295
+ 'mdm_service_name_a'
296
+ }
297
+
298
+ let(:non_matching_record_os_flavor) {
299
+ 'mdm_host_os_flavor_b'
300
+ }
301
+
302
+ let(:non_matching_record_os_name) {
303
+ 'mdm_host_os_name_b'
304
+ }
305
+
306
+ let(:non_matching_record_os_sp) {
307
+ 'mdm_host_os_sp_b'
308
+ }
309
+
310
+ let(:non_matching_service_name) {
311
+ 'mdm_service_name_b'
312
+ }
313
+
314
+ let(:non_matching_record_name) {
315
+ 'mdm_host_name_b'
316
+ }
317
+
318
+ let(:non_matching_service_name) {
319
+ 'mdm_service_name_b'
320
+ }
321
+
322
+ #
323
+ # let!s
324
+ #
325
+
326
+ let!(:matching_record) do
327
+ FactoryGirl.build(
328
+ :mdm_host,
329
+ name: matching_record_name,
330
+ os_flavor: matching_record_os_flavor,
331
+ os_name: matching_record_os_name,
332
+ os_sp: matching_record_os_sp
333
+ )
334
+ end
335
+
336
+ let!(:matching_service) do
337
+ FactoryGirl.create(
338
+ :mdm_service,
339
+ host: matching_record,
340
+ name: matching_service_name
341
+ )
342
+ end
343
+
344
+ let!(:non_matching_record) do
345
+ FactoryGirl.build(
346
+ :mdm_host,
347
+ name: non_matching_record_name,
348
+ os_flavor: non_matching_record_os_flavor,
349
+ os_name: non_matching_record_os_name,
350
+ os_sp: non_matching_record_os_sp
351
+ )
352
+ end
353
+
354
+ let!(:non_matching_service) do
355
+ FactoryGirl.create(
356
+ :mdm_service,
357
+ host: non_matching_record,
358
+ name: non_matching_service_name
359
+ )
360
+ end
361
+
362
+ it_should_behave_like 'MetasploitDataModels::Search::Visitor::Relation#visit matching record',
363
+ :attribute => :name
364
+
365
+ context 'with os' do
366
+ let(:matching_record_os_flavor) {
367
+ 'XP'
368
+ }
369
+
370
+ let(:matching_record_os_name) {
371
+ 'Microsoft Windows'
372
+ }
373
+
374
+ let(:matching_record_os_sp) {
375
+ 'SP1'
376
+ }
377
+
378
+ context 'with a combination of Mdm::Host#os_name and Mdm:Host#os_sp' do
379
+ let(:formatted) {
380
+ %Q{os:"win xp"}
381
+ }
382
+
383
+ it 'finds matching record' do
384
+ expect(visit).to match_array [matching_record]
385
+ end
227
386
  end
228
387
 
229
- expect(visit).to match_array([matching_record])
388
+ context 'with a combination of Mdm::Host#os_flavor and Mdm::Host#os_sp' do
389
+ let(:formatted) {
390
+ %Q{os:"xp sp1"}
391
+ }
392
+
393
+ it 'finds matching record' do
394
+ expect(visit).to match_array [matching_record]
395
+ end
396
+ end
397
+
398
+ context 'with multiple records matching one word' do
399
+ let(:formatted) {
400
+ %Q{os:"win xp"}
401
+ }
402
+
403
+ let(:non_matching_record_os_name) {
404
+ 'Microsoft Windows'
405
+ }
406
+
407
+ it 'finds only matching record by other words refining search' do
408
+ expect(visit).to match_array [matching_record]
409
+ end
410
+ end
411
+ end
412
+
413
+ it_should_behave_like 'MetasploitDataModels::Search::Visitor::Relation#visit matching record',
414
+ :attribute => :os_flavor
415
+
416
+ it_should_behave_like 'MetasploitDataModels::Search::Visitor::Relation#visit matching record',
417
+ :attribute => :os_name
418
+
419
+ it_should_behave_like 'MetasploitDataModels::Search::Visitor::Relation#visit matching record',
420
+ :attribute => :os_sp
421
+
422
+ it_should_behave_like 'MetasploitDataModels::Search::Visitor::Relation#visit matching record',
423
+ association: :services,
424
+ attribute: :name
425
+
426
+ context 'with all operators' do
427
+ let(:formatted) {
428
+ %Q{name:"#{matching_record_name}" os:"#{matching_record_os_name} #{matching_record_os_flavor} #{matching_record_os_sp}" os_flavor:"#{matching_record_os_flavor}" os_name:"#{matching_record_os_name}" os_sp:"#{matching_record_os_sp}" services.name:"#{matching_service_name}"}
429
+ }
430
+
431
+ it 'should find only matching record' do
432
+ if visit.to_a != [matching_record]
433
+ true
434
+ end
435
+
436
+ expect(visit).to match_array([matching_record])
437
+ end
230
438
  end
231
439
  end
232
440
  end