metasploit_data_models 0.18.1 → 0.19.0

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 (51) hide show
  1. checksums.yaml +8 -8
  2. data/app/models/mdm/host.rb +7 -0
  3. data/app/models/mdm/service.rb +30 -1
  4. data/app/models/mdm/tag.rb +10 -0
  5. data/app/models/metasploit_data_models/ip_address/v4/cidr.rb +14 -0
  6. data/app/models/metasploit_data_models/ip_address/v4/nmap.rb +14 -0
  7. data/app/models/metasploit_data_models/ip_address/v4/range.rb +12 -0
  8. data/app/models/metasploit_data_models/ip_address/v4/segment/nmap/list.rb +126 -0
  9. data/app/models/metasploit_data_models/ip_address/v4/segment/nmap/range.rb +12 -0
  10. data/app/models/metasploit_data_models/ip_address/v4/segment/single.rb +123 -0
  11. data/app/models/metasploit_data_models/ip_address/v4/segmented.rb +200 -0
  12. data/app/models/metasploit_data_models/ip_address/v4/single.rb +53 -0
  13. data/app/models/metasploit_data_models/search/operation/ip_address.rb +60 -0
  14. data/app/models/metasploit_data_models/search/operator/ip_address.rb +33 -0
  15. data/app/models/metasploit_data_models/search/visitor/attribute.rb +1 -0
  16. data/app/models/metasploit_data_models/search/visitor/includes.rb +1 -0
  17. data/app/models/metasploit_data_models/search/visitor/joins.rb +1 -0
  18. data/app/models/metasploit_data_models/search/visitor/where.rb +51 -0
  19. data/config/locales/en.yml +35 -4
  20. data/lib/metasploit_data_models/ip_address.rb +5 -0
  21. data/lib/metasploit_data_models/ip_address/cidr.rb +174 -0
  22. data/lib/metasploit_data_models/ip_address/range.rb +181 -0
  23. data/lib/metasploit_data_models/match/child.rb +48 -0
  24. data/lib/metasploit_data_models/match/parent.rb +103 -0
  25. data/lib/metasploit_data_models/version.rb +4 -4
  26. data/metasploit_data_models.gemspec +2 -1
  27. data/spec/app/models/mdm/cred_spec.rb +164 -31
  28. data/spec/app/models/mdm/service_spec.rb +33 -44
  29. data/spec/app/models/metasploit_data_models/ip_address/v4/cidr_spec.rb +121 -0
  30. data/spec/app/models/metasploit_data_models/ip_address/v4/nmap_spec.rb +151 -0
  31. data/spec/app/models/metasploit_data_models/ip_address/v4/range_spec.rb +300 -0
  32. data/spec/app/models/metasploit_data_models/ip_address/v4/segment/nmap/list_spec.rb +278 -0
  33. data/spec/app/models/metasploit_data_models/ip_address/v4/segment/nmap/range_spec.rb +304 -0
  34. data/spec/app/models/metasploit_data_models/ip_address/v4/segment/segmented_spec.rb +29 -0
  35. data/spec/app/models/metasploit_data_models/ip_address/v4/segment/single_spec.rb +315 -0
  36. data/spec/app/models/metasploit_data_models/ip_address/v4/single_spec.rb +183 -0
  37. data/spec/app/models/metasploit_data_models/search/operation/ip_address_spec.rb +182 -0
  38. data/spec/app/models/metasploit_data_models/search/operator/ip_address_spec.rb +19 -0
  39. data/spec/app/models/metasploit_data_models/search/visitor/relation_spec.rb +229 -36
  40. data/spec/dummy/config/application.rb +1 -1
  41. data/spec/dummy/db/structure.sql +3011 -0
  42. data/spec/factories/mdm/services.rb +3 -1
  43. data/spec/lib/metasploit_data_models/ip_address/cidr_spec.rb +350 -0
  44. data/spec/lib/metasploit_data_models/ip_address/range_spec.rb +77 -0
  45. data/spec/lib/metasploit_data_models/match/child_spec.rb +61 -0
  46. data/spec/lib/metasploit_data_models/match/parent_spec.rb +155 -0
  47. data/spec/support/matchers/match_regex_exactly.rb +28 -0
  48. data/spec/support/shared/contexts/rex/text.rb +15 -0
  49. data/spec/support/shared/examples/metasploit_data_models/search/operation/ipaddress/match.rb +109 -0
  50. metadata +58 -9
  51. data/spec/dummy/db/schema.rb +0 -609
@@ -10,7 +10,7 @@ FactoryGirl.define do
10
10
  #
11
11
  name { generate :mdm_service_name }
12
12
  port { generate :port }
13
- proto 'snmp'
13
+ proto { generate :mdm_service_proto }
14
14
  state 'open'
15
15
 
16
16
  factory :web_service do
@@ -23,6 +23,8 @@ FactoryGirl.define do
23
23
  "mdm_service_name#{n}"
24
24
  }
25
25
 
26
+ sequence :mdm_service_proto, Mdm::Service::PROTOS.cycle
27
+
26
28
  port_bits = 16
27
29
  port_limit = 1 << port_bits
28
30
 
@@ -0,0 +1,350 @@
1
+ require 'spec_helper'
2
+
3
+ describe MetasploitDataModels::IPAddress::CIDR do
4
+ subject(:including_class_instance) {
5
+ including_class.new(
6
+ value: formatted_value
7
+ )
8
+ }
9
+
10
+ #
11
+ # lets
12
+ #
13
+
14
+ let(:expected_address) {
15
+ double(
16
+ '#address',
17
+ valid?: true
18
+ )
19
+ }
20
+
21
+ let(:expected_address_class) {
22
+ double(
23
+ '#address_class',
24
+ new: expected_address,
25
+ regexp: expected_address_class_regexp,
26
+ segment_class: segment_class,
27
+ segment_count: segment_count
28
+ )
29
+ }
30
+
31
+ let(:expected_address_class_regexp) {
32
+ /\d+\.\d+/
33
+ }
34
+
35
+ let(:formatted_value) {
36
+ nil
37
+ }
38
+
39
+ let(:including_class) {
40
+ expected_address_class = self.expected_address_class
41
+ described_class = self.described_class
42
+
43
+ Class.new(Metasploit::Model::Base) do
44
+ include described_class
45
+
46
+ #
47
+ # CIDR
48
+ #
49
+
50
+ cidr address_class: expected_address_class
51
+ end
52
+ }
53
+
54
+ let(:segment_bits) {
55
+ 4
56
+ }
57
+
58
+ let(:segment_class) {
59
+ double(
60
+ '#address_class segment_class',
61
+ bits: segment_bits
62
+ )
63
+ }
64
+
65
+ let(:segment_count) {
66
+ 2
67
+ }
68
+
69
+ #
70
+ # Callbacks
71
+ #
72
+
73
+ before(:each) do
74
+ stub_const('IncludingClass', including_class)
75
+ end
76
+
77
+ context 'CONSTANTS' do
78
+ context 'SEPARATOR' do
79
+ subject(:separator) {
80
+ described_class::SEPARATOR
81
+ }
82
+
83
+ it { should == '/' }
84
+ end
85
+ end
86
+
87
+ context 'validation errors on' do
88
+ before(:each) do
89
+ including_class_instance.valid?
90
+ end
91
+
92
+ context '#address' do
93
+ subject(:address_errors) {
94
+ including_class_instance.errors[:address]
95
+ }
96
+
97
+ context 'with #address' do
98
+ let(:expected_address) {
99
+ super().tap { |address|
100
+ expect(address).to receive(:valid?).and_return(address_valid)
101
+ }
102
+ }
103
+
104
+ let(:invalid_error) {
105
+ I18n.translate!('errors.messages.invalid')
106
+ }
107
+
108
+ context 'with valid' do
109
+ let(:address_valid) {
110
+ true
111
+ }
112
+
113
+ it { should_not include(invalid_error) }
114
+ end
115
+
116
+ context 'without valid' do
117
+ let(:address_valid) {
118
+ false
119
+ }
120
+
121
+ it { should include(invalid_error) }
122
+ end
123
+ end
124
+
125
+ context 'without #address' do
126
+ let(:expected_address) {
127
+ nil
128
+ }
129
+
130
+ let(:blank_error) {
131
+ I18n.translate!('errors.messages.blank')
132
+ }
133
+
134
+ it { should include(blank_error) }
135
+ end
136
+ end
137
+
138
+ context '#prefix_length' do
139
+ let(:maximum_prefix_length) {
140
+ segment_count * segment_bits
141
+ }
142
+
143
+ it 'validates it is an integer between 0 and maximum_prefix_length' do
144
+ expect(including_class_instance).to validate_numericality_of(:prefix_length).only_integer.is_greater_than_or_equal_to(0).is_less_than_or_equal_to(maximum_prefix_length)
145
+ end
146
+ end
147
+ end
148
+
149
+ context 'address_class' do
150
+ subject(:address_class) do
151
+ including_class.address_class
152
+ end
153
+
154
+ context 'with call to cidr' do
155
+ it 'is value for :address_class key passed to cidr' do
156
+ expect(address_class).to eq(expected_address_class)
157
+ end
158
+ end
159
+
160
+ context 'without call to cidr' do
161
+ let(:including_class) {
162
+ described_class = self.described_class
163
+
164
+ Class.new(Metasploit::Model::Base) do
165
+ include described_class
166
+ end
167
+ }
168
+
169
+ it { should be_nil }
170
+ end
171
+ end
172
+
173
+ context 'match_regexp' do
174
+ subject(:match_regexp) {
175
+ including_class.match_regexp
176
+ }
177
+
178
+ before(:each) do
179
+ expect(including_class).to receive(:regexp).and_return(/regexp/)
180
+ end
181
+
182
+ it "is regexp pinned with '\\A' and '\\z'" do
183
+ expect(match_regexp).to eq(/\A(?-mix:regexp)\z/)
184
+ end
185
+ end
186
+
187
+ context 'maximum_prefix_length' do
188
+ subject(:maximum_prefix_length) {
189
+ including_class.maximum_prefix_length
190
+ }
191
+
192
+ it 'is the total number of bits across all segments' do
193
+ expect(maximum_prefix_length).to eq(segment_count * segment_bits)
194
+ end
195
+ end
196
+
197
+ context 'regexp' do
198
+ subject(:regexp) {
199
+ including_class.regexp
200
+ }
201
+
202
+ it 'includes address_class.regexp' do
203
+ expect(regexp.to_s).to include(expected_address_class_regexp.to_s)
204
+ end
205
+
206
+ context 'Regexp#names' do
207
+ subject(:names) {
208
+ regexp.names
209
+ }
210
+
211
+ it { should include 'address' }
212
+ it { should include 'prefix_length' }
213
+ end
214
+ end
215
+
216
+ context '#address' do
217
+ subject(:address) {
218
+ including_class_instance.address
219
+ }
220
+
221
+ let(:expected_address_class) {
222
+ Class.new(Metasploit::Model::Base) {
223
+ attr_accessor :value
224
+ }.tap { |address_class|
225
+
226
+ allow(address_class).to receive(:segment_class).and_return(segment_class)
227
+ allow(address_class).to receive(:segment_count).and_return(segment_count)
228
+ }
229
+ }
230
+
231
+ context 'writer' do
232
+ #
233
+ # lets
234
+ #
235
+
236
+ let(:formatted_address) {
237
+ '1.2'
238
+ }
239
+
240
+ it 'sets address_class #value' do
241
+ including_class_instance
242
+
243
+ expect(expected_address_class).to receive(:new).with(
244
+ hash_including(
245
+ value: formatted_value
246
+ )
247
+ )
248
+
249
+ including_class_instance.address = formatted_value
250
+ end
251
+ end
252
+ end
253
+
254
+ context '#prefix_length' do
255
+ subject(:prefix_length) {
256
+ including_class_instance.prefix_length
257
+ }
258
+
259
+ let(:formatted_address) {
260
+ ''
261
+ }
262
+
263
+ let(:formatted_value) {
264
+ "#{formatted_address}/#{formatted_prefix_length}"
265
+ }
266
+
267
+ context 'with integer' do
268
+ let(:formatted_prefix_length) {
269
+ expected_prefix_length.to_s
270
+ }
271
+
272
+ let(:expected_prefix_length) {
273
+ 7
274
+ }
275
+
276
+ it 'sets #prefix_length_before_type_cast to formatted prefix length' do
277
+ expect(including_class_instance.prefix_length_before_type_cast).to eq(formatted_prefix_length)
278
+ end
279
+
280
+ it 'is set to Integer' do
281
+ expect(prefix_length).to eq(expected_prefix_length)
282
+ end
283
+ end
284
+
285
+ context 'without integer' do
286
+ let(:formatted_prefix_length) {
287
+ '255.255.255.0'
288
+ }
289
+
290
+ it 'sets #prefix_length_before_type_cast to formatted prefix length' do
291
+ expect(including_class_instance.prefix_length_before_type_cast).to eq(formatted_prefix_length)
292
+ end
293
+
294
+ it 'is set to the formatted prefix length' do
295
+ expect(prefix_length).to eq(formatted_prefix_length)
296
+ end
297
+ end
298
+ end
299
+
300
+ context '#value' do
301
+ subject(:value) {
302
+ including_class_instance.value
303
+ }
304
+
305
+ let(:formatted_address) {
306
+ '1.2'
307
+ }
308
+
309
+ context "with '/'" do
310
+ let(:formatted_value) {
311
+ "#{formatted_address}/#{formatted_prefix_length}"
312
+ }
313
+
314
+ let(:formatted_prefix_length) {
315
+ '7'
316
+ }
317
+
318
+ it "sets #address to formatted address before '/'" do
319
+ expect(including_class_instance).to receive(:address=).with(formatted_address)
320
+
321
+ including_class_instance.value = formatted_value
322
+ end
323
+
324
+ it "sets #prefix_length to formatted prefix length after '/'" do
325
+ expect(including_class_instance).to receive(:prefix_length=).with(formatted_prefix_length)
326
+
327
+ including_class_instance.value = formatted_value
328
+ end
329
+ end
330
+
331
+ context "without '/'" do
332
+ let(:formatted_value) {
333
+ "#{formatted_address}"
334
+ }
335
+
336
+
337
+ it "sets #address to formatted address before '/'" do
338
+ expect(including_class_instance).to receive(:address=).with(formatted_address)
339
+
340
+ including_class_instance.value = formatted_value
341
+ end
342
+
343
+ it "sets #prefix_length to nil" do
344
+ expect(including_class_instance).to receive(:prefix_length=).with(nil)
345
+
346
+ including_class_instance.value = formatted_value
347
+ end
348
+ end
349
+ end
350
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+
3
+ describe MetasploitDataModels::IPAddress::Range do
4
+ subject(:range) {
5
+ range_class.new
6
+ }
7
+
8
+ #
9
+ # Shared examples
10
+ #
11
+
12
+ shared_examples_for 'extreme' do |extreme|
13
+ context "##{extreme}" do
14
+ subject("range_#{extreme}") {
15
+ range.send(extreme)
16
+ }
17
+
18
+ before(:each) do
19
+ allow(range).to receive(:value).and_return(value)
20
+ end
21
+
22
+ context 'with #value' do
23
+ context 'with Range' do
24
+ let(:value) {
25
+ Range.new(0, 1)
26
+ }
27
+
28
+ it "is Range##{extreme} of #value" do
29
+ expect(send("range_#{extreme}")).to eq(value.send(extreme))
30
+ end
31
+ end
32
+
33
+ context 'without Range' do
34
+ let(:value) {
35
+ 'invalid_value'
36
+ }
37
+
38
+ it { should be_nil }
39
+ end
40
+ end
41
+
42
+ context 'without #value' do
43
+ let(:value) {
44
+ nil
45
+ }
46
+
47
+ it { should be_nil }
48
+ end
49
+ end
50
+ end
51
+
52
+ #
53
+ # lets
54
+ #
55
+
56
+ let(:range_class) {
57
+ described_class = self.described_class
58
+
59
+ Class.new do
60
+ include described_class
61
+ end
62
+ }
63
+
64
+ context 'CONSTANTS' do
65
+ context 'SEPARATOR' do
66
+ subject(:separator) {
67
+ described_class::SEPARATOR
68
+ }
69
+
70
+ it { should == '-' }
71
+ end
72
+ end
73
+
74
+ it_should_behave_like 'extreme', :begin
75
+ it_should_behave_like 'extreme', :end
76
+
77
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe MetasploitDataModels::Match::Child do
4
+ let(:extending_class) {
5
+ # capture as local for Class.new block scope
6
+ described_class = self.described_class
7
+
8
+ Class.new(Metasploit::Model::Base) {
9
+ extend described_class
10
+
11
+ #
12
+ # Attributes
13
+ #
14
+
15
+ # @!attribute value
16
+ # @return [String]
17
+ attr_accessor :value
18
+ }
19
+ }
20
+
21
+ before(:each) do
22
+ stub_const('ExtendingClass', extending_class)
23
+ stub_const('ExtendingClass::REGEXP', /\d+-\d+/)
24
+ end
25
+
26
+ context '#match' do
27
+ subject(:match) {
28
+ extending_class.match(formatted_value)
29
+ }
30
+
31
+ context 'formatted value' do
32
+ context 'with matching' do
33
+ let(:formatted_value) {
34
+ '1-2'
35
+ }
36
+
37
+ it 'returns instance of extending class' do
38
+ expect(match).to be_an extending_class
39
+ end
40
+
41
+ context '#value' do
42
+ subject(:value) {
43
+ match.value
44
+ }
45
+
46
+ it 'is set to formatted value' do
47
+ expect(value).to eq(formatted_value)
48
+ end
49
+ end
50
+ end
51
+
52
+ context 'without matching' do
53
+ let(:formatted_value) do
54
+ '1,2-3'
55
+ end
56
+
57
+ it { should be_nil }
58
+ end
59
+ end
60
+ end
61
+ end