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
@@ -0,0 +1,362 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/credential'
3
+
4
+ describe Ronin::DB::Credential do
5
+ it "must use the 'ronin_credentials' table" do
6
+ expect(described_class.table_name).to eq('ronin_credentials')
7
+ end
8
+
9
+ let(:name) { 'alice' }
10
+ let(:plain_text) { 'secret' }
11
+
12
+ describe "validations" do
13
+ describe "user_name" do
14
+ context "when email_address is nil" do
15
+ it "must require a user_name" do
16
+ credential = described_class.new(
17
+ password: Ronin::DB::Password.new(plain_text: plain_text)
18
+ )
19
+ expect(credential).to_not be_valid
20
+ expect(credential.errors[:user_name]).to eq(
21
+ ["can't be blank"]
22
+ )
23
+ end
24
+ end
25
+
26
+ context "when email_address is not nil" do
27
+ it "must allow user_name to be nil" do
28
+ credential = described_class.new(
29
+ password: Ronin::DB::Password.new(plain_text: plain_text),
30
+ email_address: Ronin::DB::EmailAddress.new(
31
+ address: 'john.smith@example.com',
32
+ user_name: Ronin::DB::UserName.new(name: 'john.smith'),
33
+ host_name: Ronin::DB::HostName.new(name: 'example.com')
34
+ )
35
+ )
36
+ expect(credential).to be_valid
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "email_address" do
42
+ context "when user_name is nil" do
43
+ it "must require an email_address" do
44
+ credential = described_class.new(
45
+ password: Ronin::DB::Password.new(plain_text: plain_text)
46
+ )
47
+ expect(credential).to_not be_valid
48
+ expect(credential.errors[:email_address]).to eq(
49
+ ["can't be blank"]
50
+ )
51
+ end
52
+ end
53
+
54
+ context "when user_name is not nil" do
55
+ it "must allow email_address to be nil" do
56
+ credential = described_class.new(
57
+ password: Ronin::DB::Password.new(plain_text: plain_text),
58
+ user_name: Ronin::DB::UserName.new(name: 'admin')
59
+ )
60
+ expect(credential).to be_valid
61
+ end
62
+ end
63
+ end
64
+
65
+ describe "password" do
66
+ it "must require a password" do
67
+ credential = described_class.new(
68
+ user_name: Ronin::DB::UserName.new(name: name)
69
+ )
70
+ expect(credential).to_not be_valid
71
+ expect(credential.errors[:password]).to eq(
72
+ ["must exist"]
73
+ )
74
+ end
75
+ end
76
+ end
77
+
78
+ describe ".for_user" do
79
+ before do
80
+ user_name = Ronin::DB::UserName.create(name: name)
81
+ password = Ronin::DB::Password.create(plain_text: plain_text)
82
+
83
+ described_class.create(
84
+ user_name: user_name,
85
+ password: password
86
+ )
87
+ end
88
+
89
+ subject { described_class }
90
+
91
+ it "must query all #{described_class} with the matching user name" do
92
+ credential = subject.for_user(name).first
93
+
94
+ expect(credential).to be_kind_of(described_class)
95
+ expect(credential.user_name.name).to eq(name)
96
+ end
97
+
98
+ after do
99
+ Ronin::DB::Credential.destroy_all
100
+ Ronin::DB::Password.destroy_all
101
+ Ronin::DB::UserName.destroy_all
102
+ end
103
+ end
104
+
105
+ describe ".with_email_address" do
106
+ let(:user) { 'john.smith' }
107
+ let(:domain) { 'example.com' }
108
+ let(:email) { "#{user}@#{domain}" }
109
+
110
+ before do
111
+ user_name = Ronin::DB::UserName.create(name: user)
112
+ host_name = Ronin::DB::HostName.create(name: domain)
113
+ email_address = Ronin::DB::EmailAddress.create(
114
+ address: email,
115
+ user_name: user_name,
116
+ host_name: host_name
117
+ )
118
+
119
+ password = Ronin::DB::Password.create(plain_text: plain_text)
120
+
121
+ credential = described_class.create(
122
+ email_address: email_address,
123
+ password: password
124
+ )
125
+ end
126
+
127
+ subject { described_class }
128
+
129
+ it "must query all #{described_class} with the matching email address" do
130
+ credential = subject.with_email_address(email).first
131
+
132
+ expect(credential).to be_kind_of(described_class)
133
+ expect(credential.email_address.user_name.name).to eq(user)
134
+ expect(credential.email_address.host_name.name).to eq(domain)
135
+ end
136
+
137
+ after do
138
+ Ronin::DB::Credential.destroy_all
139
+ Ronin::DB::Password.destroy_all
140
+ Ronin::DB::EmailAddress.destroy_all
141
+ Ronin::DB::UserName.destroy_all
142
+ Ronin::DB::HostName.destroy_all
143
+ end
144
+ end
145
+
146
+ describe ".with_password" do
147
+ before do
148
+ user_name = Ronin::DB::UserName.create(name: name)
149
+ password = Ronin::DB::Password.create(plain_text: plain_text)
150
+
151
+ described_class.create(
152
+ user_name: user_name,
153
+ password: password
154
+ )
155
+ end
156
+
157
+ subject { described_class }
158
+
159
+ it "must query all #{described_class} with the matching password" do
160
+ credential = subject.with_password(plain_text).first
161
+
162
+ expect(credential).to be_kind_of(described_class)
163
+ expect(credential.password.plain_text).to eq(plain_text)
164
+ end
165
+
166
+ after do
167
+ Ronin::DB::Credential.destroy_all
168
+ Ronin::DB::Password.destroy_all
169
+ Ronin::DB::UserName.destroy_all
170
+ end
171
+ end
172
+
173
+ subject do
174
+ described_class.new(
175
+ user_name: Ronin::DB::UserName.new(name: name),
176
+ password: Ronin::DB::Password.new(plain_text: plain_text)
177
+ )
178
+ end
179
+
180
+ describe ".lookup" do
181
+ subject { described_class }
182
+
183
+ context "when the user-name part contains a '@' character" do
184
+ let(:host) { 'example.com' }
185
+ let(:email) { "#{name}@#{host}" }
186
+ let(:cred) { "#{email}:#{plain_text}" }
187
+
188
+ before do
189
+ described_class.create(
190
+ email_address: Ronin::DB::EmailAddress.create(
191
+ address: "other_user1@other_host1",
192
+ user_name: Ronin::DB::UserName.create(name: 'other_user1'),
193
+ host_name: Ronin::DB::HostName.create(name: 'other_host1')
194
+ ),
195
+ password: Ronin::DB::Password.new(plain_text: 'other_password1')
196
+ )
197
+
198
+ described_class.create(
199
+ email_address: Ronin::DB::EmailAddress.create(
200
+ address: email,
201
+ user_name: Ronin::DB::UserName.create(name: name),
202
+ host_name: Ronin::DB::HostName.create(name: host)
203
+ ),
204
+ password: Ronin::DB::Password.new(plain_text: plain_text)
205
+ )
206
+
207
+ described_class.create(
208
+ email_address: Ronin::DB::EmailAddress.create(
209
+ address: "other_user2@other_host2",
210
+ user_name: Ronin::DB::UserName.create(name: 'other_user2'),
211
+ host_name: Ronin::DB::HostName.create(name: 'other_host2')
212
+ ),
213
+ password: Ronin::DB::Password.new(plain_text: 'other_password2')
214
+ )
215
+ end
216
+
217
+ it "must query the Credential which has the given EmailAddress and Password" do
218
+ credential = subject.lookup(cred)
219
+
220
+ expect(credential).to be_kind_of(described_class)
221
+ expect(credential.email_address).to be_kind_of(Ronin::DB::EmailAddress)
222
+ expect(credential.email_address.address).to eq(email)
223
+ expect(credential.email_address.user_name).to be_kind_of(Ronin::DB::UserName)
224
+ expect(credential.email_address.user_name.name).to eq(name)
225
+ expect(credential.email_address.host_name).to be_kind_of(Ronin::DB::HostName)
226
+ expect(credential.email_address.host_name.name).to eq(host)
227
+ expect(credential.password).to be_kind_of(Ronin::DB::Password)
228
+ expect(credential.password.plain_text).to eq(plain_text)
229
+ end
230
+ end
231
+
232
+ context "when the user-name part does not contain a '@' character" do
233
+ before do
234
+ described_class.create(
235
+ user_name: Ronin::DB::UserName.create(name: 'other_user1'),
236
+ password: Ronin::DB::Password.create(plain_text: 'other_password1')
237
+ )
238
+
239
+ described_class.create(
240
+ user_name: Ronin::DB::UserName.create(name: name),
241
+ password: Ronin::DB::Password.create(plain_text: plain_text)
242
+ )
243
+
244
+ described_class.create(
245
+ user_name: Ronin::DB::UserName.create(name: 'other_user2'),
246
+ password: Ronin::DB::Password.create(plain_text: 'other_password2')
247
+ )
248
+ end
249
+
250
+ let(:cred) { "#{name}:#{plain_text}" }
251
+
252
+ it "must query the Credential which has the given UserName and Password" do
253
+ credential = subject.lookup(cred)
254
+
255
+ expect(credential).to be_kind_of(described_class)
256
+ expect(credential.user_name).to be_kind_of(Ronin::DB::UserName)
257
+ expect(credential.user_name.name).to eq(name)
258
+ expect(credential.password).to be_kind_of(Ronin::DB::Password)
259
+ expect(credential.password.plain_text).to eq(plain_text)
260
+ end
261
+ end
262
+
263
+ context "when the string does not contain a ':' character" do
264
+ let(:cred) { "foo" }
265
+
266
+ it do
267
+ expect {
268
+ subject.lookup(cred)
269
+ }.to raise_error(ArgumentError,"credential must be of the form user:password or email:password: #{cred.inspect}")
270
+ end
271
+ end
272
+
273
+ after do
274
+ described_class.destroy_all
275
+ Ronin::DB::EmailAddress.destroy_all
276
+ Ronin::DB::UserName.destroy_all
277
+ Ronin::DB::HostName.destroy_all
278
+ Ronin::DB::Password.destroy_all
279
+ end
280
+ end
281
+
282
+ describe ".import" do
283
+ subject { described_class }
284
+
285
+ context "when the user-name part contains a '@' character" do
286
+ let(:host) { 'example.com' }
287
+ let(:email) { "#{name}@#{host}" }
288
+ let(:cred) { "#{email}:#{plain_text}" }
289
+
290
+ it "must create a Credential with an EmailAddress and a Password" do
291
+ credential = subject.import(cred)
292
+
293
+ expect(credential).to be_kind_of(described_class)
294
+ expect(credential.email_address).to be_kind_of(Ronin::DB::EmailAddress)
295
+ expect(credential.email_address.id).to_not be(nil)
296
+ expect(credential.email_address.address).to eq(email)
297
+ expect(credential.email_address.user_name).to be_kind_of(Ronin::DB::UserName)
298
+ expect(credential.email_address.user_name.id).to_not be(nil)
299
+ expect(credential.email_address.user_name.name).to eq(name)
300
+ expect(credential.email_address.host_name).to be_kind_of(Ronin::DB::HostName)
301
+ expect(credential.email_address.host_name.id).to_not be(nil)
302
+ expect(credential.email_address.host_name.name).to eq(host)
303
+ expect(credential.password).to be_kind_of(Ronin::DB::Password)
304
+ expect(credential.password.id).to_not be(nil)
305
+ expect(credential.password.plain_text).to eq(plain_text)
306
+ end
307
+ end
308
+
309
+ context "when the user-name part does not contain a '@' character" do
310
+ let(:cred) { "#{name}:#{plain_text}" }
311
+
312
+ it "must create a Credential with an UserName and a Password" do
313
+ credential = subject.import(cred)
314
+
315
+ expect(credential).to be_kind_of(described_class)
316
+ expect(credential.id).to_not be(nil)
317
+ expect(credential.user_name).to be_kind_of(Ronin::DB::UserName)
318
+ expect(credential.user_name.id).to_not be(nil)
319
+ expect(credential.user_name.name).to eq(name)
320
+ expect(credential.password).to be_kind_of(Ronin::DB::Password)
321
+ expect(credential.password.id).to_not be(nil)
322
+ expect(credential.password.plain_text).to eq(plain_text)
323
+ end
324
+ end
325
+
326
+ context "when the string does not contain a ':' character" do
327
+ let(:cred) { "foo" }
328
+
329
+ it do
330
+ expect {
331
+ subject.import(cred)
332
+ }.to raise_error(ArgumentError,"credential must be of the form user:password or email:password: #{cred.inspect}")
333
+ end
334
+ end
335
+
336
+ after do
337
+ described_class.destroy_all
338
+ Ronin::DB::EmailAddress.destroy_all
339
+ Ronin::DB::UserName.destroy_all
340
+ Ronin::DB::HostName.destroy_all
341
+ Ronin::DB::Password.destroy_all
342
+ end
343
+ end
344
+
345
+ describe "#user" do
346
+ it "must return the username String" do
347
+ expect(subject.user).to eq(name)
348
+ end
349
+ end
350
+
351
+ describe "#plain_text" do
352
+ it "should provide the clear-text password String" do
353
+ expect(subject.plain_text).to eq(plain_text)
354
+ end
355
+ end
356
+
357
+ describe "#to_s" do
358
+ it "should include the user name and password" do
359
+ expect(subject.to_s).to eq("#{name}:#{plain_text}")
360
+ end
361
+ end
362
+ end