ronin-db-activerecord 0.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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/url_spec.rb ADDED
@@ -0,0 +1,951 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/url'
3
+
4
+ describe Ronin::DB::URL do
5
+ it "must use the 'ronin_urls' table" do
6
+ expect(described_class.table_name).to eq('ronin_urls')
7
+ end
8
+
9
+ let(:scheme) { 'https' }
10
+ let(:host_name) { 'www.example.com' }
11
+ let(:port) { 8080 }
12
+ let(:path) { '/path' }
13
+ let(:query_params) { {'q' => '1'} }
14
+ let(:query) { 'q=1' }
15
+ let(:fragment) { 'frag' }
16
+
17
+ let(:uri) do
18
+ URI::HTTPS.build(
19
+ scheme: scheme,
20
+ host: host_name,
21
+ port: port,
22
+ path: path,
23
+ query: query,
24
+ fragment: fragment
25
+ )
26
+ end
27
+
28
+ let(:url_scheme) do
29
+ Ronin::DB::URLScheme.find_or_initialize_by(name: scheme)
30
+ end
31
+ let(:url_host_name) do
32
+ Ronin::DB::HostName.find_or_initialize_by(name: host_name)
33
+ end
34
+ let(:url_port) do
35
+ Ronin::DB::Port.find_or_initialize_by(protocol: :tcp, number: port)
36
+ end
37
+ let(:url_query_param_name) do
38
+ Ronin::DB::URLQueryParamName.find_or_initialize_by(
39
+ name: query_params.keys[0]
40
+ )
41
+ end
42
+ let(:url_query_param) do
43
+ Ronin::DB::URLQueryParam.new(
44
+ name: url_query_param_name,
45
+ value: query_params.values[0]
46
+ )
47
+ end
48
+
49
+ subject do
50
+ described_class.new(
51
+ scheme: url_scheme,
52
+ host_name: url_host_name,
53
+ port: url_port,
54
+ path: path,
55
+ query: query,
56
+ fragment: fragment,
57
+ query_params: [url_query_param]
58
+ )
59
+ end
60
+
61
+ describe ".http" do
62
+ subject { described_class }
63
+
64
+ before do
65
+ http_scheme = Ronin::DB::URLScheme.create(name: 'http')
66
+ https_scheme = Ronin::DB::URLScheme.create(name: 'https')
67
+
68
+ host = Ronin::DB::HostName.create(name: 'example.com')
69
+
70
+ port_80 = Ronin::DB::Port.create(number: 80)
71
+ port_443 = Ronin::DB::Port.create(number: 443)
72
+
73
+ described_class.create(
74
+ scheme: http_scheme,
75
+ host_name: host,
76
+ port: port_80,
77
+ path: '/'
78
+ )
79
+
80
+ described_class.create(
81
+ scheme: https_scheme,
82
+ host_name: host,
83
+ port: port_443,
84
+ path: '/'
85
+ )
86
+ end
87
+
88
+ it "must query all #{described_class} with the 'http' scheme" do
89
+ urls = subject.http
90
+
91
+ expect(urls).to_not be_empty
92
+ expect(urls.map { |url| url.scheme.name }.uniq).to eq(['http'])
93
+ end
94
+
95
+ after do
96
+ described_class.destroy_all
97
+ Ronin::DB::URLScheme.destroy_all
98
+ Ronin::DB::HostName.destroy_all
99
+ Ronin::DB::Port.destroy_all
100
+ end
101
+ end
102
+
103
+ describe ".https" do
104
+ subject { described_class }
105
+
106
+ before do
107
+ http_scheme = Ronin::DB::URLScheme.create(name: 'http')
108
+ https_scheme = Ronin::DB::URLScheme.create(name: 'https')
109
+
110
+ host = Ronin::DB::HostName.create(name: 'example.com')
111
+
112
+ port_80 = Ronin::DB::Port.create(number: 80)
113
+ port_443 = Ronin::DB::Port.create(number: 443)
114
+
115
+ described_class.create(
116
+ scheme: http_scheme,
117
+ host_name: host,
118
+ port: port_80,
119
+ path: '/'
120
+ )
121
+
122
+ described_class.create(
123
+ scheme: https_scheme,
124
+ host_name: host,
125
+ port: port_443,
126
+ path: '/'
127
+ )
128
+ end
129
+
130
+ it "must query all #{described_class} with the 'https' scheme" do
131
+ urls = subject.https
132
+
133
+ expect(urls).to_not be_empty
134
+ expect(urls.map { |url| url.scheme.name }.uniq).to eq(['https'])
135
+ end
136
+
137
+ after do
138
+ described_class.destroy_all
139
+ Ronin::DB::URLScheme.destroy_all
140
+ Ronin::DB::HostName.destroy_all
141
+ Ronin::DB::Port.destroy_all
142
+ end
143
+ end
144
+
145
+ describe ".with_host_name" do
146
+ subject { described_class }
147
+
148
+ let(:host_name1) { 'example1.com' }
149
+ let(:host_name2) { 'example2.com' }
150
+
151
+ before do
152
+ http_scheme = Ronin::DB::URLScheme.create(name: 'http')
153
+
154
+ host1 = Ronin::DB::HostName.create(name: host_name1)
155
+ host2 = Ronin::DB::HostName.create(name: host_name2)
156
+
157
+ port_80 = Ronin::DB::Port.create(number: 443)
158
+
159
+ described_class.create(
160
+ scheme: http_scheme,
161
+ host_name: host1,
162
+ port: port_80,
163
+ path: '/'
164
+ )
165
+
166
+ described_class.create(
167
+ scheme: http_scheme,
168
+ host_name: host2,
169
+ port: port_80,
170
+ path: '/'
171
+ )
172
+
173
+ described_class.create(
174
+ scheme: http_scheme,
175
+ host_name: host1,
176
+ port: port_80,
177
+ path: '/other'
178
+ )
179
+ end
180
+
181
+ it "must query all #{described_class} with the matching host name" do
182
+ urls = subject.with_host_name(host_name1)
183
+
184
+ expect(urls).to_not be_empty
185
+ expect(urls.map { |url| url.host_name.name }.uniq).to eq([host_name1])
186
+ end
187
+
188
+ after do
189
+ described_class.destroy_all
190
+ Ronin::DB::URLScheme.destroy_all
191
+ Ronin::DB::HostName.destroy_all
192
+ Ronin::DB::Port.destroy_all
193
+ end
194
+ end
195
+
196
+ describe ".with_port_number" do
197
+ subject { described_class }
198
+
199
+ let(:port_number1) { 80 }
200
+ let(:port_number2) { 443 }
201
+
202
+ before do
203
+ http_scheme = Ronin::DB::URLScheme.create(name: 'http')
204
+ host = Ronin::DB::HostName.create(name: 'example.com')
205
+
206
+ port1 = Ronin::DB::Port.create(number: port_number1)
207
+ port2 = Ronin::DB::Port.create(number: port_number2)
208
+
209
+ described_class.create(
210
+ scheme: http_scheme,
211
+ host_name: host,
212
+ port: port1,
213
+ path: '/'
214
+ )
215
+
216
+ described_class.create(
217
+ scheme: http_scheme,
218
+ host_name: host,
219
+ port: port2,
220
+ path: '/'
221
+ )
222
+
223
+ described_class.create(
224
+ scheme: http_scheme,
225
+ host_name: host,
226
+ port: port1,
227
+ path: '/other'
228
+ )
229
+ end
230
+
231
+ it "must query all #{described_class} with the matching port number" do
232
+ urls = subject.with_port_number(port_number1)
233
+
234
+ expect(urls).to_not be_empty
235
+ expect(urls.map { |url| url.port.number }.uniq).to eq([port_number1])
236
+ end
237
+
238
+ after do
239
+ described_class.destroy_all
240
+ Ronin::DB::URLScheme.destroy_all
241
+ Ronin::DB::HostName.destroy_all
242
+ Ronin::DB::Port.destroy_all
243
+ end
244
+ end
245
+
246
+ describe ".with_path" do
247
+ subject { described_class }
248
+
249
+ let(:host_name1) { 'example1.com' }
250
+ let(:host_name2) { 'example2.com' }
251
+
252
+ before do
253
+ http_scheme = Ronin::DB::URLScheme.create(name: 'http')
254
+ other_host = Ronin::DB::HostName.create(name: 'other-host.com')
255
+ host1 = Ronin::DB::HostName.create(name: host_name1)
256
+ host2 = Ronin::DB::HostName.create(name: host_name2)
257
+ port = Ronin::DB::Port.create(number: 80)
258
+
259
+ described_class.create(
260
+ scheme: http_scheme,
261
+ host_name: other_host,
262
+ port: port,
263
+ path: '/other_path1'
264
+ )
265
+
266
+ described_class.create(
267
+ scheme: http_scheme,
268
+ host_name: host1,
269
+ port: port,
270
+ path: path
271
+ )
272
+
273
+ described_class.create(
274
+ scheme: http_scheme,
275
+ host_name: host2,
276
+ port: port,
277
+ path: path
278
+ )
279
+
280
+ described_class.create(
281
+ scheme: http_scheme,
282
+ host_name: other_host,
283
+ port: port,
284
+ path: '/other_path2'
285
+ )
286
+ end
287
+
288
+ it "must query the URLs with the matching path" do
289
+ urls = subject.with_path(path)
290
+
291
+ expect(urls.length).to eq(2)
292
+ expect(urls).to all(be_kind_of(described_class))
293
+ expect(urls[0].host_name.name).to eq(host_name1)
294
+ expect(urls[0].path).to eq(path)
295
+ expect(urls[1].host_name.name).to eq(host_name2)
296
+ expect(urls[1].path).to eq(path)
297
+ end
298
+
299
+ after do
300
+ described_class.destroy_all
301
+ Ronin::DB::URLScheme.destroy_all
302
+ Ronin::DB::HostName.destroy_all
303
+ Ronin::DB::Port.destroy_all
304
+ end
305
+ end
306
+
307
+ describe ".with_fragment" do
308
+ subject { described_class }
309
+
310
+ let(:host_name1) { 'example1.com' }
311
+ let(:host_name2) { 'example2.com' }
312
+ let(:fragment) { 'fragment' }
313
+
314
+ before do
315
+ http_scheme = Ronin::DB::URLScheme.create(name: 'http')
316
+ other_host = Ronin::DB::HostName.create(name: 'other-host.com')
317
+ host1 = Ronin::DB::HostName.create(name: host_name1)
318
+ host2 = Ronin::DB::HostName.create(name: host_name2)
319
+ port = Ronin::DB::Port.create(number: 80)
320
+
321
+ described_class.create(
322
+ scheme: http_scheme,
323
+ host_name: other_host,
324
+ port: port,
325
+ path: '/other_path1'
326
+ )
327
+
328
+ described_class.create(
329
+ scheme: http_scheme,
330
+ host_name: host1,
331
+ port: port,
332
+ path: '/path1',
333
+ fragment: fragment
334
+ )
335
+
336
+ described_class.create(
337
+ scheme: http_scheme,
338
+ host_name: host2,
339
+ port: port,
340
+ path: '/path2',
341
+ fragment: fragment
342
+ )
343
+
344
+ described_class.create(
345
+ scheme: http_scheme,
346
+ host_name: other_host,
347
+ port: port,
348
+ path: '/other_path2'
349
+ )
350
+ end
351
+
352
+ it "must query the URLs with the matching fragment" do
353
+ urls = subject.with_fragment(fragment)
354
+
355
+ expect(urls.length).to eq(2)
356
+ expect(urls).to all(be_kind_of(described_class))
357
+ expect(urls[0].host_name.name).to eq(host_name1)
358
+ expect(urls[0].fragment).to eq(fragment)
359
+ expect(urls[1].host_name.name).to eq(host_name2)
360
+ expect(urls[1].fragment).to eq(fragment)
361
+ end
362
+
363
+ after do
364
+ described_class.destroy_all
365
+ Ronin::DB::URLScheme.destroy_all
366
+ Ronin::DB::HostName.destroy_all
367
+ Ronin::DB::Port.destroy_all
368
+ end
369
+ end
370
+
371
+ describe ".with_directory" do
372
+ subject { described_class }
373
+
374
+ let(:dir) { '/dir' }
375
+
376
+ before do
377
+ http_scheme = Ronin::DB::URLScheme.create(name: 'http')
378
+ host = Ronin::DB::HostName.create(name: 'example.com')
379
+ port = Ronin::DB::Port.create(number: 80)
380
+
381
+ described_class.create(
382
+ scheme: http_scheme,
383
+ host_name: host,
384
+ port: port,
385
+ path: "#{dir}/foo"
386
+ )
387
+
388
+ described_class.create(
389
+ scheme: http_scheme,
390
+ host_name: host,
391
+ port: port,
392
+ path: '/'
393
+ )
394
+
395
+ described_class.create(
396
+ scheme: http_scheme,
397
+ host_name: host,
398
+ port: port,
399
+ path: "#{dir}/bar"
400
+ )
401
+ end
402
+
403
+ it "must query all #{described_class} with the common directory" do
404
+ urls = subject.with_directory(dir)
405
+
406
+ expect(urls).to_not be_empty
407
+ expect(urls.map(&:path)).to all(start_with(dir))
408
+ end
409
+
410
+ after do
411
+ described_class.destroy_all
412
+ Ronin::DB::URLScheme.destroy_all
413
+ Ronin::DB::HostName.destroy_all
414
+ Ronin::DB::Port.destroy_all
415
+ end
416
+ end
417
+
418
+ describe ".with_basename" do
419
+ subject { described_class }
420
+
421
+ let(:dir) { '/dir' }
422
+ let(:basename) { 'base' }
423
+
424
+ before do
425
+ http_scheme = Ronin::DB::URLScheme.create(name: 'http')
426
+ host = Ronin::DB::HostName.create(name: 'example.com')
427
+ port = Ronin::DB::Port.create(number: 80)
428
+
429
+ described_class.create(
430
+ scheme: http_scheme,
431
+ host_name: host,
432
+ port: port,
433
+ path: "#{dir}/foo"
434
+ )
435
+
436
+ described_class.create(
437
+ scheme: http_scheme,
438
+ host_name: host,
439
+ port: port,
440
+ path: "#{dir}/#{basename}"
441
+ )
442
+
443
+ described_class.create(
444
+ scheme: http_scheme,
445
+ host_name: host,
446
+ port: port,
447
+ path: "#{dir}/bar"
448
+ )
449
+ end
450
+
451
+ it "must query all #{described_class} with the common base name" do
452
+ urls = subject.with_basename(basename)
453
+
454
+ expect(urls).to_not be_empty
455
+ expect(urls.map(&:path)).to all(end_with("/#{basename}"))
456
+ end
457
+
458
+ after do
459
+ described_class.destroy_all
460
+ Ronin::DB::URLScheme.destroy_all
461
+ Ronin::DB::HostName.destroy_all
462
+ Ronin::DB::Port.destroy_all
463
+ end
464
+ end
465
+
466
+ describe ".with_file_ext" do
467
+ subject { described_class }
468
+
469
+ let(:ext) { 'xml' }
470
+
471
+ before do
472
+ http_scheme = Ronin::DB::URLScheme.create(name: 'http')
473
+ host = Ronin::DB::HostName.create(name: 'example.com')
474
+ port = Ronin::DB::Port.create(number: 80)
475
+
476
+ described_class.create(
477
+ scheme: http_scheme,
478
+ host_name: host,
479
+ port: port,
480
+ path: "/foo.#{ext}"
481
+ )
482
+
483
+ described_class.create(
484
+ scheme: http_scheme,
485
+ host_name: host,
486
+ port: port,
487
+ path: '/foo.txt'
488
+ )
489
+
490
+ described_class.create(
491
+ scheme: http_scheme,
492
+ host_name: host,
493
+ port: port,
494
+ path: "/bar.#{ext}"
495
+ )
496
+ end
497
+
498
+ it "must query all #{described_class} with the matching file extension" do
499
+ urls = subject.with_file_ext(ext)
500
+
501
+ expect(urls).to_not be_empty
502
+ expect(urls.map(&:path)).to all(end_with(".#{ext}"))
503
+ end
504
+
505
+ after do
506
+ described_class.destroy_all
507
+ Ronin::DB::URLScheme.destroy_all
508
+ Ronin::DB::HostName.destroy_all
509
+ Ronin::DB::Port.destroy_all
510
+ end
511
+ end
512
+
513
+ describe ".with_query_param" do
514
+ subject { described_class }
515
+
516
+ let(:name) { 'id' }
517
+ let(:value) { '2' }
518
+
519
+ before do
520
+ http_scheme = Ronin::DB::URLScheme.create(name: 'http')
521
+ host = Ronin::DB::HostName.create(name: 'example.com')
522
+ port = Ronin::DB::Port.create(number: 80)
523
+
524
+ query_param_name1 = Ronin::DB::URLQueryParamName.create(name: 'foo')
525
+ query_param_name2 = Ronin::DB::URLQueryParamName.create(name: name)
526
+ query_param_name3 = Ronin::DB::URLQueryParamName.create(name: 'bar')
527
+
528
+ described_class.create(
529
+ scheme: http_scheme,
530
+ host_name: host,
531
+ port: port,
532
+ path: '/foo',
533
+ query_params: [
534
+ Ronin::DB::URLQueryParam.new(
535
+ name: query_param_name1,
536
+ value: 'abc'
537
+ )
538
+ ]
539
+ )
540
+
541
+ described_class.create(
542
+ scheme: http_scheme,
543
+ host_name: host,
544
+ port: port,
545
+ path: '/bar',
546
+ query_params: [
547
+ Ronin::DB::URLQueryParam.new(
548
+ name: query_param_name2,
549
+ value: value
550
+ )
551
+ ]
552
+ )
553
+
554
+ described_class.create(
555
+ scheme: http_scheme,
556
+ host_name: host,
557
+ port: port,
558
+ path: '/baz',
559
+ query_params: [
560
+ Ronin::DB::URLQueryParam.new(
561
+ name: query_param_name3,
562
+ value: 'xyz'
563
+ )
564
+ ]
565
+ )
566
+ described_class.create(
567
+ scheme: http_scheme,
568
+ host_name: host,
569
+ port: port,
570
+ path: '/qux',
571
+ query_params: [
572
+ Ronin::DB::URLQueryParam.new(
573
+ name: query_param_name2,
574
+ value: value
575
+ )
576
+ ]
577
+ )
578
+
579
+ end
580
+
581
+ it "must query all #{described_class} with the matching query_param name and value" do
582
+ urls = subject.with_query_param(name,value)
583
+
584
+ expect(urls).to_not be_empty
585
+ expect(
586
+ urls.flat_map(&:query_params).map { |param|
587
+ [param.name.name, param.value]
588
+ }.uniq
589
+ ).to eq([ [name, value] ])
590
+ end
591
+
592
+ after do
593
+ described_class.destroy_all
594
+ Ronin::DB::URLQueryParamName.destroy_all
595
+ Ronin::DB::URLScheme.destroy_all
596
+ Ronin::DB::HostName.destroy_all
597
+ Ronin::DB::Port.destroy_all
598
+ end
599
+ end
600
+
601
+ describe ".with_query_param_name" do
602
+ subject { described_class }
603
+
604
+ let(:name) { 'id' }
605
+ let(:value1) { 'A' }
606
+ let(:value2) { 'B' }
607
+
608
+ before do
609
+ http_scheme = Ronin::DB::URLScheme.create(name: 'http')
610
+ host = Ronin::DB::HostName.create(name: 'example.com')
611
+ port = Ronin::DB::Port.create(number: 80)
612
+
613
+ query_param_name1 = Ronin::DB::URLQueryParamName.create(name: 'foo')
614
+ query_param_name2 = Ronin::DB::URLQueryParamName.create(name: name)
615
+ query_param_name3 = Ronin::DB::URLQueryParamName.create(name: 'bar')
616
+
617
+ described_class.create(
618
+ scheme: http_scheme,
619
+ host_name: host,
620
+ port: port,
621
+ path: '/foo',
622
+ query_params: [
623
+ Ronin::DB::URLQueryParam.new(
624
+ name: query_param_name1,
625
+ value: 'abc'
626
+ )
627
+ ]
628
+ )
629
+
630
+ described_class.create(
631
+ scheme: http_scheme,
632
+ host_name: host,
633
+ port: port,
634
+ path: '/bar',
635
+ query_params: [
636
+ Ronin::DB::URLQueryParam.new(
637
+ name: query_param_name2,
638
+ value: value1
639
+ )
640
+ ]
641
+ )
642
+
643
+ described_class.create(
644
+ scheme: http_scheme,
645
+ host_name: host,
646
+ port: port,
647
+ path: '/baz',
648
+ query_params: [
649
+ Ronin::DB::URLQueryParam.new(
650
+ name: query_param_name3,
651
+ value: 'xyz'
652
+ )
653
+ ]
654
+ )
655
+ described_class.create(
656
+ scheme: http_scheme,
657
+ host_name: host,
658
+ port: port,
659
+ path: '/qux',
660
+ query_params: [
661
+ Ronin::DB::URLQueryParam.new(
662
+ name: query_param_name2,
663
+ value: value2
664
+ )
665
+ ]
666
+ )
667
+
668
+ end
669
+
670
+ it "must query all #{described_class} with the matching query_param name" do
671
+ urls = subject.with_query_param_name(name)
672
+
673
+ expect(urls).to_not be_empty
674
+ expect(
675
+ urls.flat_map(&:query_params).map { |param|
676
+ [param.name.name, param.value]
677
+ }.uniq
678
+ ).to eq([ [name, value1], [name, value2] ])
679
+ end
680
+
681
+ after do
682
+ described_class.destroy_all
683
+ Ronin::DB::URLQueryParamName.destroy_all
684
+ Ronin::DB::URLScheme.destroy_all
685
+ Ronin::DB::HostName.destroy_all
686
+ Ronin::DB::Port.destroy_all
687
+ end
688
+ end
689
+
690
+ describe ".with_query_param_name" do
691
+ subject { described_class }
692
+
693
+ let(:name1) { 'id1' }
694
+ let(:name2) { 'id2' }
695
+ let(:value) { 'foo' }
696
+
697
+ before do
698
+ http_scheme = Ronin::DB::URLScheme.create(name: 'http')
699
+ host = Ronin::DB::HostName.create(name: 'example.com')
700
+ port = Ronin::DB::Port.create(number: 80)
701
+
702
+ query_param_name1 = Ronin::DB::URLQueryParamName.create(name: 'a')
703
+ query_param_name2 = Ronin::DB::URLQueryParamName.create(name: name1)
704
+ query_param_name3 = Ronin::DB::URLQueryParamName.create(name: 'b')
705
+ query_param_name4 = Ronin::DB::URLQueryParamName.create(name: name2)
706
+
707
+ described_class.create(
708
+ scheme: http_scheme,
709
+ host_name: host,
710
+ port: port,
711
+ path: '/foo',
712
+ query_params: [
713
+ Ronin::DB::URLQueryParam.new(
714
+ name: query_param_name1,
715
+ value: 'abc'
716
+ )
717
+ ]
718
+ )
719
+
720
+ described_class.create(
721
+ scheme: http_scheme,
722
+ host_name: host,
723
+ port: port,
724
+ path: '/bar',
725
+ query_params: [
726
+ Ronin::DB::URLQueryParam.new(
727
+ name: query_param_name2,
728
+ value: value
729
+ )
730
+ ]
731
+ )
732
+
733
+ described_class.create(
734
+ scheme: http_scheme,
735
+ host_name: host,
736
+ port: port,
737
+ path: '/baz',
738
+ query_params: [
739
+ Ronin::DB::URLQueryParam.new(
740
+ name: query_param_name3,
741
+ value: 'xyz'
742
+ )
743
+ ]
744
+ )
745
+ described_class.create(
746
+ scheme: http_scheme,
747
+ host_name: host,
748
+ port: port,
749
+ path: '/qux',
750
+ query_params: [
751
+ Ronin::DB::URLQueryParam.new(
752
+ name: query_param_name4,
753
+ value: value
754
+ )
755
+ ]
756
+ )
757
+
758
+ end
759
+
760
+ it "must query all #{described_class} with the matching query_param value" do
761
+ urls = subject.with_query_param_value(value)
762
+
763
+ expect(urls).to_not be_empty
764
+ expect(
765
+ urls.flat_map(&:query_params).map { |param|
766
+ [param.name.name, param.value]
767
+ }.uniq
768
+ ).to eq([ [name1, value], [name2, value] ])
769
+ end
770
+
771
+ after do
772
+ described_class.destroy_all
773
+ Ronin::DB::URLQueryParamName.destroy_all
774
+ Ronin::DB::URLScheme.destroy_all
775
+ Ronin::DB::HostName.destroy_all
776
+ Ronin::DB::Port.destroy_all
777
+ end
778
+ end
779
+
780
+ describe ".lookup" do
781
+ subject { described_class }
782
+
783
+ let(:scheme) { 'https' }
784
+ let(:host) { 'example.com' }
785
+ let(:port) { 443 }
786
+ let(:path) { '/path' }
787
+
788
+ before do
789
+ http_scheme = Ronin::DB::URLScheme.create(name: 'http')
790
+ https_scheme = Ronin::DB::URLScheme.create(name: scheme)
791
+
792
+ host1 = Ronin::DB::HostName.create(name: 'example1.com')
793
+ host2 = Ronin::DB::HostName.create(name: host)
794
+ host3 = Ronin::DB::HostName.create(name: 'example2.com')
795
+
796
+ port_80 = Ronin::DB::Port.create(number: 80)
797
+ port_443 = Ronin::DB::Port.create(number: port)
798
+
799
+ path1 = '/foo'
800
+ path2 = path
801
+ path3 = '/bar'
802
+
803
+ described_class.create(
804
+ scheme: http_scheme,
805
+ host_name: host1,
806
+ port: port_80,
807
+ path: path1
808
+ )
809
+
810
+ described_class.create(
811
+ scheme: https_scheme,
812
+ host_name: host2,
813
+ port: port_443,
814
+ path: path2
815
+ )
816
+
817
+ described_class.create(
818
+ scheme: https_scheme,
819
+ host_name: host3,
820
+ port: port_443,
821
+ path: path3
822
+ )
823
+ end
824
+
825
+ let(:uri) do
826
+ URI::HTTPS.build(
827
+ scheme: scheme,
828
+ host: host,
829
+ port: port,
830
+ path: path
831
+ )
832
+ end
833
+
834
+ context "when given a URI object" do
835
+ it "must find the #{described_class} with the URI's scheme, host, port, and path" do
836
+ url = subject.lookup(uri)
837
+
838
+ expect(url).to_not be(nil)
839
+ expect(url.to_uri).to eq(uri)
840
+ end
841
+ end
842
+
843
+ context "when given a String" do
844
+ let(:string) { uri.to_s }
845
+
846
+ it "must parse the String before querying the #{described_class} with the URI's same scheme, host, port, and path" do
847
+ url = subject.lookup(string)
848
+
849
+ expect(url).to_not be(nil)
850
+ expect(url.to_uri).to eq(uri)
851
+ end
852
+ end
853
+
854
+ after do
855
+ described_class.destroy_all
856
+ Ronin::DB::URLScheme.destroy_all
857
+ Ronin::DB::HostName.destroy_all
858
+ Ronin::DB::Port.destroy_all
859
+ end
860
+ end
861
+
862
+ describe ".import" do
863
+ context "when given a URI::HTTP object" do
864
+ subject { described_class.import(uri) }
865
+
866
+ it "should parse URL schemes" do
867
+ expect(subject.scheme).not_to be_nil
868
+ expect(subject.scheme.name).to be == scheme
869
+ end
870
+
871
+ it "should parse host names" do
872
+ expect(subject.host_name.name).to be == host_name
873
+ end
874
+
875
+ it "should parse port numbers" do
876
+ expect(subject.port.number).to be == port
877
+ end
878
+
879
+ it "should parse paths" do
880
+ expect(subject.path).to be == path
881
+ end
882
+
883
+ it "should parse query strings" do
884
+ expect(subject.query).to be == query
885
+ end
886
+
887
+ it "should parse URL fragments" do
888
+ expect(subject.fragment).to be == fragment
889
+ end
890
+
891
+ context "when the URIs path is empty" do
892
+ let(:uri) { URI('http://www.example.com') }
893
+
894
+ it "must default the path to '/'" do
895
+ expect(subject.path).to eq('/')
896
+ end
897
+ end
898
+ end
899
+
900
+ after do
901
+ described_class.destroy_all
902
+ Ronin::DB::URLScheme.destroy_all
903
+ Ronin::DB::HostName.destroy_all
904
+ Ronin::DB::Port.destroy_all
905
+ end
906
+ end
907
+
908
+ describe "#host" do
909
+ subject do
910
+ described_class.new(host_name: url_host_name)
911
+ end
912
+
913
+ it "should return the URI host String" do
914
+ expect(subject.host).to be == host_name
915
+ end
916
+ end
917
+
918
+ describe "#to_uri" do
919
+ subject { super().to_uri }
920
+
921
+ it "should convert the scheme" do
922
+ expect(subject.scheme).to be == scheme
923
+ end
924
+
925
+ it "should convert the host name" do
926
+ expect(subject.host).to be == host_name
927
+ end
928
+
929
+ it "should convert the port number" do
930
+ expect(subject.port).to be == port
931
+ end
932
+
933
+ it "should convert the path" do
934
+ expect(subject.path).to be == path
935
+ end
936
+
937
+ it "should convert the query string" do
938
+ expect(subject.query).to be == query
939
+ end
940
+
941
+ it "should convert the fragment" do
942
+ expect(subject.fragment).to be == fragment
943
+ end
944
+ end
945
+
946
+ describe "#to_s" do
947
+ it "should convert the URL back into a String URI" do
948
+ expect(subject.to_s).to be == uri.to_s
949
+ end
950
+ end
951
+ end