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/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