ronin-db-activerecord 0.1.6 → 0.2.0.rc1

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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.md +91 -0
  3. data/README.md +49 -1
  4. data/db/migrate/0037_add_created_at_column_to_ronin_ports_table.rb +40 -0
  5. data/db/migrate/0038_add_created_at_column_to_ronin_services_table.rb +40 -0
  6. data/db/migrate/0039_create_ronin_cert_names_table.rb +37 -0
  7. data/db/migrate/0040_create_ronin_cert_issuers_table.rb +52 -0
  8. data/db/migrate/0041_create_ronin_cert_subjects_table.rb +54 -0
  9. data/db/migrate/0042_create_ronin_cert_subject_alt_names_table.rb +42 -0
  10. data/db/migrate/0043_create_ronin_certs_table.rb +61 -0
  11. data/db/migrate/0044_add_cert_id_column_to_ronin_open_ports_table.rb +35 -0
  12. data/db/migrate/0045_create_ronin_notes_table.rb +120 -0
  13. data/db/migrate/0046_create_ronin_web_vulns_table.rb +61 -0
  14. data/db/migrate/0047_create_ronin_phone_numbers_table.rb +47 -0
  15. data/db/migrate/0048_create_ronin_street_addresses_table.rb +46 -0
  16. data/db/migrate/0049_create_ronin_people_table.rb +48 -0
  17. data/db/migrate/0050_create_ronin_personal_connections_table.rb +48 -0
  18. data/db/migrate/0051_create_ronin_personal_phone_numbers_table.rb +48 -0
  19. data/db/migrate/0052_create_ronin_personal_email_addresses_table.rb +45 -0
  20. data/db/migrate/0053_create_ronin_personal_street_addresses_table.rb +47 -0
  21. data/db/migrate/0054_add_type_column_to_ronin_organizations_table.rb +33 -0
  22. data/db/migrate/0055_add_parent_id_column_to_ronin_organizations_table.rb +43 -0
  23. data/db/migrate/0056_create_ronin_organization_departments_table.rb +59 -0
  24. data/db/migrate/0057_create_ronin_organization_members_table.rb +62 -0
  25. data/db/migrate/0058_create_ronin_organization_customers_table.rb +52 -0
  26. data/db/migrate/0059_create_ronin_organization_phone_numbers_table.rb +47 -0
  27. data/db/migrate/0060_create_ronin_organization_email_addresses_table.rb +45 -0
  28. data/db/migrate/0061_create_ronin_organization_street_addresses_table.rb +47 -0
  29. data/db/migrate/0062_add_source_ip_column_to_http_requests_table.rb +30 -0
  30. data/db/migrate/0063_create_ronin_dns_queries_table.rb +41 -0
  31. data/db/migrate/0064_create_ronin_dns_records_table.rb +42 -0
  32. data/db/migrate/0065_create_ronin_organization_host_names_table.rb +43 -0
  33. data/db/migrate/0066_create_ronin_organization_ip_addresses_table.rb +43 -0
  34. data/gemspec.yml +1 -1
  35. data/lib/ronin/db/address.rb +1 -1
  36. data/lib/ronin/db/advisory.rb +66 -1
  37. data/lib/ronin/db/arch.rb +1 -1
  38. data/lib/ronin/db/asn.rb +15 -1
  39. data/lib/ronin/db/cert.rb +501 -0
  40. data/lib/ronin/db/cert_issuer.rb +78 -0
  41. data/lib/ronin/db/cert_name.rb +107 -0
  42. data/lib/ronin/db/cert_organization.rb +127 -0
  43. data/lib/ronin/db/cert_subject.rb +81 -0
  44. data/lib/ronin/db/cert_subject_alt_name.rb +88 -0
  45. data/lib/ronin/db/credential.rb +10 -1
  46. data/lib/ronin/db/dns_query.rb +98 -0
  47. data/lib/ronin/db/dns_record.rb +76 -0
  48. data/lib/ronin/db/email_address.rb +139 -1
  49. data/lib/ronin/db/host_name.rb +45 -1
  50. data/lib/ronin/db/host_name_ip_address.rb +1 -1
  51. data/lib/ronin/db/http_header_name.rb +1 -1
  52. data/lib/ronin/db/http_query_param.rb +1 -1
  53. data/lib/ronin/db/http_query_param_name.rb +1 -1
  54. data/lib/ronin/db/http_request.rb +13 -1
  55. data/lib/ronin/db/http_request_header.rb +1 -1
  56. data/lib/ronin/db/http_response.rb +1 -1
  57. data/lib/ronin/db/http_response_header.rb +1 -1
  58. data/lib/ronin/db/ip_address.rb +46 -1
  59. data/lib/ronin/db/ip_address_mac_address.rb +1 -1
  60. data/lib/ronin/db/mac_address.rb +28 -1
  61. data/lib/ronin/db/migrations.rb +1 -1
  62. data/lib/ronin/db/model/has_name.rb +18 -1
  63. data/lib/ronin/db/model/has_unique_name.rb +1 -1
  64. data/lib/ronin/db/model/importable.rb +1 -1
  65. data/lib/ronin/db/model/last_scanned_at.rb +1 -1
  66. data/lib/ronin/db/model.rb +1 -1
  67. data/lib/ronin/db/models.rb +44 -2
  68. data/lib/ronin/db/note.rb +199 -0
  69. data/lib/ronin/db/open_port.rb +104 -3
  70. data/lib/ronin/db/organization.rb +237 -3
  71. data/lib/ronin/db/organization_customer.rb +73 -0
  72. data/lib/ronin/db/organization_department.rb +97 -0
  73. data/lib/ronin/db/organization_email_address.rb +66 -0
  74. data/lib/ronin/db/organization_host_name.rb +65 -0
  75. data/lib/ronin/db/organization_ip_address.rb +65 -0
  76. data/lib/ronin/db/organization_member.rb +158 -0
  77. data/lib/ronin/db/organization_phone_number.rb +66 -0
  78. data/lib/ronin/db/organization_street_address.rb +66 -0
  79. data/lib/ronin/db/os.rb +35 -1
  80. data/lib/ronin/db/os_guess.rb +1 -1
  81. data/lib/ronin/db/password.rb +84 -1
  82. data/lib/ronin/db/person.rb +455 -0
  83. data/lib/ronin/db/personal_connection.rb +110 -0
  84. data/lib/ronin/db/personal_email_address.rb +66 -0
  85. data/lib/ronin/db/personal_phone_number.rb +76 -0
  86. data/lib/ronin/db/personal_street_address.rb +66 -0
  87. data/lib/ronin/db/phone_number.rb +330 -0
  88. data/lib/ronin/db/port.rb +110 -1
  89. data/lib/ronin/db/service.rb +130 -1
  90. data/lib/ronin/db/service_credential.rb +1 -1
  91. data/lib/ronin/db/software.rb +37 -1
  92. data/lib/ronin/db/software_vendor.rb +1 -1
  93. data/lib/ronin/db/street_address.rb +340 -0
  94. data/lib/ronin/db/url.rb +37 -1
  95. data/lib/ronin/db/url_query_param.rb +1 -1
  96. data/lib/ronin/db/url_query_param_name.rb +9 -1
  97. data/lib/ronin/db/url_scheme.rb +1 -1
  98. data/lib/ronin/db/user_name.rb +58 -1
  99. data/lib/ronin/db/vulnerability.rb +1 -1
  100. data/lib/ronin/db/web_credential.rb +1 -1
  101. data/lib/ronin/db/web_vuln.rb +348 -0
  102. metadata +57 -2
@@ -0,0 +1,455 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
4
+ #
5
+ # Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-db-activerecord is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-db-activerecord is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-db-activerecord. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/db/model'
22
+ require 'ronin/db/model/importable'
23
+
24
+ require 'active_record'
25
+
26
+ module Ronin
27
+ module DB
28
+ #
29
+ # Represents a person.
30
+ #
31
+ # @since 0.2.0
32
+ #
33
+ class Person < ActiveRecord::Base
34
+
35
+ include Model
36
+ include Model::Importable
37
+
38
+ # @!attribute [rw] id
39
+ # The primary key of the person.
40
+ #
41
+ # @return [Integer]
42
+ attribute :id, :integer
43
+
44
+ # @!attribute [rw] full_name
45
+ # The person's full name.
46
+ #
47
+ # @return [String]
48
+ attribute :full_name, :string
49
+ validates :full_name, presence: true,
50
+ uniqueness: true,
51
+ format: {
52
+ with: /\A(?:(?:Mr|Mrs|Ms|Miss|Dr|Sir|Madam|Master|Fr|Rev|Atty)\.?\s)?(?:\p{L}+(['-]\p{L}+)?)(?:(?:\s(?:(?:(?:\p{Lu})\.?)|(?:\p{Lu}\p{L}+(?:['-]\p{L}+)?)))?\s(?:\p{L}+(?:['-]\p{L}+)?)(?:,?\s(?:Jr|Sr|II|III|IV|V|Esq|CPA|Dc|Dds|Vm|Jd|Md|Phd)\.?)?)?\z/,
53
+ message: 'must be a valid personal name'
54
+ }
55
+
56
+ # @!attribute [rw] prefix
57
+ # The person's prefix.
58
+ #
59
+ # @return [String, nil]
60
+ attribute :prefix, :string
61
+ validates :prefix, inclusion: %w[
62
+ Mr Mrs Ms Miss Dr Sir Madam Master Fr Rev Atty
63
+ ],
64
+ allow_nil: true
65
+
66
+ # @!attribute [rw] first_name
67
+ # The person's first name.
68
+ #
69
+ # @return [String]
70
+ attribute :first_name, :string
71
+ validates :first_name, presence: true,
72
+ format: {
73
+ with: /\A\p{L}+(?:['-]\p{L}+)?\z/,
74
+ message: 'must be a valid first name'
75
+ }
76
+
77
+ # @!attribute [rw] middle_name
78
+ # The person's middle name.
79
+ #
80
+ # @return [String, nil]
81
+ attribute :middle_name, :string
82
+ validates :middle_name, format: {
83
+ with: /\A\p{L}+(?:['-]\p{L}+)?\z/,
84
+ message: 'must be a valid middle name'
85
+ },
86
+ allow_nil: true
87
+
88
+ # @!attribute [rw] middle_initial
89
+ # The person's middle initial.
90
+ #
91
+ # @return [String, nil]
92
+ attribute :middle_initial, :string
93
+ validates :middle_initial, presence: true,
94
+ format: {
95
+ with: /\A\p{Lu}\z/,
96
+ message: 'must be a valid middle initial'
97
+ },
98
+ allow_nil: true
99
+
100
+ # @!attribute [rw] last_name
101
+ # The person's last name.
102
+ #
103
+ # @return [String, nil]
104
+ attribute :last_name, :string
105
+ validates :last_name, format: {
106
+ with: /\A\p{L}+(?:['-]\p{L}+)?\z/,
107
+ message: 'must be a valid last name'
108
+ },
109
+ allow_nil: true
110
+
111
+ # @!attribute [rw] suffix
112
+ # The person's suffix.
113
+ #
114
+ # @return [String, nil]
115
+ attribute :suffix, :string
116
+ validates :suffix, inclusion: %w[
117
+ Jr Sr II III IV V Esq CPA Dc Dds Vm Jd Md Phd
118
+ ],
119
+ allow_nil: true
120
+
121
+ # @!attribute [rw] created_at
122
+ # Tracks when the person was first created.
123
+ #
124
+ # @return [Time]
125
+ attribute :created_at, :datetime
126
+
127
+ # @!attribute [rw] personal_street_addresses
128
+ # The association of street addresses associated with the person.
129
+ #
130
+ # @return [Array<PersonalStreetAddress>]
131
+ has_many :personal_street_addresses, dependent: :destroy
132
+
133
+ # @!attribute [rw] street_addresses
134
+ # The street addresses associated with the person.
135
+ #
136
+ # @return [Array<StreetAddress>]
137
+ has_many :street_addresses, through: :personal_street_addresses
138
+
139
+ # @!attribute [rw] personal_phone_numbers
140
+ # The perons's phone numbers.
141
+ #
142
+ # @return [Array<PersonalPhoneNumber>]
143
+ has_many :personal_phone_numbers, dependent: :destroy
144
+
145
+ # @!attribute [rw] phone_numbers
146
+ # The phone numbers associated with the person.
147
+ #
148
+ # @return [Array<PhoneNumber>]
149
+ has_many :phone_numbers, through: :personal_phone_numbers
150
+
151
+ # @!attribute [rw] personal_email_addresss
152
+ # The perons's email addresses.
153
+ #
154
+ # @return [Array<PersonalEmailAddress>]
155
+ has_many :personal_email_addresses, dependent: :destroy
156
+
157
+ # @!attribute [rw] email_addresses
158
+ # The email addresses associated with the person.
159
+ #
160
+ # @return [Array<EmailAddress>]
161
+ has_many :email_addresses, through: :personal_email_addresses
162
+
163
+ # @!attribute [rw] personal_connections
164
+ # The perons's connections with other people.
165
+ #
166
+ # @return [Array<PersonalConnection>]
167
+ has_many :personal_connections, dependent: :destroy
168
+
169
+ # @!attribute [rw] connected_people
170
+ # The other people connected to the person.
171
+ #
172
+ # @return [Array<Person>]
173
+ has_many :connected_people, through: :personal_connections,
174
+ source: :other_person
175
+
176
+ # @!attribute [rw] organization_customers
177
+ # The perons's customer relationships with other organizations.
178
+ #
179
+ # @return [Array<OrganizationCustomer>]
180
+ has_many :organization_customers, class_name: 'OrganizationCustomer',
181
+ foreign_key: :customer_id,
182
+ dependent: :destroy
183
+
184
+ # @!attribute [rw] vendors
185
+ # The vendor organizations of the person.
186
+ #
187
+ # @return [Array<Organization>]
188
+ has_many :vendors, through: :organization_customers
189
+
190
+ # @!attribute [rw] notes
191
+ # The associated notes.
192
+ #
193
+ # @return [Array<Note>]
194
+ has_many :notes, dependent: :destroy
195
+
196
+ #
197
+ # Queries all people associated with the street address.
198
+ #
199
+ # @param [String] address
200
+ # The street address to search for.
201
+ #
202
+ # @return [Array<Person>]
203
+ # The people associated with the street address.
204
+ #
205
+ # @api public
206
+ #
207
+ def self.for_address(address)
208
+ joins(:street_addresses).where(street_addresses: {address: address})
209
+ end
210
+
211
+ #
212
+ # Queries all people associated with the city.
213
+ #
214
+ # @param [String] city
215
+ # The city to search for.
216
+ #
217
+ # @return [Array<Person>]
218
+ # The people associated with the city.
219
+ #
220
+ # @api public
221
+ #
222
+ def self.for_city(city)
223
+ joins(:street_addresses).where(street_addresses: {city: city})
224
+ end
225
+
226
+ #
227
+ # Queries all people associated with the state.
228
+ #
229
+ # @param [String] state
230
+ # The state to search for.
231
+ #
232
+ # @return [Array<Person>]
233
+ # The people associated with the state.
234
+ #
235
+ # @api public
236
+ #
237
+ def self.for_state(state)
238
+ joins(:street_addresses).where(street_addresses: {state: state})
239
+ end
240
+
241
+ #
242
+ # Queries all people associated with the province.
243
+ #
244
+ # @param [String] province
245
+ # The province to search for.
246
+ #
247
+ # @return [Array<Person>]
248
+ # The people associated with the province.
249
+ #
250
+ # @see for_state
251
+ #
252
+ # @api public
253
+ #
254
+ def self.for_province(province)
255
+ for_state(province)
256
+ end
257
+
258
+ #
259
+ # Queries all people associated with the zipcode.
260
+ #
261
+ # @param [String] zipcode
262
+ # The zipcode to search for.
263
+ #
264
+ # @return [Array<Person>]
265
+ # The people associated with the zipcode.
266
+ #
267
+ # @api public
268
+ #
269
+ def self.for_zipcode(zipcode)
270
+ joins(:street_addresses).where(street_addresses: {zipcode: zipcode})
271
+ end
272
+
273
+ #
274
+ # Queries all people associated with the country.
275
+ #
276
+ # @param [String] country
277
+ # The country to search for.
278
+ #
279
+ # @return [Array<Person>]
280
+ # The people associated with the country.
281
+ #
282
+ # @api public
283
+ #
284
+ def self.for_country(country)
285
+ joins(:street_addresses).where(street_addresses: {country: country})
286
+ end
287
+
288
+ #
289
+ # Queries all people with the given prefix.
290
+ #
291
+ # @param [String] prefix
292
+ # The name prefix to search for.
293
+ #
294
+ # @return [Array<Person>]
295
+ # The people with the matching {#prefix}.
296
+ #
297
+ # @api public
298
+ #
299
+ def self.with_prefix(prefix)
300
+ where(prefix: prefix)
301
+ end
302
+
303
+ #
304
+ # Queries all people with the matching first name.
305
+ #
306
+ # @param [String] first_name
307
+ # The first name to search for.
308
+ #
309
+ # @return [Array<Person>]
310
+ # The people with the matching {#first_name}.
311
+ #
312
+ # @api public
313
+ #
314
+ def self.with_first_name(first_name)
315
+ where(first_name: first_name)
316
+ end
317
+
318
+ #
319
+ # Queries all people with the matching middle name.
320
+ #
321
+ # @param [String] middle_name
322
+ # The middle name to search for.
323
+ #
324
+ # @return [Array<Person>]
325
+ # The people with the matching {#middle_name}.
326
+ #
327
+ # @api public
328
+ #
329
+ def self.with_middle_name(middle_name)
330
+ where(middle_name: middle_name)
331
+ end
332
+
333
+ #
334
+ # Queries all people with the matching middle initial.
335
+ #
336
+ # @param [String] initial
337
+ # The middle initial to search for.
338
+ #
339
+ # @return [Array<Person>]
340
+ # The people with the matching {#middle_initial}.
341
+ #
342
+ # @api public
343
+ #
344
+ def self.with_middle_initial(initial)
345
+ where(middle_initial: initial)
346
+ end
347
+
348
+ #
349
+ # Queries all people with the matching last name.
350
+ #
351
+ # @param [String] last_name
352
+ # The last name to search for.
353
+ #
354
+ # @return [Array<Person>]
355
+ # The people with the matching {#last_name}.
356
+ #
357
+ # @api public
358
+ #
359
+ def self.with_last_name(last_name)
360
+ where(last_name: last_name)
361
+ end
362
+
363
+ #
364
+ # Queries all people with the given suffix.
365
+ #
366
+ # @param [String] suffix
367
+ # The name suffix to search for.
368
+ #
369
+ # @return [Array<Person>]
370
+ # The people with the matching {#suffix}.
371
+ #
372
+ # @api public
373
+ #
374
+ def self.with_suffix(suffix)
375
+ where(suffix: suffix)
376
+ end
377
+
378
+ #
379
+ # Looks up a person by name.
380
+ #
381
+ # @param [String] name
382
+ # The person's full name to query.
383
+ #
384
+ # @return [Person, nil]
385
+ # The found person.
386
+ #
387
+ # @api public
388
+ #
389
+ def self.lookup(name)
390
+ find_by(full_name: name)
391
+ end
392
+
393
+ #
394
+ # Parses a person's full name into attributes.
395
+ #
396
+ # @param [String] name
397
+ # The person's full name to parse.
398
+ #
399
+ # @return [Hash{Symbol => String}]
400
+ # The parsed attributes.
401
+ #
402
+ # @api private
403
+ #
404
+ def self.parse(name)
405
+ if (match = name.match(/\A(?:(?<prefix>Mr|Mrs|Ms|Miss|Dr|Sir|Madam|Master|Fr|Rev|Atty)\.?\s)?(?<first_name>\p{L}+(?:['-]\p{L}+)?)(?:(?:\s(?:(?:(?<middle_initial>\p{Lu})\.?)|(?<middle_name>(?<middle_initial>\p{Lu})\p{L}+(?:['-]\p{L}+)?)))?\s(?!Jr|Sr|II|III|IV|V|Esq|CPA|Dc|Dds|Vm|Jd|Md|Phd)(?<last_name>\p{L}+(?:['-]\p{L}+)?)(?:,?\s(?<suffix>Jr|Sr|II|III|IV|V|Esq|CPA|Dc|Dds|Vm|Jd|Md|Phd)\.?)?)?\z/))
406
+ {
407
+ full_name: name,
408
+
409
+ prefix: match[:prefix],
410
+ first_name: match[:first_name],
411
+ middle_name: match[:middle_name],
412
+ middle_initial: match[:middle_initial],
413
+ last_name: match[:last_name],
414
+ suffix: match[:suffix]
415
+ }
416
+ else
417
+ raise(ArgumentError,"invalid personal name: #{name.inspect}")
418
+ end
419
+ end
420
+
421
+ #
422
+ # Imports a person by name.
423
+ #
424
+ # @param [String] name
425
+ # The person's full name.
426
+ #
427
+ # @return [Person]
428
+ # The imported person.
429
+ #
430
+ # @api public
431
+ #
432
+ def self.import(name)
433
+ create(parse(name))
434
+ end
435
+
436
+ #
437
+ # Converts the person into a String.
438
+ #
439
+ # @return [String]
440
+ # The person's full name.
441
+ #
442
+ def to_s
443
+ full_name
444
+ end
445
+
446
+ end
447
+ end
448
+ end
449
+
450
+ require 'ronin/db/personal_street_address'
451
+ require 'ronin/db/personal_phone_number'
452
+ require 'ronin/db/personal_connection'
453
+ require 'ronin/db/organization_customer'
454
+ require 'ronin/db/organization'
455
+ require 'ronin/db/note'
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
4
+ #
5
+ # Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-db-activerecord is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-db-activerecord is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-db-activerecord. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/db/model'
22
+ require 'ronin/db/model/importable'
23
+
24
+ require 'active_record'
25
+
26
+ module Ronin
27
+ module DB
28
+ #
29
+ # Represents a connection between two {Person}s.
30
+ #
31
+ # @since 0.2.0
32
+ #
33
+ class PersonalConnection < ActiveRecord::Base
34
+
35
+ include Model
36
+
37
+ # NOTE: disable STI so we can use the type column as an enum.
38
+ self.inheritance_column = nil
39
+
40
+ # @!attribute [rw] id
41
+ # The primary key of the friendship.
42
+ #
43
+ # @return [Integer]
44
+ attribute :id, :integer
45
+
46
+ # @!attribute [rw] type
47
+ # The type of the connection.
48
+ #
49
+ # @return [String, nil]
50
+ enum :type, {
51
+ friend: 'friend',
52
+ collegue: 'collegue',
53
+ coworker: 'coworker',
54
+
55
+ parent: 'parent',
56
+ mother: 'mother',
57
+ father: 'father',
58
+ aunt: 'aunt',
59
+ uncle: 'uncle',
60
+ brother: 'brother',
61
+ sister: 'sister',
62
+ cousin: 'cousin',
63
+ nephew: 'nephew',
64
+ niece: 'niece',
65
+
66
+ stepmother: 'stepmother',
67
+ stepfather: 'stepfather',
68
+ stepchild: 'stepchild',
69
+ stepbrother: 'stepbrother',
70
+ stepsister: 'stepsister',
71
+
72
+ in_law: 'in-law',
73
+ father_in_law: 'father-in-law',
74
+ mother_in_law: 'mother-in-law',
75
+
76
+ partner: 'partner',
77
+ boyfriend: 'boyfriend',
78
+ girlfriend: 'girlfriend',
79
+ hushband: 'husband',
80
+ wife: 'wife',
81
+
82
+ ex: 'ex',
83
+ ex_husband: 'ex-husband',
84
+ ex_wife: 'ex-wife'
85
+ }, prefix: 'is_'
86
+
87
+ # @!attribute [rw] person
88
+ # The person who is befriending the other person.
89
+ #
90
+ # @return [Person]
91
+ belongs_to :person
92
+
93
+ # @!attribute [rw] friend
94
+ # The friend of the {#person}.
95
+ #
96
+ # @return [Person]
97
+ belongs_to :other_person, class_name: 'Person'
98
+ validates :other_person, uniqueness: {scope: [:person, :type]}
99
+
100
+ # @!attribute [rw] created_at
101
+ # Tracks when the friendship was created.
102
+ #
103
+ # @return [Time]
104
+ attribute :created_at, :datetime
105
+
106
+ end
107
+ end
108
+ end
109
+
110
+ require 'ronin/db/person'
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
4
+ #
5
+ # Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-db-activerecord is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-db-activerecord is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-db-activerecord. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/db/model'
22
+
23
+ require 'active_record'
24
+
25
+ module Ronin
26
+ module DB
27
+ #
28
+ # Represents an email address associated with a {Person}.
29
+ #
30
+ # @since 0.2.0
31
+ #
32
+ class PersonalEmailAddress < ActiveRecord::Base
33
+
34
+ include Model
35
+
36
+ # @!attribute [rw] id
37
+ # Primary key of the personal email address.
38
+ #
39
+ # @return [Integer]
40
+ attribute :id, :integer
41
+
42
+ # @!attribute [rw] person
43
+ # The perons.
44
+ #
45
+ # @return [Person]
46
+ belongs_to :person
47
+
48
+ # @!attribute [rw] email_address
49
+ # The email address associated with the person.
50
+ #
51
+ # @return [EmailAddress]
52
+ belongs_to :email_address
53
+ validates :email_address, uniqueness: {scope: :person_id}
54
+
55
+ # @!attribute [r] created_at
56
+ # Tracks when the personal email address was first created.
57
+ #
58
+ # @return [Time]
59
+ attribute :created_at, :datetime
60
+
61
+ end
62
+ end
63
+ end
64
+
65
+ require 'ronin/db/person'
66
+ require 'ronin/db/email_address'
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
4
+ #
5
+ # Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-db-activerecord is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-db-activerecord is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-db-activerecord. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/db/model'
22
+ require 'ronin/db/model/importable'
23
+
24
+ require 'active_record'
25
+
26
+ module Ronin
27
+ module DB
28
+ #
29
+ # Represents a {PhoneNumber} that belongs to a {Person}.
30
+ #
31
+ # @since 0.2.0
32
+ #
33
+ class PersonalPhoneNumber < ActiveRecord::Base
34
+
35
+ include Model
36
+
37
+ # NOTE: disable STI so we can use the type column as an enum.
38
+ self.inheritance_column = nil
39
+
40
+ # @!attribute [rw] id
41
+ # The primary key of the personal phone number.
42
+ #
43
+ # @return [Integer]
44
+ attribute :id, :integer
45
+
46
+ # @!attribute [rw] type
47
+ # The type of the phone number.
48
+ #
49
+ # @return ["home", "cell", "fax", "voip", nil]
50
+ enum :type, {home: 'home', cell: 'cell', fax: 'fax', voip: 'voip'}
51
+
52
+ # @!attribute [rw] person
53
+ # The person who owns the phone number.
54
+ #
55
+ # @return [Person]
56
+ belongs_to :person
57
+
58
+ # @!attribute [rw] phone_number
59
+ # The phone number.
60
+ #
61
+ # @return [PhoneNumber]
62
+ belongs_to :phone_number
63
+ validates :phone_number, uniqueness: {scope: [:type, :person_id]}
64
+
65
+ # @!attribute [rw] created_at
66
+ # Tracks when the personal phone number was created.
67
+ #
68
+ # @return [Time]
69
+ attribute :created_at, :datetime
70
+
71
+ end
72
+ end
73
+ end
74
+
75
+ require 'ronin/db/person'
76
+ require 'ronin/db/phone_number'