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
@@ -3,6 +3,28 @@ require 'spec_helper'
3
3
  describe Mdm::Service do
4
4
  it_should_behave_like 'Metasploit::Concern.run'
5
5
 
6
+ context 'CONSTANTS' do
7
+ context 'PROTOS' do
8
+ subject(:protos) {
9
+ described_class::PROTOS
10
+ }
11
+
12
+ it { should include 'tcp' }
13
+ it { should include 'udp' }
14
+ end
15
+
16
+ context 'STATES' do
17
+ subject(:states) {
18
+ described_class::STATES
19
+ }
20
+
21
+ it { should include 'closed' }
22
+ it { should include 'filtered' }
23
+ it { should include 'open' }
24
+ it { should include 'unknown' }
25
+ end
26
+ end
27
+
6
28
  context "Associations" do
7
29
 
8
30
  it { should have_many(:task_services).class_name('Mdm::TaskService').dependent(:destroy) }
@@ -33,13 +55,13 @@ describe Mdm::Service do
33
55
  end
34
56
  end
35
57
 
36
- context "search for 'snmp'" do
58
+ context "search for 'tcp'" do
37
59
  it "should find only services that match" do
38
- snmp_service = FactoryGirl.create(:mdm_service)
39
- ftp_service = FactoryGirl.create(:mdm_service, :proto => 'ftp')
40
- search_results = Mdm::Service.search('snmp')
41
- search_results.should include(snmp_service)
42
- search_results.should_not include(ftp_service)
60
+ tcp_service = FactoryGirl.create(:mdm_service, proto: 'tcp')
61
+ udp_service = FactoryGirl.create(:mdm_service, proto: 'udp')
62
+ search_results = Mdm::Service.search('tcp')
63
+ search_results.should include(tcp_service)
64
+ search_results.should_not include(udp_service)
43
65
  end
44
66
  end
45
67
  end
@@ -98,44 +120,11 @@ describe Mdm::Service do
98
120
  end
99
121
 
100
122
  context "validations" do
101
- let(:mdm_service) do
102
- mdm_service = FactoryGirl.build(:mdm_service)
103
- mdm_service.valid?
104
- mdm_service
105
- end
106
-
107
- context "invalid" do
108
- it "should validate presence of :port" do
109
- mdm_service.port = nil
110
- mdm_service.valid?
111
- mdm_service.errors[:port][0].should include "is not a number"
112
- end
123
+ subject(:mdm_service) {
124
+ FactoryGirl.build(:mdm_service)
125
+ }
113
126
 
114
- it "should validate presence of :proto" do
115
- mdm_service.proto = nil
116
- mdm_service.valid?
117
- mdm_service.errors[:proto][0].should include "can't be blank"
118
- end
119
-
120
- it "should not allow non-numeric value for port" do
121
- mdm_service.port = Faker::Lorem.characters(4)
122
- mdm_service.valid?
123
- mdm_service.errors[:port][0].should include "is not a number"
124
- end
125
- end
126
-
127
- context "valid" do
128
- it "should allow numeric value for port" do
129
- mdm_service.port = Faker::Number.number(4)
130
- mdm_service.valid?
131
- mdm_service.should have(0).errors_on(:port)
132
- end
133
-
134
- it "should allow proto" do
135
- mdm_service.proto = "tcp"
136
- mdm_service.valid?
137
- mdm_service.should have(0).errors_on(:proto)
138
- end
139
- end
127
+ it { should validate_numericality_of(:port).only_integer }
128
+ it { should ensure_inclusion_of(:proto).in_array(described_class::PROTOS) }
140
129
  end
141
130
  end
@@ -0,0 +1,121 @@
1
+ require 'spec_helper'
2
+
3
+ describe MetasploitDataModels::IPAddress::V4::CIDR do
4
+ subject(:cidr) {
5
+ described_class.new(
6
+ value: formatted_value
7
+ )
8
+ }
9
+
10
+ let(:formatted_value) {
11
+ nil
12
+ }
13
+
14
+ it { should be_a MetasploitDataModels::IPAddress::CIDR }
15
+
16
+ context 'address_class' do
17
+ subject(:address_class) {
18
+ described_class.address_class
19
+ }
20
+
21
+ it { should == MetasploitDataModels::IPAddress::V4::Single }
22
+ end
23
+
24
+ context 'validations' do
25
+ let(:formatted_address) {
26
+ '1.2.3.4'
27
+ }
28
+
29
+ context 'with IPv4 CIDR notation' do
30
+ let(:formatted_prefix_length) {
31
+ '8'
32
+ }
33
+
34
+ let(:formatted_value) {
35
+ "#{formatted_address}/#{formatted_prefix_length}"
36
+ }
37
+
38
+ it { should be_valid }
39
+ end
40
+
41
+ context 'with IPv4 address' do
42
+ let(:formatted_value) {
43
+ formatted_address
44
+ }
45
+
46
+ it { should_not be_valid }
47
+
48
+ context 'errors' do
49
+ before(:each) do
50
+ cidr.valid?
51
+ end
52
+
53
+ context 'on #address' do
54
+ subject(:address_errors) {
55
+ cidr.errors[:address]
56
+ }
57
+
58
+ it { should be_empty }
59
+ end
60
+
61
+ context 'on #prefix_length' do
62
+ subject(:prefix_length_errors) {
63
+ cidr.errors[:prefix_length]
64
+ }
65
+
66
+ let(:blank_error) {
67
+ I18n.translate!('errors.messages.not_a_number')
68
+ }
69
+
70
+ it { should include(blank_error) }
71
+ end
72
+ end
73
+ end
74
+
75
+ context 'with IPv6 CIDR notation' do
76
+ let(:formatted_value) {
77
+ "#{formatted_address}/#{formatted_prefix_length}"
78
+ }
79
+
80
+ let(:formatted_address) {
81
+ '::1'
82
+ }
83
+
84
+ let(:formatted_prefix_length) {
85
+ '48'
86
+ }
87
+
88
+ it { should_not be_valid }
89
+
90
+ context 'errors' do
91
+ before(:each) do
92
+ cidr.valid?
93
+ end
94
+
95
+ context 'on #address' do
96
+ subject(:address_errors) {
97
+ cidr.errors[:address]
98
+ }
99
+
100
+ let(:invalid_error) {
101
+ I18n.translate!('errors.messages.invalid')
102
+ }
103
+
104
+ it { should include(invalid_error) }
105
+ end
106
+
107
+ context 'on #prefix_length' do
108
+ subject(:prefix_length_errors) {
109
+ cidr.errors[:prefix_length]
110
+ }
111
+
112
+ let(:too_big_error) {
113
+ I18n.translate!('errors.messages.less_than_or_equal_to', count: 32)
114
+ }
115
+
116
+ it { should include(too_big_error) }
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,151 @@
1
+ require 'spec_helper'
2
+
3
+ describe MetasploitDataModels::IPAddress::V4::Nmap do
4
+ subject(:nmap) {
5
+ described_class.new(
6
+ value: formatted_value
7
+ )
8
+ }
9
+
10
+ context 'validation' do
11
+ before(:each) do
12
+ nmap.valid?
13
+ end
14
+
15
+ context 'errors on #segments' do
16
+ subject(:segments_errors) {
17
+ nmap.errors[:segments]
18
+ }
19
+
20
+ context 'with segments' do
21
+ context 'with invalid segment' do
22
+ let(:error) {
23
+ I18n.translate!(
24
+ 'metasploit.model.errors.models.metasploit_data_models/ip_address/v4/segmented.attributes.segments.segment_invalid',
25
+ index: 0,
26
+ segment: '5-4'
27
+ )
28
+ }
29
+
30
+ let(:formatted_value) {
31
+ '5-4.3.2.1'
32
+ }
33
+
34
+ it 'should include index of segment and segment value in the error' do
35
+ expect(segments_errors).to include(error)
36
+ end
37
+ end
38
+
39
+ context 'with valid segments' do
40
+ let(:formatted_value) {
41
+ '1.2.3.4'
42
+ }
43
+
44
+ it { should be_empty }
45
+ end
46
+ end
47
+
48
+ context 'without segments' do
49
+ let(:formatted_value) {
50
+ '::1'
51
+ }
52
+
53
+ let(:length_error) {
54
+ I18n.translate!(
55
+ 'metasploit.model.errors.models.metasploit_data_models/ip_address/v4/segmented.attributes.segments.wrong_length',
56
+ count: 4
57
+ )
58
+ }
59
+
60
+ it { should include length_error }
61
+ end
62
+ end
63
+ end
64
+
65
+ context 'regexp' do
66
+ subject(:regexp) {
67
+ described_class.regexp
68
+ }
69
+
70
+ it 'matches a normal IPv4 address because they are a generate form of Nmap format' do
71
+ expect(regexp).to match_string_exactly('1.2.3.4')
72
+ end
73
+
74
+ it 'matches an IPv4 Nmap address with comma separated list of numbers and ranges for each segment' do
75
+ expect(regexp).to match_string_exactly('1,2-3.4-5,6.7,8.9-10,11-12')
76
+ end
77
+ end
78
+
79
+ context '#value' do
80
+ subject(:value) {
81
+ nmap.value
82
+ }
83
+
84
+ context 'with nil' do
85
+ let(:formatted_value) {
86
+ nil
87
+ }
88
+
89
+ it { should be_nil }
90
+ end
91
+
92
+ context 'with matching formatted value' do
93
+ let(:formatted_value) {
94
+ '1.2-3.4,5-6.7-8,9'
95
+ }
96
+
97
+ it 'has 4 segments' do
98
+ expect(value.length).to eq(4)
99
+ end
100
+
101
+ it 'has MetasploitDataModels::IPAddress::V4::Segment::Nmap::List for segments' do
102
+ expect(
103
+ value.all? { |segment|
104
+ segment.is_a? MetasploitDataModels::IPAddress::V4::Segment::Nmap::List
105
+ }
106
+ ).to eq(true)
107
+ end
108
+
109
+ it 'has segments ordered from high to low' do
110
+ highest_segment = value[0]
111
+
112
+ expect(highest_segment.value[0]).to be_a MetasploitDataModels::IPAddress::V4::Segment::Single
113
+ expect(highest_segment.value[0].value).to eq(1)
114
+
115
+ high_middle_segment = value[1]
116
+
117
+ expect(high_middle_segment.value[0]).to be_a MetasploitDataModels::IPAddress::V4::Segment::Nmap::Range
118
+ expect(high_middle_segment.value[0].begin.value).to eq(2)
119
+ expect(high_middle_segment.value[0].end.value).to eq(3)
120
+
121
+ low_middle_segment = value[2]
122
+
123
+ expect(low_middle_segment.value[0]).to be_a MetasploitDataModels::IPAddress::V4::Segment::Single
124
+ expect(low_middle_segment.value[0].value).to eq(4)
125
+
126
+ expect(low_middle_segment.value[1]).to be_a MetasploitDataModels::IPAddress::V4::Segment::Nmap::Range
127
+ expect(low_middle_segment.value[1].begin.value).to eq(5)
128
+ expect(low_middle_segment.value[1].end.value).to eq(6)
129
+
130
+ low_segment = value[3]
131
+
132
+ expect(low_segment.value[0]).to be_a MetasploitDataModels::IPAddress::V4::Segment::Nmap::Range
133
+ expect(low_segment.value[0].begin.value).to eq(7)
134
+ expect(low_segment.value[0].end.value).to eq(8)
135
+
136
+ expect(low_segment.value[1]).to be_a MetasploitDataModels::IPAddress::V4::Segment::Single
137
+ expect(low_segment.value[1].value).to eq(9)
138
+ end
139
+ end
140
+
141
+ context 'without matching formatted value' do
142
+ let(:formatted_value) {
143
+ '::1'
144
+ }
145
+
146
+ it 'is the formated value' do
147
+ expect(value).to eq(formatted_value)
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,300 @@
1
+ require 'spec_helper'
2
+
3
+ describe MetasploitDataModels::IPAddress::V4::Range do
4
+ subject(:range) {
5
+ described_class.new(
6
+ value: formatted_value
7
+ )
8
+ }
9
+
10
+ #
11
+ # lets
12
+ #
13
+
14
+ let(:formatted_value) {
15
+ nil
16
+ }
17
+
18
+ context 'validations' do
19
+ #
20
+ # lets
21
+ #
22
+
23
+ let(:presence_error) {
24
+ I18n.translate!('errors.messages.blank')
25
+ }
26
+
27
+ let(:invalid_error) {
28
+ I18n.translate!('errors.messages.invalid')
29
+ }
30
+
31
+ #
32
+ # Callbacks
33
+ #
34
+
35
+ before(:each) do
36
+ range.valid?
37
+ end
38
+
39
+ context 'errors on #begin' do
40
+ subject(:begin_errors) {
41
+ range.errors[:begin]
42
+ }
43
+
44
+ context '#begin' do
45
+ context 'with nil' do
46
+ let(:formatted_value) {
47
+ nil
48
+ }
49
+
50
+ it { should include presence_error }
51
+ end
52
+
53
+ context 'with MetasploitDataModels::IPAddress::V4::Single' do
54
+ context 'with valid' do
55
+ let(:formatted_value) {
56
+ '1.1.1.1-256.256.256.256'
57
+ }
58
+
59
+ it { should_not include invalid_error }
60
+ end
61
+
62
+ context 'without valid' do
63
+ let(:formatted_value) {
64
+ '256.256.256.256-257.257.257.257'
65
+ }
66
+
67
+ it { should include invalid_error }
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ context 'errors on #end' do
74
+ subject(:end_errors) {
75
+ range.errors[:end]
76
+ }
77
+
78
+ context '#end' do
79
+ context 'with nil' do
80
+ let(:formatted_value) {
81
+ nil
82
+ }
83
+
84
+ it { should include presence_error }
85
+ end
86
+
87
+ context 'with MetasploitDataModels::IPAddress::V4::Single' do
88
+ context 'with valid' do
89
+ let(:formatted_value) {
90
+ '256.256.256.256-1.1.1.1'
91
+ }
92
+
93
+ it { should_not include invalid_error }
94
+ end
95
+
96
+ context 'without valid' do
97
+ let(:formatted_value) {
98
+ '257.257.257.257-256.256.256.256'
99
+ }
100
+
101
+ it { should include invalid_error }
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ context 'errors on #value' do
108
+ subject(:value_errors) {
109
+ range.errors[:value]
110
+ }
111
+
112
+ let(:error) {
113
+ I18n.translate!(
114
+ 'metasploit.model.errors.models.metasploit_data_models/ip_address/range.attributes.value.order',
115
+ begin: range.begin,
116
+ end: range.end
117
+ )
118
+ }
119
+
120
+ context 'with nil' do
121
+ let(:formatted_value) {
122
+ nil
123
+ }
124
+
125
+ it { should_not include error }
126
+ end
127
+
128
+ context 'with incomparables' do
129
+ let(:formatted_value) {
130
+ 'a-1'
131
+ }
132
+
133
+ it { should_not include error }
134
+ end
135
+
136
+ context 'with numbers' do
137
+ context 'in order' do
138
+ let(:formatted_value) {
139
+ '1.1.1.1-2.2.2.2'
140
+ }
141
+
142
+ it { should_not include error }
143
+ end
144
+
145
+ context 'out of order' do
146
+ let(:formatted_value) {
147
+ '2.2.2.2-1.1.1.1'
148
+ }
149
+
150
+ it { should include error }
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ context 'match_regexp' do
157
+ subject(:match_regexp) do
158
+ described_class::match_regexp
159
+ end
160
+
161
+ it 'matches range exactly' do
162
+ expect(match_regexp).to match_string_exactly('1.1.1.1-255.255.255.255')
163
+ end
164
+ end
165
+
166
+ context 'regexp' do
167
+ subject(:regexp) {
168
+ described_class::regexp
169
+ }
170
+
171
+ it 'does not match a single IPv4 address' do
172
+ expect(regexp).not_to match('255.255.255.255')
173
+ end
174
+
175
+ it 'does not match separator by itself' do
176
+ expect(regexp).not_to match('-')
177
+ end
178
+
179
+ it 'does not match range with only one extreme' do
180
+ expect(regexp).not_to match('1.1.1.1-')
181
+ expect(regexp).not_to match('-255.255.255.255')
182
+ end
183
+
184
+ it 'matches range' do
185
+ expect(regexp).to match_string_exactly('1.1.1.1-255.255.255.255')
186
+ end
187
+ end
188
+
189
+ context '#to_s' do
190
+ subject(:to_s) {
191
+ range.to_s
192
+ }
193
+
194
+ context 'with Range' do
195
+ let(:formatted_value) {
196
+ '1.1.1.1-2.2.2.2'
197
+ }
198
+
199
+ it 'equals the original formatted value' do
200
+ expect(to_s).to eq(formatted_value)
201
+ end
202
+ end
203
+
204
+ context 'without Range' do
205
+ let(:formatted_value) {
206
+ '1..2'
207
+ }
208
+
209
+ it { should == '-' }
210
+ end
211
+ end
212
+
213
+ context '#value' do
214
+ subject(:value) {
215
+ range.value
216
+ }
217
+
218
+ context 'with -' do
219
+ context 'with extremes' do
220
+ let(:formatted_value) {
221
+ '1.1.1.1-2.2.2.2'
222
+ }
223
+
224
+ it { should be_a Range }
225
+
226
+ context 'Range#begin' do
227
+ subject(:range_begin) {
228
+ value.begin
229
+ }
230
+
231
+ it { should be_a MetasploitDataModels::IPAddress::V4::Single }
232
+
233
+ it "is value before '-'" do
234
+ expect(range_begin).to eq(MetasploitDataModels::IPAddress::V4::Single.new(value: '1.1.1.1'))
235
+ end
236
+ end
237
+
238
+ context 'Range#end' do
239
+ subject(:range_end) {
240
+ value.end
241
+ }
242
+
243
+ it { should be_a MetasploitDataModels::IPAddress::V4::Single }
244
+
245
+ it "is value after '-'" do
246
+ expect(range_end).to eq(MetasploitDataModels::IPAddress::V4::Single.new(value: '2.2.2.2'))
247
+ end
248
+ end
249
+ end
250
+
251
+ context 'without extremes' do
252
+ let(:formatted_value) {
253
+ '-'
254
+ }
255
+
256
+ it { should be_a Range }
257
+
258
+ context 'Range#begin' do
259
+ subject(:range_begin) {
260
+ value.begin
261
+ }
262
+
263
+ it { should be_a MetasploitDataModels::IPAddress::V4::Single }
264
+
265
+ context 'MetasploitDataModels::IPAddress::V4::Single#value' do
266
+ subject(:begin_value) {
267
+ range_begin.value
268
+ }
269
+
270
+ it { should == '' }
271
+ end
272
+ end
273
+
274
+ context 'Range#end' do
275
+ subject(:range_end) {
276
+ value.end
277
+ }
278
+
279
+ it { should be_a MetasploitDataModels::IPAddress::V4::Single }
280
+
281
+ context 'MetasploitDataModels::IPAddress::V4::Single#value' do
282
+ subject(:end_value) {
283
+ range_end.value
284
+ }
285
+
286
+ it { should == '' }
287
+ end
288
+ end
289
+ end
290
+ end
291
+
292
+ context 'without -' do
293
+ let(:formatted_value) do
294
+ '1'
295
+ end
296
+
297
+ it { should_not be_a Range }
298
+ end
299
+ end
300
+ end