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,351 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
4
+ #
5
+ # Copyright (c) 2022 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/address'
22
+
23
+ require 'active_record'
24
+ require 'ipaddr'
25
+ require 'resolv'
26
+
27
+ module Ronin
28
+ module DB
29
+ #
30
+ # Represents IP addresses and their associated {HostName host names}
31
+ # and {MACAddress MAC addresses}.
32
+ #
33
+ class IPAddress < Address
34
+
35
+ # @!attribute [rw] address
36
+ # The IP Address.
37
+ #
38
+ # @return [String]
39
+ attribute :address, :string
40
+ validates :address, presence: true,
41
+ uniqueness: true,
42
+ length: {maximum: 39},
43
+ format: {
44
+ with: /#{Resolv::IPv4::Regex}|#{Resolv::IPv6::Regex}/,
45
+ message: 'Must be a valid IP address'
46
+ }
47
+
48
+ # @!attribute [rw] hton
49
+ # The IP address, but in network byte-order.
50
+ #
51
+ # @return [String]
52
+ attribute :hton, :binary
53
+ before_save :set_hton
54
+
55
+ # @!attribute [rw] version
56
+ # Type of the address.
57
+ #
58
+ # @return [Integer]
59
+ attribute :version, :integer
60
+ validates :version, inclusion: {in: [4, 6]}
61
+
62
+ # @!attribute [rw] ip_address_mac_addresses
63
+ # The MAC Addresses associations.
64
+ #
65
+ # @return [Array<IPAddressMACAddress>]
66
+ has_many :ip_address_mac_addresses, dependent: :destroy,
67
+ class_name: 'IPAddressMACAddress'
68
+
69
+ # @!attribute [rw] mac_addresses
70
+ # The MAC Addresses associated with the IP Address.
71
+ #
72
+ # @return [Array<MACAddress>]
73
+ has_many :mac_addresses, through: :ip_address_mac_addresses,
74
+ class_name: 'MACAddress'
75
+
76
+ # @!attribute [rw] host_name_ip_addresses
77
+ # The host-names that the IP Address serves.
78
+ #
79
+ # @return [Array<HostNameIPAddress>]
80
+ has_many :host_name_ip_addresses, dependent: :destroy,
81
+ class_name: 'HostNameIPAddress'
82
+
83
+ # @!attribute [rw] host_names
84
+ # The host-names associated with the IP Address.
85
+ #
86
+ # @return [Array<HostName>]
87
+ has_many :host_names, through: :host_name_ip_addresses
88
+
89
+ # @!attribute [rw] open_ports
90
+ # The open ports of the host.
91
+ #
92
+ # @return [Array<OpenPort>]
93
+ has_many :open_ports, dependent: :destroy
94
+
95
+ # @!attribute [rw] ports
96
+ # The ports of the host.
97
+ #
98
+ # @return [Array<Port>]
99
+ has_many :ports, through: :open_ports
100
+
101
+ # @!attribute [rw] os_guesses
102
+ # Any OS guesses against the IP Address.
103
+ #
104
+ # @return [Array<OSGuess>]
105
+ has_many :os_guesses, dependent: :destroy,
106
+ class_name: 'OSGuess'
107
+
108
+ # @!attribute [rw] oses
109
+ # Any OSes that the IP Address might be running
110
+ #
111
+ # @return [Array<OS>]
112
+ has_many :oses, through: :os_guesses,
113
+ class_name: 'OS'
114
+
115
+ #
116
+ # Searches for all IPv4 addresses.
117
+ #
118
+ # @return [Array<IPAddress>]
119
+ # The IPv4 addresses.
120
+ #
121
+ # @api public
122
+ #
123
+ def self.v4
124
+ where(version: 4)
125
+ end
126
+
127
+ #
128
+ # Searches for all IPv6 addresses.
129
+ #
130
+ # @return [Array<IPAddress>]
131
+ # The IPv6 addresses.
132
+ #
133
+ # @api public
134
+ #
135
+ def self.v6
136
+ where(version: 6)
137
+ end
138
+
139
+ #
140
+ # Queries all IP address that are between the first IP address and last IP
141
+ # address.
142
+ #
143
+ # @param [String] first_ip
144
+ # The first IP of the IP range.
145
+ #
146
+ # @param [String] last_ip
147
+ # The last IP of the IP range.
148
+ #
149
+ # @return [Array<IPAddress>]
150
+ #
151
+ def self.between(first_ip,last_ip)
152
+ first_ip_hton = IPAddr.new(first_ip).hton
153
+ last_ip_hton = IPAddr.new(last_ip).hton
154
+
155
+ hton = arel_table[:hton]
156
+
157
+ where(hton.gteq(first_ip_hton).and(hton.lteq(last_ip_hton)))
158
+ end
159
+
160
+ #
161
+ # Queries all IP addresses that exist in the range of IP addresses.
162
+ #
163
+ # @param [Range, #begin, #end] range
164
+ # The IP range to query.
165
+ #
166
+ # @return [Array<IPAddress>]
167
+ #
168
+ def self.in_range(range)
169
+ between(range.begin,range.end)
170
+ end
171
+
172
+ #
173
+ # Searches for all IP addresses associated with specific MAC address(es).
174
+ #
175
+ # @param [Array<String>, String] mac
176
+ # The MAC address(es) to search for.
177
+ #
178
+ # @return [Array<IPAddress>]
179
+ # The matching IP addresses.
180
+ #
181
+ # @api public
182
+ #
183
+ def self.with_mac_address(mac)
184
+ joins(:mac_addresses).where(mac_addresses: {address: mac})
185
+ end
186
+
187
+ #
188
+ # Searches for IP addresses associated with the given host name(s).
189
+ #
190
+ # @param [Array<String>, String] name
191
+ # The host name(s) to search for.
192
+ #
193
+ # @return [Array<IPAddress>]
194
+ # The matching IP addresses.
195
+ #
196
+ # @api public
197
+ #
198
+ def self.with_host_name(name)
199
+ joins(:host_names).where(host_names: {name: name})
200
+ end
201
+
202
+ #
203
+ # Searches for IP addresses with the given open port(s).
204
+ #
205
+ # @param [Array<Integer>, Integer] number
206
+ # The port number(s) to search for.
207
+ #
208
+ # @return [Array<IPAddress>]
209
+ # The matching IP addresses.
210
+ #
211
+ # @api public
212
+ #
213
+ def self.with_port_number(number)
214
+ joins(:ports).where(ports: {number: number})
215
+ end
216
+
217
+ #
218
+ # Initializes the IP address record.
219
+ #
220
+ # @param [Array] arguments
221
+ # Additional attribute arguments.
222
+ #
223
+ # @param [Hash{Symbol => Object}] kwargs
224
+ # Additional attribute values.
225
+ #
226
+ # @note Also assigns a default value to `version` based on the `address`.
227
+ #
228
+ def initialize(*arguments,**kwargs)
229
+ super(*arguments,**kwargs)
230
+
231
+ self.version ||= if ipaddr
232
+ if ipaddr.ipv6? then 6
233
+ else 4
234
+ end
235
+ end
236
+ end
237
+
238
+ #
239
+ # Sets the IP address'es address.
240
+ #
241
+ # @param [String, IPAddr, nil] new_address
242
+ # The new address to use.
243
+ #
244
+ # @return [String, IPAddr, nil]
245
+ # The IP address'es new address.
246
+ #
247
+ def address=(new_address)
248
+ @ipaddr = nil
249
+ super(new_address)
250
+ end
251
+
252
+ #
253
+ # Returns an `IPAddr` object for the IP address.
254
+ #
255
+ # @return [IPAddr]
256
+ # The IPAddr object representing either the IPv4 or IPv6 address.
257
+ #
258
+ # @api public
259
+ #
260
+ def ipaddr
261
+ @ipaddr ||= if self.address
262
+ begin
263
+ IPAddr.new(self.address)
264
+ rescue IPAddr::InvalidAddressError
265
+ end
266
+ end
267
+ end
268
+
269
+ #
270
+ # Queries the {ASN} record for the IP address.
271
+ #
272
+ # @return [ASN, nil]
273
+ #
274
+ def asn
275
+ ASN.containing_ip(ipaddr)
276
+ end
277
+
278
+ #
279
+ # The MAC Address that was most recently used by the IP Address.
280
+ #
281
+ # @return [MACAddress]
282
+ # The MAC Address that most recently used the IP Address.
283
+ #
284
+ # @api public
285
+ #
286
+ def recent_mac_address
287
+ self.ip_address_mac_addresses.order('created_at DESC').mac_addresses.first
288
+ end
289
+
290
+ #
291
+ # The host-name that was most recently used by the IP Address.
292
+ #
293
+ # @return [HostName]
294
+ # The host-name that most recently used by the IP Address.
295
+ #
296
+ # @api public
297
+ #
298
+ def recent_host_name
299
+ self.host_name_ip_addresses.order('created_at DESC').host_names.first
300
+ end
301
+
302
+ #
303
+ # The Operating System that was most recently guessed for the IP
304
+ # Address.
305
+ #
306
+ # @return [OS]
307
+ # The Operating System that most recently was guessed.
308
+ #
309
+ # @api public
310
+ #
311
+ def recent_os_guess
312
+ self.os_guesses.order('created_at DESC').oses.first
313
+ end
314
+
315
+ alias to_ip ipaddr
316
+
317
+ #
318
+ # Converts the address to an Integer.
319
+ #
320
+ # @return [Integer]
321
+ # The network representation of the IP address.
322
+ #
323
+ # @api public
324
+ #
325
+ def to_i
326
+ ipaddr.to_i
327
+ end
328
+
329
+ private
330
+
331
+ #
332
+ # Sets the `hton` attribute.
333
+ #
334
+ def set_hton
335
+ self.hton = self.ipaddr.hton
336
+ end
337
+
338
+ end
339
+ end
340
+ end
341
+
342
+ require 'ronin/db/ip_address_mac_address'
343
+ require 'ronin/db/mac_address'
344
+ require 'ronin/db/host_name_ip_address'
345
+ require 'ronin/db/host_name'
346
+ require 'ronin/db/open_port'
347
+ require 'ronin/db/port'
348
+ require 'ronin/db/host_name'
349
+ require 'ronin/db/os_guess'
350
+ require 'ronin/db/os'
351
+ require 'ronin/db/asn'
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
4
+ #
5
+ # Copyright (c) 2022 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
+ # Associates an {IPAddress} with a {MACAddress}.
29
+ #
30
+ class IPAddressMACAddress < ActiveRecord::Base
31
+
32
+ include Model
33
+
34
+ # @!attribute [rw] id
35
+ # The primary-key of the join model.
36
+ #
37
+ # @return [Integer]
38
+ attribute :id, :integer
39
+
40
+ # @!attribute [rw] ip_address
41
+ # The IP Address.
42
+ #
43
+ # @return [IPAddress]
44
+ belongs_to :ip_address, required: true,
45
+ class_name: 'IPAddress'
46
+
47
+ # @!attribute [rw] mac_address
48
+ # The Mac Address.
49
+ #
50
+ # @return [MACAddress]
51
+ belongs_to :mac_address, required: true,
52
+ class_name: 'MACAddress'
53
+
54
+ # @!attribute [r] created_at
55
+ # Tracks when an IP Address becomes associated with a MAC Address.
56
+ #
57
+ # @return [Time]
58
+ attribute :created_at, :time
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
4
+ #
5
+ # Copyright (c) 2022 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/address'
22
+
23
+ require 'active_record'
24
+ require 'strscan'
25
+
26
+ module Ronin
27
+ module DB
28
+ #
29
+ # Represents MAC addresses and their associated {IPAddress IP addresses}.
30
+ #
31
+ class MACAddress < Address
32
+
33
+ # @!attribute [rw] address
34
+ # The MAC address.
35
+ #
36
+ # @return [String]
37
+ attribute :address, :string # length: 17..17,
38
+ validates :address, presence: true,
39
+ uniqueness: true,
40
+ length: {maximum: 17},
41
+ format: {
42
+ with: /[0-9a-fA-F]{2}(?::[0-9a-fA-F]{2}){5}/,
43
+ message: 'Must be a valid MAC address'
44
+ }
45
+
46
+ # @!attribute [rw] ip_address_mac_addresses
47
+ # The IP Addresses the MAC Address hosts
48
+ #
49
+ # @return [Array<IPAddressMACAddress>]
50
+ has_many :ip_address_mac_addresses, dependent: :destroy,
51
+ class_name: 'IPAddressMACAddress'
52
+
53
+ # @!attribute [rw] ip_addresses
54
+ # The IP Addresses associated with the MAC Address
55
+ #
56
+ # @return [Array<IPAddress>]
57
+ has_many :ip_addresses, through: :ip_address_mac_addresses,
58
+ class_name: 'IPAddress'
59
+
60
+ #
61
+ # The IP Address that most recently used the MAC Address.
62
+ #
63
+ # @return [IPAddress]
64
+ # The IP Address that most recently used the MAC Address.
65
+ #
66
+ # @api public
67
+ #
68
+ def recent_ip_address
69
+ self.ip_address_mac_addresses.order('created_at DESC').ip_addresses.first
70
+ end
71
+
72
+ #
73
+ # Converts the MAC address to an Integer.
74
+ #
75
+ # @return [Integer]
76
+ # The network representation of the MAC address.
77
+ #
78
+ # @api public
79
+ #
80
+ def to_i
81
+ self.address.split(':').inject(0) do |bits,char|
82
+ bits = ((bits << 8) | char.hex)
83
+ end
84
+ end
85
+
86
+ end
87
+ end
88
+ end
89
+
90
+ require 'ronin/db/ip_address_mac_address'
91
+ require 'ronin/db/ip_address'
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-db-activerecord - ActiveRecord backend for the Ronin Database.
4
+ #
5
+ # Copyright (c) 2022 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/schema_migration'
22
+
23
+ require 'active_record'
24
+ require 'active_record/migration'
25
+
26
+ module Ronin
27
+ module DB
28
+ module Migrations
29
+ #
30
+ # The current migration version of the database.
31
+ #
32
+ # @return [Integer]
33
+ #
34
+ def self.current_version
35
+ context.current_version
36
+ end
37
+
38
+ #
39
+ # Determines if the database needs migrating up.
40
+ #
41
+ # @return [Boolean]
42
+ #
43
+ def self.needs_migration?
44
+ context.needs_migration?
45
+ end
46
+
47
+ #
48
+ # Migrates the database to the target version.
49
+ #
50
+ # @param [Integer, nil] target_version
51
+ # The desired target version.
52
+ #
53
+ # @api semipublic
54
+ #
55
+ def self.migrate(target_version=nil)
56
+ context.migrate(target_version)
57
+ end
58
+
59
+ #
60
+ # Explicitly migrates up the database to the target version.
61
+ #
62
+ # @param [Integer, nil] target_version
63
+ # The desired target version.
64
+ #
65
+ # @api semipublic
66
+ #
67
+ def self.up(target_version=nil,&block)
68
+ context.up(target_version,&block)
69
+ end
70
+
71
+ #
72
+ # Explicitly migrates down the database to the target version.
73
+ #
74
+ # @param [Integer, nil] target_version
75
+ # The desired target version.
76
+ #
77
+ # @api semipublic
78
+ #
79
+ def self.down(target_version=nil,&block)
80
+ context.down(target_version,&block)
81
+ end
82
+
83
+ #
84
+ # Rollbacks the last number of migrations.
85
+ #
86
+ # @param [Integer] steps
87
+ # The number of migrations to rollback.
88
+ #
89
+ # @api semipublic
90
+ #
91
+ def self.rollback(steps=1)
92
+ context.rollback(steps)
93
+ end
94
+
95
+ #
96
+ # Applies the next number of migrations.
97
+ #
98
+ # @param [Integer] steps
99
+ # The number of migrations to rollback.
100
+ #
101
+ # @api semipublic
102
+ #
103
+ def self.foreward(steps=1)
104
+ context.foreward(steps)
105
+ end
106
+
107
+ private
108
+
109
+ # Path to the `db/migrate/` directory in `ronin-db-activerecord`.
110
+ DIR = File.expand_path('../../../db/migrate',__dir__)
111
+
112
+ #
113
+ # Extensions `ActiveRecord::MigrationContext` to load our migrations from
114
+ # the `db/migrate/` directory and update our
115
+ # `ronin_schema_migration` table.
116
+ #
117
+ # @api private
118
+ #
119
+ class MigrationContext < ActiveRecord::MigrationContext
120
+
121
+ def initialize
122
+ super([Ronin::DB::Migrations::DIR],Ronin::DB::SchemaMigration)
123
+ end
124
+
125
+ end
126
+
127
+ #
128
+ # The migration context.
129
+ #
130
+ # @return [MigrationContext]
131
+ #
132
+ def self.context
133
+ @migrations ||= MigrationContext.new
134
+ end
135
+ end
136
+ end
137
+ end