ronin-db-activerecord 0.1.0.beta1

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 (135) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.github/workflows/ruby.yml +31 -0
  4. data/.gitignore +13 -0
  5. data/.rspec +1 -0
  6. data/.ruby-version +1 -0
  7. data/.yardopts +1 -0
  8. data/COPYING.txt +165 -0
  9. data/ChangeLog.md +39 -0
  10. data/Gemfile +27 -0
  11. data/README.md +143 -0
  12. data/Rakefile +72 -0
  13. data/db/migrate/0001_create_ronin_ip_address_mac_addresses_table.rb +43 -0
  14. data/db/migrate/0002_create_ronin_vulnerabilities_table.rb +61 -0
  15. data/db/migrate/0003_create_ronin_url_schemes_table.rb +32 -0
  16. data/db/migrate/0004_create_ronin_url_query_param_names_table.rb +32 -0
  17. data/db/migrate/0005_create_ronin_user_names_table.rb +33 -0
  18. data/db/migrate/0006_create_ronin_software_vendors_table.rb +32 -0
  19. data/db/migrate/0007_create_ronin_advisories_table.rb +42 -0
  20. data/db/migrate/0008_create_ronin_host_name_ip_addresses_table.rb +43 -0
  21. data/db/migrate/0009_create_ronin_host_names_table.rb +34 -0
  22. data/db/migrate/0010_create_ronin_arches_table.rb +37 -0
  23. data/db/migrate/0011_create_ronin_email_addresses_table.rb +44 -0
  24. data/db/migrate/0012_create_ronin_oses_table.rb +36 -0
  25. data/db/migrate/0013_create_ronin_organizations_table.rb +31 -0
  26. data/db/migrate/0014_create_ronin_ip_addresses_table.rb +35 -0
  27. data/db/migrate/0015_create_ronin_os_guesses_table.rb +40 -0
  28. data/db/migrate/0016_create_ronin_url_query_params_table.rb +42 -0
  29. data/db/migrate/0017_create_ronin_passwords_table.rb +32 -0
  30. data/db/migrate/0018_create_ronin_open_ports_table.rb +46 -0
  31. data/db/migrate/0019_create_ronin_urls_table.rb +50 -0
  32. data/db/migrate/0020_create_ronin_softwares_table.rb +39 -0
  33. data/db/migrate/0021_create_ronin_mac_addresses_table.rb +33 -0
  34. data/db/migrate/0022_create_ronin_countries_table.rb +34 -0
  35. data/db/migrate/0023_create_ronin_services_table.rb +32 -0
  36. data/db/migrate/0024_create_ronin_credentials_table.rb +44 -0
  37. data/db/migrate/0025_create_ronin_ports_table.rb +33 -0
  38. data/db/migrate/0026_create_ronin_asns_table.rb +44 -0
  39. data/db/migrate/0027_create_ronin_http_query_param_names_table.rb +32 -0
  40. data/db/migrate/0028_create_ronin_http_query_params_table.rb +42 -0
  41. data/db/migrate/0029_create_ronin_http_header_names_table.rb +31 -0
  42. data/db/migrate/0030_create_ronin_http_request_headers_table.rb +41 -0
  43. data/db/migrate/0031_create_ronin_http_response_headers_table.rb +41 -0
  44. data/db/migrate/0032_create_ronin_http_requests_table.rb +41 -0
  45. data/db/migrate/0033_create_ronin_http_responses_table.rb +36 -0
  46. data/db/migrate/0034_create_ronin_service_credentials_table.rb +41 -0
  47. data/db/migrate/0035_create_ronin_web_credentials_table.rb +41 -0
  48. data/gemspec.yml +28 -0
  49. data/lib/ronin/db/address.rb +105 -0
  50. data/lib/ronin/db/advisory.rb +169 -0
  51. data/lib/ronin/db/arch.rb +160 -0
  52. data/lib/ronin/db/asn.rb +212 -0
  53. data/lib/ronin/db/credential.rb +248 -0
  54. data/lib/ronin/db/email_address.rb +225 -0
  55. data/lib/ronin/db/host_name.rb +224 -0
  56. data/lib/ronin/db/host_name_ip_address.rb +65 -0
  57. data/lib/ronin/db/http_header_name.rb +75 -0
  58. data/lib/ronin/db/http_query_param.rb +79 -0
  59. data/lib/ronin/db/http_query_param_name.rb +76 -0
  60. data/lib/ronin/db/http_request.rb +120 -0
  61. data/lib/ronin/db/http_request_header.rb +78 -0
  62. data/lib/ronin/db/http_response.rb +91 -0
  63. data/lib/ronin/db/http_response_header.rb +78 -0
  64. data/lib/ronin/db/ip_address.rb +351 -0
  65. data/lib/ronin/db/ip_address_mac_address.rb +62 -0
  66. data/lib/ronin/db/mac_address.rb +91 -0
  67. data/lib/ronin/db/migrations.rb +137 -0
  68. data/lib/ronin/db/model/has_name.rb +102 -0
  69. data/lib/ronin/db/model/has_unique_name.rb +82 -0
  70. data/lib/ronin/db/model/importable.rb +85 -0
  71. data/lib/ronin/db/model/last_scanned_at.rb +48 -0
  72. data/lib/ronin/db/model.rb +37 -0
  73. data/lib/ronin/db/models.rb +108 -0
  74. data/lib/ronin/db/open_port.rb +148 -0
  75. data/lib/ronin/db/organization.rb +50 -0
  76. data/lib/ronin/db/os.rb +183 -0
  77. data/lib/ronin/db/os_guess.rb +67 -0
  78. data/lib/ronin/db/password.rb +167 -0
  79. data/lib/ronin/db/port.rb +123 -0
  80. data/lib/ronin/db/root.rb +28 -0
  81. data/lib/ronin/db/schema_migration.rb +34 -0
  82. data/lib/ronin/db/service.rb +48 -0
  83. data/lib/ronin/db/service_credential.rb +66 -0
  84. data/lib/ronin/db/software.rb +85 -0
  85. data/lib/ronin/db/software_vendor.rb +42 -0
  86. data/lib/ronin/db/url.rb +497 -0
  87. data/lib/ronin/db/url_query_param.rb +79 -0
  88. data/lib/ronin/db/url_query_param_name.rb +76 -0
  89. data/lib/ronin/db/url_scheme.rb +80 -0
  90. data/lib/ronin/db/user_name.rb +96 -0
  91. data/lib/ronin/db/vulnerability.rb +81 -0
  92. data/lib/ronin/db/web_credential.rb +69 -0
  93. data/ronin-db-activerecord.gemspec +61 -0
  94. data/spec/advisory_spec.rb +277 -0
  95. data/spec/arch_spec.rb +228 -0
  96. data/spec/asn_spec.rb +504 -0
  97. data/spec/credential_spec.rb +362 -0
  98. data/spec/email_address_spec.rb +372 -0
  99. data/spec/host_name_ip_address_spec.rb +8 -0
  100. data/spec/host_name_spec.rb +207 -0
  101. data/spec/http_header_name_spec.rb +25 -0
  102. data/spec/http_query_param_name_spec.rb +25 -0
  103. data/spec/http_query_param_spec.rb +104 -0
  104. data/spec/http_request_header_spec.rb +72 -0
  105. data/spec/http_request_spec.rb +168 -0
  106. data/spec/http_response_header_spec.rb +74 -0
  107. data/spec/http_response_spec.rb +103 -0
  108. data/spec/ip_address_mac_addresses_spec.rb +8 -0
  109. data/spec/ip_address_spec.rb +386 -0
  110. data/spec/mac_address_spec.rb +67 -0
  111. data/spec/migrations_spec.rb +122 -0
  112. data/spec/model/has_name_spec.rb +65 -0
  113. data/spec/model/has_unique_name_spec.rb +61 -0
  114. data/spec/model/importable_spec.rb +105 -0
  115. data/spec/models_spec.rb +60 -0
  116. data/spec/open_port_spec.rb +87 -0
  117. data/spec/organization_spec.rb +10 -0
  118. data/spec/os_guess_spec.rb +43 -0
  119. data/spec/os_spec.rb +114 -0
  120. data/spec/password_spec.rb +81 -0
  121. data/spec/port_spec.rb +102 -0
  122. data/spec/schema_migration_spec.rb +8 -0
  123. data/spec/service_credential_spec.rb +43 -0
  124. data/spec/service_spec.rb +39 -0
  125. data/spec/software_spec.rb +76 -0
  126. data/spec/software_vendor_spec.rb +33 -0
  127. data/spec/spec_helper.rb +13 -0
  128. data/spec/url_query_param_name_spec.rb +25 -0
  129. data/spec/url_query_param_spec.rb +110 -0
  130. data/spec/url_scheme_spec.rb +39 -0
  131. data/spec/url_spec.rb +951 -0
  132. data/spec/user_name_spec.rb +54 -0
  133. data/spec/vulnerability_spec.rb +8 -0
  134. data/spec/web_credential_spec.rb +72 -0
  135. metadata +266 -0
data/spec/asn_spec.rb ADDED
@@ -0,0 +1,504 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/asn'
3
+
4
+ describe Ronin::DB::ASN do
5
+ it "must use the 'ronin_asns' table" do
6
+ expect(described_class.table_name).to eq('ronin_asns')
7
+ end
8
+
9
+ let(:version) { 4 }
10
+ let(:range_start) { '4.0.0.0' }
11
+ let(:range_end) { '4.7.168.255' }
12
+ let(:number) { 3356 }
13
+ let(:country_code) { 'US' }
14
+ let(:name) { 'LEVEL3' }
15
+
16
+ describe "validations" do
17
+ describe "version" do
18
+ it "must require a version" do
19
+ asn = described_class.new(
20
+ range_start: range_start,
21
+ range_end: range_end,
22
+ number: number,
23
+ country_code: country_code,
24
+ name: name
25
+ )
26
+
27
+ expect(asn).to_not be_valid
28
+ expect(asn.errors[:version]).to eq(
29
+ ["can't be blank", "is not included in the list"]
30
+ )
31
+ end
32
+
33
+ it "must accept a value of 4" do
34
+ asn = described_class.new(
35
+ version: 4,
36
+ range_start: range_start,
37
+ range_end: range_end,
38
+ number: number,
39
+ country_code: country_code,
40
+ name: name
41
+ )
42
+
43
+ expect(asn).to be_valid
44
+ end
45
+
46
+ it "must accept a value of 6" do
47
+ asn = described_class.new(
48
+ version: 6,
49
+ range_start: range_start,
50
+ range_end: range_end,
51
+ number: number,
52
+ country_code: country_code,
53
+ name: name
54
+ )
55
+
56
+ expect(asn).to be_valid
57
+ end
58
+ end
59
+
60
+ describe "range_start" do
61
+ it "must require #range_start" do
62
+ asn = described_class.new(
63
+ version: version,
64
+ range_end: range_end,
65
+ number: number,
66
+ country_code: country_code,
67
+ name: name
68
+ )
69
+
70
+ expect(asn).to_not be_valid
71
+ expect(asn.errors[:range_start]).to eq(
72
+ ["can't be blank"]
73
+ )
74
+ end
75
+ end
76
+
77
+ describe "range_end" do
78
+ it "must require #range_end" do
79
+ asn = described_class.new(
80
+ version: version,
81
+ range_start: range_start,
82
+ number: number,
83
+ country_code: country_code,
84
+ name: name
85
+ )
86
+
87
+ expect(asn).to_not be_valid
88
+ expect(asn.errors[:range_end]).to eq(
89
+ ["can't be blank"]
90
+ )
91
+ end
92
+ end
93
+
94
+ describe "number" do
95
+ it "must require #number" do
96
+ asn = described_class.new(
97
+ version: version,
98
+ range_start: range_start,
99
+ range_end: range_end,
100
+ country_code: country_code,
101
+ name: name
102
+ )
103
+
104
+ expect(asn).to_not be_valid
105
+ expect(asn.errors[:number]).to eq(
106
+ ["can't be blank"]
107
+ )
108
+ end
109
+ end
110
+
111
+ describe "country_code" do
112
+ it "must omit the name if unrouted" do
113
+ asn = described_class.new(
114
+ version: version,
115
+ range_start: range_start,
116
+ range_end: range_end,
117
+ number: number
118
+ )
119
+
120
+ expect(asn).to be_valid
121
+ end
122
+ end
123
+
124
+ describe "name" do
125
+ it "must omit the name if unrouted" do
126
+ asn = described_class.new(
127
+ version: version,
128
+ range_start: range_start,
129
+ range_end: range_end,
130
+ number: number
131
+ )
132
+
133
+ expect(asn).to be_valid
134
+ end
135
+ end
136
+ end
137
+
138
+ describe ".v4" do
139
+ subject { described_class }
140
+
141
+ before do
142
+ subject.create(
143
+ version: 6,
144
+ range_start: '64:ff9b::1:0:0',
145
+ range_end: '100::ffff:ffff:ffff:ffff',
146
+ number: 0
147
+ )
148
+
149
+ subject.create(
150
+ version: 4,
151
+ range_start: range_start,
152
+ range_end: range_end,
153
+ number: number,
154
+ country_code: country_code,
155
+ name: name
156
+ )
157
+
158
+ subject.create(
159
+ version: 6,
160
+ range_start: '::',
161
+ range_end: '::1',
162
+ number: 0
163
+ )
164
+ end
165
+
166
+ it "must query all IPv4 ASNs" do
167
+ asns = subject.v4
168
+
169
+ expect(asns).to_not be_empty
170
+ expect(asns.map(&:version)).to all(eq(4))
171
+ end
172
+
173
+ after { described_class.destroy_all }
174
+ end
175
+
176
+ describe ".v6" do
177
+ subject { described_class }
178
+
179
+ before do
180
+ subject.create(
181
+ version: 4,
182
+ range_start: '1.0.0.0',
183
+ range_end: '1.0.0.255',
184
+ number: 13335,
185
+ country_code: 'US',
186
+ name: 'CLOUDFLARENET'
187
+ )
188
+
189
+ subject.create(
190
+ version: 6,
191
+ range_start: '64:ff9b::1:0:0',
192
+ range_end: '100::ffff:ffff:ffff:ffff',
193
+ number: 0
194
+ )
195
+
196
+ subject.create(
197
+ version: 4,
198
+ range_start: '1.0.1.0',
199
+ range_end: '1.0.3.255',
200
+ number: 0
201
+ )
202
+ end
203
+
204
+ it "must query all IPv6 ASNs" do
205
+ asns = subject.v6
206
+
207
+ expect(asns).to_not be_empty
208
+ expect(asns.map(&:version)).to all(eq(6))
209
+ end
210
+
211
+ after { described_class.destroy_all }
212
+ end
213
+
214
+ describe ".with_number" do
215
+ subject { described_class }
216
+
217
+ let(:number) { 3356 }
218
+
219
+ before do
220
+ subject.create(
221
+ version: 4,
222
+ range_start: '3.248.0.0',
223
+ range_end: '3.255.255.255',
224
+ number: 16509,
225
+ country_code: 'US',
226
+ name: 'AMAZON-02'
227
+ )
228
+
229
+ subject.create(
230
+ version: 4,
231
+ range_start: '4.0.0.0',
232
+ range_end: '4.7.168.255',
233
+ number: number,
234
+ country_code: 'US',
235
+ name: 'LEVEL3'
236
+ )
237
+
238
+ subject.create(
239
+ version: 4,
240
+ range_start: '4.7.169.0',
241
+ range_end: '4.23.87.255',
242
+ number: number,
243
+ country_code: 'US',
244
+ name: 'LEVEL3'
245
+ )
246
+
247
+ subject.create(
248
+ version: 4,
249
+ range_start: '4.23.88.0',
250
+ range_end: '4.23.89.255',
251
+ number: 46164,
252
+ country_code: 'US',
253
+ name: 'ATT-MOBILITY-LABS'
254
+ )
255
+ end
256
+
257
+ it "must query the ASN recrds with the matching number" do
258
+ asns = subject.with_number(number)
259
+
260
+ expect(asns.length).to eq(2)
261
+ expect(asns).to all(be_kind_of(described_class))
262
+ expect(asns[0].number).to eq(number)
263
+ expect(asns[1].number).to eq(number)
264
+ end
265
+
266
+ after { described_class.destroy_all }
267
+ end
268
+
269
+ describe ".with_country_code" do
270
+ subject { described_class }
271
+
272
+ let(:country_code) { 'US' }
273
+
274
+ before do
275
+ subject.create(
276
+ version: 4,
277
+ range_start: '3.30.0.0',
278
+ range_end: '3.32.255.255',
279
+ number: 8987,
280
+ country_code: 'IE',
281
+ name: 'AMAZON EXPANSION'
282
+ )
283
+
284
+ subject.create(
285
+ version: 4,
286
+ range_start: '4.0.0.0',
287
+ range_end: '4.7.168.255',
288
+ number: 3356,
289
+ country_code: country_code,
290
+ name: 'LEVEL3'
291
+ )
292
+
293
+ subject.create(
294
+ version: 4,
295
+ range_start: '4.7.169.0',
296
+ range_end: '4.23.87.255',
297
+ number: 3356,
298
+ country_code: country_code,
299
+ name: 'LEVEL3'
300
+ )
301
+
302
+ subject.create(
303
+ version: 4,
304
+ range_start: '5.0.0.0',
305
+ range_end: '5.0.255.255',
306
+ number: 29256,
307
+ country_code: 'SV',
308
+ name: 'INT-PDN-STE-AS STE PDN Internal AS'
309
+ )
310
+ end
311
+
312
+ it "must query the ASN recrds with the matching country code" do
313
+ asns = subject.with_country_code(country_code)
314
+
315
+ expect(asns.length).to eq(2)
316
+ expect(asns).to all(be_kind_of(described_class))
317
+ expect(asns[0].country_code).to eq(country_code)
318
+ expect(asns[1].country_code).to eq(country_code)
319
+ end
320
+
321
+ after { described_class.destroy_all }
322
+ end
323
+
324
+ describe ".with_name" do
325
+ subject { described_class }
326
+
327
+ let(:number) { 3356 }
328
+ let(:name) { 'LEVEL3' }
329
+
330
+ before do
331
+ subject.create(
332
+ version: 4,
333
+ range_start: '3.248.0.0',
334
+ range_end: '3.255.255.255',
335
+ number: 16509,
336
+ country_code: 'US',
337
+ name: 'AMAZON-02'
338
+ )
339
+
340
+ subject.create(
341
+ version: 4,
342
+ range_start: '4.0.0.0',
343
+ range_end: '4.7.168.255',
344
+ number: number,
345
+ country_code: 'US',
346
+ name: name
347
+ )
348
+
349
+ subject.create(
350
+ version: 4,
351
+ range_start: '4.7.169.0',
352
+ range_end: '4.23.87.255',
353
+ number: number,
354
+ country_code: 'US',
355
+ name: name
356
+ )
357
+
358
+ subject.create(
359
+ version: 4,
360
+ range_start: '4.23.88.0',
361
+ range_end: '4.23.89.255',
362
+ number: 46164,
363
+ country_code: 'US',
364
+ name: 'ATT-MOBILITY-LABS'
365
+ )
366
+ end
367
+
368
+ it "must query the ASN recrds with the matching number" do
369
+ asns = subject.with_name(name)
370
+
371
+ expect(asns.length).to eq(2)
372
+ expect(asns).to all(be_kind_of(described_class))
373
+ expect(asns[0].name).to eq(name)
374
+ expect(asns[1].name).to eq(name)
375
+ end
376
+
377
+ after { described_class.destroy_all }
378
+ end
379
+
380
+ describe ".containing_ip" do
381
+ subject { described_class }
382
+
383
+ before do
384
+ subject.create(
385
+ version: version,
386
+ range_start: range_start,
387
+ range_end: range_end,
388
+ number: number,
389
+ country_code: country_code,
390
+ name: name
391
+ )
392
+ end
393
+
394
+ let(:ip) { "4.4.4.4" }
395
+
396
+ it "must find the #{described_class} that contains the given IP address" do
397
+ asn = subject.containing_ip(ip)
398
+
399
+ expect(asn).to be_kind_of(described_class)
400
+ expect(asn.version).to eq(version)
401
+ expect(asn.range_start).to eq(range_start)
402
+ expect(asn.range_end).to eq(range_end)
403
+ expect(asn.number).to eq(number)
404
+ expect(asn.country_code).to eq(country_code)
405
+ expect(asn.name).to eq(name)
406
+ end
407
+
408
+ after { described_class.destroy_all }
409
+ end
410
+
411
+ subject do
412
+ described_class.new(
413
+ version: version,
414
+ range_start: range_start,
415
+ range_end: range_end,
416
+ number: number,
417
+ country_code: country_code,
418
+ name: name
419
+ )
420
+ end
421
+
422
+ describe "#range_start_ipaddr" do
423
+ context "when #range_start is set" do
424
+ it "must return an IPAddr of #range_start" do
425
+ expect(subject.range_start_ipaddr).to be_kind_of(IPAddr)
426
+ expect(subject.range_start_ipaddr.to_s).to eq(subject.range_start)
427
+ end
428
+ end
429
+
430
+ context "when #range_start is nil" do
431
+ subject { described_class.new }
432
+
433
+ it "must return nil" do
434
+ expect(subject.range_start_ipaddr).to be(nil)
435
+ end
436
+ end
437
+ end
438
+
439
+ describe "#range_end_ipaddr" do
440
+ context "when #range_end is set" do
441
+ it "must return an IPAddr of #range_end" do
442
+ expect(subject.range_end_ipaddr).to be_kind_of(IPAddr)
443
+ expect(subject.range_end_ipaddr.to_s).to eq(subject.range_end)
444
+ end
445
+ end
446
+
447
+ context "when #range_end is nil" do
448
+ subject { described_class.new }
449
+
450
+ it "must return nil" do
451
+ expect(subject.range_end_ipaddr).to be(nil)
452
+ end
453
+ end
454
+ end
455
+
456
+ describe "#ip_addresses" do
457
+ let(:address1) { '4.1.1.1' }
458
+ let(:address2) { '4.2.2.2' }
459
+ let(:address3) { '4.3.3.3' }
460
+
461
+ before do
462
+ Ronin::DB::IPAddress.create(address: '3.255.255.255')
463
+ Ronin::DB::IPAddress.create(address: address1)
464
+ Ronin::DB::IPAddress.create(address: address2)
465
+ Ronin::DB::IPAddress.create(address: address3)
466
+ Ronin::DB::IPAddress.create(address: '4.7.169.0')
467
+ end
468
+
469
+ it "must query all IP addresses that are in between the first and last IP address" do
470
+ ip_addresses = subject.ip_addresses
471
+
472
+ expect(ip_addresses.length).to eq(3)
473
+ expect(ip_addresses).to all(be_kind_of(Ronin::DB::IPAddress))
474
+ expect(ip_addresses[0].address).to eq(address1)
475
+ expect(ip_addresses[1].address).to eq(address2)
476
+ expect(ip_addresses[2].address).to eq(address3)
477
+ end
478
+
479
+ after { Ronin::DB::IPAddress.destroy_all }
480
+ end
481
+
482
+ describe "#save" do
483
+ subject do
484
+ described_class.create(
485
+ version: 4,
486
+ range_start: range_start,
487
+ range_end: range_end,
488
+ number: number,
489
+ country_code: country_code,
490
+ name: name
491
+ )
492
+ end
493
+
494
+ it "must set #range_start_hton" do
495
+ expect(subject.range_start_hton).to eq(subject.range_start_ipaddr.hton)
496
+ end
497
+
498
+ it "must set #range_end_hton" do
499
+ expect(subject.range_end_hton).to eq(subject.range_end_ipaddr.hton)
500
+ end
501
+
502
+ after { subject.destroy }
503
+ end
504
+ end