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,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 a {Person}'s {StreetAddress street address}.
29
+ #
30
+ # @since 0.2.0
31
+ #
32
+ class PersonalStreetAddress < ActiveRecord::Base
33
+
34
+ include Model
35
+
36
+ # @!attribute [rw] id
37
+ # The primary key of the personal street address.
38
+ #
39
+ # @return [Integer]
40
+ attribute :id, :integer
41
+
42
+ # @!attribute [rw] person
43
+ # The personal.
44
+ #
45
+ # @return [Person]
46
+ belongs_to :person
47
+
48
+ # @!attribute [rw] street_address
49
+ # The street address.
50
+ #
51
+ # @return [StreetAddress]
52
+ belongs_to :street_address
53
+ validates :street_address, uniqueness: {scope: :person_id}
54
+
55
+ # @!attribute [rw] created_at
56
+ # Tracks when the personal street 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/street_address'
@@ -0,0 +1,330 @@
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 phone number.
30
+ #
31
+ # @since 0.2.0
32
+ #
33
+ class PhoneNumber < ActiveRecord::Base
34
+
35
+ include Model
36
+ include Model::Importable
37
+
38
+ # @!attribute [rw] id
39
+ # The primary key of the phone number.
40
+ #
41
+ # @return [Integer]
42
+ attribute :id, :integer
43
+
44
+ # @!attribute [rw] number
45
+ # The phone number.
46
+ #
47
+ # @return [String]
48
+ attribute :number, :string
49
+ validates :number, presence: true,
50
+ format: {
51
+ with: /\A(?:\+?\d{1,3}[\s.-])?(?:(?:\(\d{3}\)|\d{3})[\s.-])?\d{3}[\s.-]\d{4}\z/,
52
+ message: 'must be a valid phone number'
53
+ },
54
+ uniqueness: true
55
+
56
+ # @!attribute [rw] country_code
57
+ # The phone number country code (the first one or two digits).
58
+ #
59
+ # @return [String, nil]
60
+ attribute :country_code, :string
61
+ validates :country_code, format: {
62
+ with: /\A\d{1,3}\z/,
63
+ message: 'must be a valid country code number'
64
+ },
65
+ allow_nil: true
66
+
67
+ # @!attribute [rw] area_code
68
+ # The phone number area code (three digits after the country code).
69
+ #
70
+ # @return [String, nil]
71
+ attribute :area_code, :string
72
+ validates :area_code, format: {
73
+ with: /\A\d{3}\z/,
74
+ message: 'must be a valid area code number'
75
+ },
76
+ allow_nil: true
77
+
78
+ # @!attribute [rw] prefix
79
+ # The phone number prefix (three digits after the area code).
80
+ #
81
+ # @return [String]
82
+ attribute :prefix, :string
83
+ validates :prefix, presence: true,
84
+ format: {
85
+ with: /\A\d{3}\z/,
86
+ message: 'must be a valid prefix number'
87
+ }
88
+
89
+ # @!attribute [rw] line_number
90
+ # The phone number line number (last four digits).
91
+ #
92
+ # @return [String]
93
+ attribute :line_number, :string
94
+ validates :line_number, presence: true,
95
+ format: {
96
+ with: /\A\d{4}\z/,
97
+ message: 'must be a valid line number'
98
+ }
99
+
100
+ # @!attribute [rw] created_at
101
+ # Tracks when the phone number was first created.
102
+ #
103
+ # @return [Time]
104
+ attribute :created_at, :datetime
105
+
106
+ # @!attribute [rw] personal_phone_numbers
107
+ # The association of people that use this phone number.
108
+ #
109
+ # @return [Array<PersonalPhoneNumber>]
110
+ has_many :personal_phone_numbers, dependent: :destroy
111
+
112
+ # @!attribute [rw] people
113
+ # The people that use this phone number.
114
+ #
115
+ # @return [Array<Person>]
116
+ has_many :people, through: :personal_phone_numbers
117
+
118
+ # @!attribute [rw] organization_phone_number
119
+ # The association of the organization that use the phone number.
120
+ #
121
+ # @return [OrganiationPhoneNumber, nil]
122
+ has_one :organization_phone_number, dependent: :destroy
123
+
124
+ # @!attribute [rw] organization_department
125
+ # The organization department that uses the email address.
126
+ #
127
+ # @return [OrganizationDepartment, nil]
128
+ has_one :organization_department, dependent: :nullify
129
+
130
+ # @!attribute [rw] organization_members
131
+ # The organization member that use the phone number.
132
+ #
133
+ # @return [OrganizationMember, nil]
134
+ has_one :organization_member, dependent: :nullify
135
+
136
+ # @!attribute [rw] notes
137
+ # The associated notes.
138
+ #
139
+ # @return [Array<Note>]
140
+ has_many :notes, dependent: :destroy
141
+
142
+ #
143
+ # Looks up the phone number.
144
+ #
145
+ # @param [String] number
146
+ # The phone number to query.
147
+ #
148
+ # @return [PhoneNumber, nil]
149
+ # The found phone number.
150
+ #
151
+ # @api public
152
+ #
153
+ def self.lookup(number)
154
+ find_by(number: number)
155
+ end
156
+
157
+ #
158
+ # Parses the phone number.
159
+ #
160
+ # @param [String] number
161
+ # The raw phone number to parse.
162
+ #
163
+ # @return [Hash{Symbol => String,nil}]
164
+ # The parsed attributes of the phone number.
165
+ #
166
+ # @api private
167
+ #
168
+ def self.parse(number)
169
+ if (match = number.match(/\A(?:(?:\+?(?<country_code>\d{1,3})[\s.-])?(?:\((?<area_code>\d{3})\)|(?<area_code>\d{3}))[\s.-])?(?<prefix>\d{3})[\s.-](?<line_number>\d{4})\z/))
170
+ {
171
+ number: number,
172
+
173
+ country_code: match[:country_code],
174
+ area_code: match[:area_code],
175
+ prefix: match[:prefix],
176
+ line_number: match[:line_number]
177
+ }
178
+ else
179
+ raise(ArgumentError,"invalid phone number: #{number.inspect}")
180
+ end
181
+ end
182
+
183
+ #
184
+ # Imports an phone number.
185
+ #
186
+ # @param [String] number
187
+ # The phone number to import.
188
+ #
189
+ # @return [PhoneNumber]
190
+ # The imported phone number.
191
+ #
192
+ # @api public
193
+ #
194
+ def self.import(number)
195
+ create(parse(number))
196
+ end
197
+
198
+ #
199
+ # Queries all phone numbers associated with the person.
200
+ #
201
+ # @param [String] full_name
202
+ # The person's full name.
203
+ #
204
+ # @return [Array<PhoneNumber>]
205
+ # The phone numbers associated with the person.
206
+ #
207
+ # @api public
208
+ #
209
+ def self.for_person(full_name)
210
+ joins(:people).where(people: {full_name: full_name})
211
+ end
212
+
213
+ #
214
+ # Queries all phone numbers associated with the organization name.
215
+ #
216
+ # @param [String] name
217
+ # The organization's name.
218
+ #
219
+ # @return [Array<PhoneNumber>]
220
+ # The phone numbers associated with the organization.
221
+ #
222
+ # @api public
223
+ #
224
+ def self.for_organization(name)
225
+ joins(organization_phone_number: :organization).where(
226
+ organization_phone_number: {
227
+ ronin_organizations: {name: name}
228
+ }
229
+ )
230
+ end
231
+
232
+ #
233
+ # Finds all similar phone numbers with the matching phone number
234
+ # components.
235
+ #
236
+ # @param [String] number
237
+ # The phone number to parse and search for.
238
+ #
239
+ # @return [Array<PhoneNumber>]
240
+ # The similar phone numbers.
241
+ #
242
+ # @api public
243
+ #
244
+ def self.similar_to(number)
245
+ attributes = parse(number)
246
+ attributes.delete(:number)
247
+ attributes.compact!
248
+
249
+ where(**attributes)
250
+ end
251
+
252
+ #
253
+ # Finds all phone numbers with the matching country code.
254
+ #
255
+ # @param [String] country_code
256
+ # The country code to search for.
257
+ #
258
+ # @return [Array<PhoneNumber>]
259
+ # The phone numbers with the matching country code.
260
+ #
261
+ # @api public
262
+ #
263
+ def self.with_country_code(country_code)
264
+ where(country_code: country_code)
265
+ end
266
+
267
+ #
268
+ # Finds all phone numbers with the matching area code.
269
+ #
270
+ # @param [String] area_code
271
+ # The area code to search for.
272
+ #
273
+ # @return [Array<PhoneNumber>]
274
+ # The phone numbers with the matching area code.
275
+ #
276
+ # @api public
277
+ #
278
+ def self.with_area_code(area_code)
279
+ where(area_code: area_code)
280
+ end
281
+
282
+ #
283
+ # Finds all phone numbers with the matching prefix.
284
+ #
285
+ # @param [String] prefix
286
+ # The prefix to search for.
287
+ #
288
+ # @return [Array<PhoneNumber>]
289
+ # The phone numbers with the matching prefix.
290
+ #
291
+ # @api public
292
+ #
293
+ def self.with_prefix(prefix)
294
+ where(prefix: prefix)
295
+ end
296
+
297
+ #
298
+ # Finds all phone numbers with the matching line number.
299
+ #
300
+ # @param [String] line_number
301
+ # The line number to search for.
302
+ #
303
+ # @return [Array<PhoneNumber>]
304
+ # The phone numbers with the matching line number.
305
+ #
306
+ # @api public
307
+ #
308
+ def self.with_line_number(line_number)
309
+ where(line_number: line_number)
310
+ end
311
+
312
+ #
313
+ # Converts the phone number to a String.
314
+ #
315
+ # @return [String]
316
+ #
317
+ def to_s
318
+ number
319
+ end
320
+
321
+ end
322
+ end
323
+ end
324
+
325
+ require 'ronin/db/personal_phone_number'
326
+ require 'ronin/db/person'
327
+ require 'ronin/db/organization_phone_number'
328
+ require 'ronin/db/organization_department'
329
+ require 'ronin/db/organization_member'
330
+ require 'ronin/db/note'
data/lib/ronin/db/port.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
4
4
  #
5
- # Copyright (c) 2022-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
+ # Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
6
6
  #
7
7
  # ronin-db-activerecord is free software: you can redistribute it and/or modify
8
8
  # it under the terms of the GNU Lesser General Public License as published
@@ -56,12 +56,120 @@ module Ronin
56
56
  },
57
57
  uniqueness: {scope: :protocol}
58
58
 
59
+ # @!attribute [r] created_at
60
+ # Defines the created_at timestamp
61
+ #
62
+ # @return [Time]
63
+ #
64
+ # @since 0.2.0
65
+ attribute :created_at, :datetime
66
+
59
67
  # @!attribute [rw] open_ports
60
68
  # The open ports.
61
69
  #
62
70
  # @return [Array<OpenPort>]
63
71
  has_many :open_ports, dependent: :destroy
64
72
 
73
+ # @!attribute [rw] ip_addresses
74
+ # The IP Addresses that that have this port open.
75
+ #
76
+ # @return [Array<IPAddress>]
77
+ #
78
+ # @since 0.2.0
79
+ has_many :ip_addresses, through: :open_ports
80
+
81
+ # @!attribute [rw] services
82
+ # The services that that use this port.
83
+ #
84
+ # @return [Array<Service>]
85
+ #
86
+ # @since 0.2.0
87
+ has_many :services, through: :open_ports
88
+
89
+ # @!attribute [rw] notes
90
+ # The associated notes.
91
+ #
92
+ # @return [Array<Note>]
93
+ #
94
+ # @since 0.2.0
95
+ has_many :notes, dependent: :destroy
96
+
97
+ #
98
+ # Queries all ports with the port number or in the port range.
99
+ #
100
+ # @param [Integer, Range<Integer>] number
101
+ # The port number or range.
102
+ #
103
+ # @return [Array<Port>]
104
+ # The ports with the port number or in the port range.
105
+ #
106
+ # @api public
107
+ #
108
+ # @since 0.2.0
109
+ #
110
+ def self.with_number(number)
111
+ where(number: number)
112
+ end
113
+
114
+ #
115
+ # Queries all ports with the protocol.
116
+ #
117
+ # @param [:tcp, ;udp] protocol
118
+ # The protocol to search for.
119
+ #
120
+ # @return [Array<Port>]
121
+ # The ports that use the protocol.
122
+ #
123
+ # @api public
124
+ #
125
+ # @since 0.2.0
126
+ #
127
+ def self.with_protocol(protocol)
128
+ where(protocol: protocol)
129
+ end
130
+
131
+ #
132
+ # Queries all ports associated with the service name.
133
+ #
134
+ # @param [String] name
135
+ # The service name to search for.
136
+ #
137
+ # @return [Array<Port>]
138
+ # The ports associated with the service name.
139
+ #
140
+ # @api public
141
+ #
142
+ # @since 0.2.0
143
+ #
144
+ def self.with_service_name(name)
145
+ joins(open_ports: :service).where(
146
+ open_ports: {
147
+ ronin_services: {name: name}
148
+ }
149
+ )
150
+ end
151
+
152
+ #
153
+ # Queries all ports associated with the IP address.
154
+ #
155
+ # @param [String] address
156
+ # The IP address to search by.
157
+ #
158
+ # @return [Array<Port>]
159
+ # The ports associated with the IP address.
160
+ #
161
+ # @api public
162
+ #
163
+ # @since 0.2.0
164
+ #
165
+ def self.with_ip_address(address)
166
+ joins(open_ports: :ip_address).where(
167
+ open_ports: {
168
+ ronin_ip_addresses: {address: address}
169
+ }
170
+ )
171
+ end
172
+
65
173
  #
66
174
  # Looks up a port by it's number.
67
175
  #
@@ -121,3 +229,4 @@ module Ronin
121
229
  end
122
230
 
123
231
  require 'ronin/db/open_port'
232
+ require 'ronin/db/note'
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
4
4
  #
5
- # Copyright (c) 2022-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
+ # Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
6
6
  #
7
7
  # ronin-db-activerecord is free software: you can redistribute it and/or modify
8
8
  # it under the terms of the GNU Lesser General Public License as published
@@ -20,6 +20,7 @@
20
20
 
21
21
  require 'ronin/db/model'
22
22
  require 'ronin/db/model/has_unique_name'
23
+ require 'ronin/db/model/importable'
23
24
 
24
25
  module Ronin
25
26
  module DB
@@ -29,6 +30,7 @@ module Ronin
29
30
  class Service < ActiveRecord::Base
30
31
 
31
32
  include Model
33
+ include Model::Importable
32
34
  include Model::HasUniqueName
33
35
 
34
36
  # @!attribute [rw] id
@@ -37,12 +39,139 @@ module Ronin
37
39
  # @return [Integer]
38
40
  attribute :id, :integer
39
41
 
42
+ # @!attribute [r] created_at
43
+ # Defines the created_at timestamp
44
+ #
45
+ # @return [Time]
46
+ #
47
+ # @since 0.2.0
48
+ attribute :created_at, :datetime
49
+
40
50
  # @!attribute [rw] open_ports
41
51
  # The open ports running the service
42
52
  #
43
53
  # @return [Array<OpenPort>]
44
54
  has_many :open_ports
45
55
 
56
+ # @!attribute [rw] ip_addresses
57
+ # The IP Addresses that that run this service.
58
+ #
59
+ # @return [Array<IPAddress>]
60
+ #
61
+ # @since 0.2.0
62
+ has_many :ip_addresses, through: :open_ports
63
+
64
+ # @!attribute [rw] ports
65
+ # The ports that that use this service.
66
+ #
67
+ # @return [Array<Port>]
68
+ #
69
+ # @since 0.2.0
70
+ has_many :ports, through: :open_ports
71
+
72
+ # @!attribute [rw] notes
73
+ # The associated notes.
74
+ #
75
+ # @return [Array<Note>]
76
+ #
77
+ # @since 0.2.0
78
+ has_many :notes, dependent: :destroy
79
+
80
+ #
81
+ # Queries all services associated with the port number.
82
+ #
83
+ # @param [Integer] number
84
+ # The port number to search by.
85
+ #
86
+ # @return [Array<Service>]
87
+ # The services associated with the port number.
88
+ #
89
+ # @api public
90
+ #
91
+ # @since 0.2.0
92
+ #
93
+ def self.with_port_number(number)
94
+ joins(open_ports: :port).where(
95
+ open_ports: {
96
+ ronin_ports: {number: number}
97
+ }
98
+ )
99
+ end
100
+
101
+ #
102
+ # Queries all services associated with the protocol.
103
+ #
104
+ # @param [:tcp, :udp] protocol
105
+ # The port protocol to search by.
106
+ #
107
+ # @return [Array<Service>]
108
+ # The services associated with the protocol.
109
+ #
110
+ # @api public
111
+ #
112
+ # @since 0.2.0
113
+ #
114
+ def self.with_protocol(protocol)
115
+ joins(open_ports: :port).where(
116
+ open_ports: {
117
+ ronin_ports: {protocol: protocol}
118
+ }
119
+ )
120
+ end
121
+
122
+ #
123
+ # Queries all services associated with the IP address.
124
+ #
125
+ # @param [String] address
126
+ # The IP address to search by.
127
+ #
128
+ # @return [Array<Service>]
129
+ # The services associated with the IP address.
130
+ #
131
+ # @api public
132
+ #
133
+ # @since 0.2.0
134
+ #
135
+ def self.with_ip_address(address)
136
+ joins(open_ports: :ip_address).where(
137
+ open_ports: {
138
+ ronin_ip_addresses: {address: address}
139
+ }
140
+ )
141
+ end
142
+
143
+ #
144
+ # Looks up the service.
145
+ #
146
+ # @param [String] name
147
+ # The service name to lookup.
148
+ #
149
+ # @return [Service, nil]
150
+ # The found service.
151
+ #
152
+ # @since 0.2.0
153
+ #
154
+ def self.lookup(name)
155
+ find_by(name: name)
156
+ end
157
+
158
+ #
159
+ # Imports a service.
160
+ #
161
+ # @param [String] name
162
+ # The service name to import.
163
+ #
164
+ # @return [Service]
165
+ # The imported service.
166
+ #
167
+ # @since 0.2.0
168
+ #
169
+ def self.import(name)
170
+ create(name: name)
171
+ end
172
+
46
173
  end
47
174
  end
48
175
  end
176
+
177
+ require 'ronin/db/note'
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
4
4
  #
5
- # Copyright (c) 2022-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
+ # Copyright (c) 2022-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
6
6
  #
7
7
  # ronin-db-activerecord is free software: you can redistribute it and/or modify
8
8
  # it under the terms of the GNU Lesser General Public License as published