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