mihari 3.3.0 → 3.6.0
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.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/config.ru +1 -0
- data/lib/mihari/analyzers/base.rb +34 -6
- data/lib/mihari/analyzers/censys.rb +37 -9
- data/lib/mihari/analyzers/onyphe.rb +34 -9
- data/lib/mihari/analyzers/shodan.rb +26 -5
- data/lib/mihari/cli/analyzer.rb +4 -0
- data/lib/mihari/cli/base.rb +0 -5
- data/lib/mihari/commands/init.rb +4 -4
- data/lib/mihari/commands/search.rb +17 -8
- data/lib/mihari/commands/web.rb +1 -0
- data/lib/mihari/{constraints.rb → constants.rb} +0 -0
- data/lib/mihari/database.rb +42 -3
- data/lib/mihari/mixins/rule.rb +5 -1
- data/lib/mihari/models/alert.rb +28 -10
- data/lib/mihari/models/artifact.rb +55 -0
- data/lib/mihari/models/autonomous_system.rb +9 -0
- data/lib/mihari/models/dns.rb +53 -0
- data/lib/mihari/models/geolocation.rb +9 -0
- data/lib/mihari/models/reverse_dns.rb +24 -0
- data/lib/mihari/models/whois.rb +119 -0
- data/lib/mihari/schemas/configuration.rb +1 -0
- data/lib/mihari/schemas/rule.rb +5 -15
- data/lib/mihari/serializers/alert.rb +6 -4
- data/lib/mihari/serializers/artifact.rb +11 -2
- data/lib/mihari/serializers/autonomous_system.rb +9 -0
- data/lib/mihari/serializers/dns.rb +11 -0
- data/lib/mihari/serializers/geolocation.rb +11 -0
- data/lib/mihari/serializers/reverse_dns.rb +11 -0
- data/lib/mihari/serializers/tag.rb +4 -2
- data/lib/mihari/serializers/whois.rb +11 -0
- data/lib/mihari/structs/censys.rb +92 -0
- data/lib/mihari/structs/onyphe.rb +47 -0
- data/lib/mihari/structs/shodan.rb +53 -0
- data/lib/mihari/templates/rule.yml.erb +3 -0
- data/lib/mihari/types.rb +21 -0
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/app.rb +2 -0
- data/lib/mihari/web/controllers/alerts_controller.rb +3 -4
- data/lib/mihari/web/controllers/artifacts_controller.rb +46 -2
- data/lib/mihari/web/controllers/ip_address_controller.rb +36 -0
- data/lib/mihari/web/controllers/sources_controller.rb +2 -2
- data/lib/mihari/web/controllers/tags_controller.rb +3 -1
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari/web/public/redoc-static.html +12 -10
- data/lib/mihari/web/public/static/fonts/fa-brands-400.1a575a41.woff +0 -0
- data/lib/mihari/web/public/static/fonts/fa-brands-400.513aa607.ttf +0 -0
- data/lib/mihari/web/public/static/fonts/fa-brands-400.592643a8.eot +0 -0
- data/lib/mihari/web/public/static/fonts/fa-brands-400.ed311c7a.woff2 +0 -0
- data/lib/mihari/web/public/static/fonts/fa-regular-400.766913e6.ttf +0 -0
- data/lib/mihari/web/public/static/fonts/fa-regular-400.b0e2db3b.eot +0 -0
- data/lib/mihari/web/public/static/fonts/fa-regular-400.b91d376b.woff2 +0 -0
- data/lib/mihari/web/public/static/fonts/fa-regular-400.d1d7e3b4.woff +0 -0
- data/lib/mihari/web/public/static/fonts/fa-solid-900.0c6bfc66.eot +0 -0
- data/lib/mihari/web/public/static/fonts/fa-solid-900.b9625119.ttf +0 -0
- data/lib/mihari/web/public/static/fonts/fa-solid-900.d745348d.woff +0 -0
- data/lib/mihari/web/public/static/fonts/fa-solid-900.d824df7e.woff2 +0 -0
- data/lib/mihari/web/public/static/img/fa-brands-400.1d5619cd.svg +3717 -0
- data/lib/mihari/web/public/static/img/fa-regular-400.c5d109be.svg +801 -0
- data/lib/mihari/web/public/static/img/fa-solid-900.37bc7099.svg +5034 -0
- data/lib/mihari/web/public/static/js/app.8e3e5150.js +36 -0
- data/lib/mihari/web/public/static/js/app.8e3e5150.js.map +1 -0
- data/lib/mihari/web/public/static/js/app.b5914c39.js +36 -0
- data/lib/mihari/web/public/static/js/app.b5914c39.js.map +1 -0
- data/lib/mihari.rb +25 -4
- data/mihari.gemspec +9 -2
- metadata +140 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9c1cbdf0570c25e2d89d7f6fd402b64991dfaebc75cf3cf5422a56504287ae9
|
4
|
+
data.tar.gz: d5b7a0db7b49f245e3c949135011fb674e28a9d3c251e165f827e8f3d90673b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e76a216dedbc1aec17748c37a1b874c2c825fed6f7716ef356a48ddf2861584da299c384737e588a48b67165874f495192bb42a4c20c2f29f4620f8b559d1a83
|
7
|
+
data.tar.gz: 2f3e380b252ba238594ccacd2df8e362a62b9685aafeff34d6506e7301184cf5b38c4244db9498842f4aee9df109d7c43a9ad99cecc3b63616d333a7f5093333
|
data/README.md
CHANGED
@@ -53,6 +53,10 @@ Mihari supports the following services by default.
|
|
53
53
|
|
54
54
|
- [Mihari Knowledge Base](https://www.notion.so/Mihari-Knowledge-Base-266994ff61204428ba6cfcebe40b0bd1)
|
55
55
|
|
56
|
+
## Presentations
|
57
|
+
|
58
|
+
- [Adversary Infrastructure Tracking with Mihari](https://ninoseki.github.io/presentations/Adversary%20Infrastructure%20Tracking%20with%20Mihari.pdf)
|
59
|
+
|
56
60
|
## License
|
57
61
|
|
58
62
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/config.ru
CHANGED
@@ -51,7 +51,7 @@ module Mihari
|
|
51
51
|
# @return [nil]
|
52
52
|
#
|
53
53
|
def run
|
54
|
-
|
54
|
+
set_enriched_artifacts
|
55
55
|
|
56
56
|
Parallel.each(valid_emitters) do |emitter|
|
57
57
|
run_emitter emitter
|
@@ -66,7 +66,7 @@ module Mihari
|
|
66
66
|
# @return [nil]
|
67
67
|
#
|
68
68
|
def run_emitter(emitter)
|
69
|
-
emitter.run(title: title, description: description, artifacts:
|
69
|
+
emitter.run(title: title, description: description, artifacts: enriched_artifacts, source: source, tags: tags)
|
70
70
|
rescue StandardError => e
|
71
71
|
puts "Emission by #{emitter.class} is failed: #{e}"
|
72
72
|
end
|
@@ -88,7 +88,7 @@ module Mihari
|
|
88
88
|
# No need to set data_type manually
|
89
89
|
# It is set automatically in #initialize
|
90
90
|
artifact.is_a?(Artifact) ? artifact : Artifact.new(data: artifact, source: source)
|
91
|
-
end.select(&:valid?)
|
91
|
+
end.select(&:valid?).uniq(&:data)
|
92
92
|
end
|
93
93
|
|
94
94
|
private
|
@@ -105,12 +105,26 @@ module Mihari
|
|
105
105
|
end
|
106
106
|
|
107
107
|
#
|
108
|
-
#
|
108
|
+
# Enriched artifacts
|
109
|
+
#
|
110
|
+
# @return [Array<Mihari::Artifact>]
|
111
|
+
#
|
112
|
+
def enriched_artifacts
|
113
|
+
@enriched_artifacts ||= unique_artifacts.map do |artifact|
|
114
|
+
artifact.enrich_whois
|
115
|
+
artifact.enrich_dns
|
116
|
+
artifact.enrich_reverse_dns
|
117
|
+
artifact
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Set enriched artifacts
|
109
123
|
#
|
110
124
|
# @return [nil]
|
111
125
|
#
|
112
|
-
def
|
113
|
-
retry_on_error {
|
126
|
+
def set_enriched_artifacts
|
127
|
+
retry_on_error { enriched_artifacts }
|
114
128
|
rescue ArgumentError => _e
|
115
129
|
klass = self.class.to_s.split("::").last.to_s
|
116
130
|
raise Error, "Please configure #{klass} API settings properly"
|
@@ -127,6 +141,20 @@ module Mihari
|
|
127
141
|
emitter.valid? ? emitter : nil
|
128
142
|
end
|
129
143
|
end
|
144
|
+
|
145
|
+
#
|
146
|
+
# Normalize ASN value
|
147
|
+
#
|
148
|
+
# @param [String, Integer] asn
|
149
|
+
#
|
150
|
+
# @return [Integer]
|
151
|
+
#
|
152
|
+
def normalize_asn(asn)
|
153
|
+
return asn if asn.is_a?(Integer)
|
154
|
+
return asn.to_i unless asn.start_with?("AS")
|
155
|
+
|
156
|
+
asn.delete_prefix("AS").to_i
|
157
|
+
end
|
130
158
|
end
|
131
159
|
end
|
132
160
|
end
|
@@ -17,31 +17,59 @@ module Mihari
|
|
17
17
|
private
|
18
18
|
|
19
19
|
def search
|
20
|
-
|
20
|
+
artifacts = []
|
21
21
|
|
22
22
|
cursor = nil
|
23
23
|
loop do
|
24
24
|
response = api.search(query, cursor: cursor)
|
25
|
-
|
25
|
+
response = Structs::Censys::Response.from_dynamic!(response)
|
26
26
|
|
27
|
-
|
28
|
-
|
27
|
+
artifacts << response_to_artifacts(response)
|
28
|
+
|
29
|
+
cursor = response.result.links.next
|
29
30
|
break if cursor == ""
|
30
31
|
end
|
31
32
|
|
32
|
-
|
33
|
+
artifacts.flatten.uniq(&:data)
|
33
34
|
end
|
34
35
|
|
35
36
|
#
|
36
37
|
# Extract IPv4s from Censys search API response
|
37
38
|
#
|
38
|
-
# @param [
|
39
|
+
# @param [Structs::Censys::Response] response
|
39
40
|
#
|
40
41
|
# @return [Array<String>]
|
41
42
|
#
|
42
|
-
def
|
43
|
-
hits
|
44
|
-
|
43
|
+
def response_to_artifacts(response)
|
44
|
+
response.result.hits.map { |hit| build_artifact(hit) }
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Build an artifact from a Shodan search API response
|
49
|
+
#
|
50
|
+
# @param [Structs::Censys::Hit] hit
|
51
|
+
#
|
52
|
+
# @return [Artifact]
|
53
|
+
#
|
54
|
+
def build_artifact(hit)
|
55
|
+
as = AutonomousSystem.new(asn: normalize_asn(hit.autonomous_system.asn))
|
56
|
+
|
57
|
+
# sometimes Censys overlooks country
|
58
|
+
# then set geolocation as nil
|
59
|
+
geolocation = nil
|
60
|
+
unless hit.location.country.nil?
|
61
|
+
geolocation = Geolocation.new(
|
62
|
+
country: hit.location.country,
|
63
|
+
country_code: hit.location.country_code
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
Artifact.new(
|
68
|
+
data: hit.ip,
|
69
|
+
source: source,
|
70
|
+
autonomous_system: as,
|
71
|
+
geolocation: geolocation
|
72
|
+
)
|
45
73
|
end
|
46
74
|
|
47
75
|
def configuration_keys
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "onyphe"
|
4
|
+
require "normalize_country"
|
4
5
|
|
5
6
|
module Mihari
|
6
7
|
module Analyzers
|
@@ -11,14 +12,13 @@ module Mihari
|
|
11
12
|
option :tags, default: proc { [] }
|
12
13
|
|
13
14
|
def artifacts
|
14
|
-
|
15
|
-
return [] unless
|
15
|
+
responses = search
|
16
|
+
return [] unless responses
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
flat_results.filter_map { |result| result["ip"] }.uniq
|
18
|
+
results = responses.map(&:results).flatten
|
19
|
+
results.map do |result|
|
20
|
+
build_artifact result
|
21
|
+
end
|
22
22
|
end
|
23
23
|
|
24
24
|
private
|
@@ -34,7 +34,8 @@ module Mihari
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def search_with_page(query, page: 1)
|
37
|
-
api.simple.datascan(query, page: page)
|
37
|
+
res = api.simple.datascan(query, page: page)
|
38
|
+
Structs::Onyphe::Response.from_dynamic!(res)
|
38
39
|
end
|
39
40
|
|
40
41
|
def search
|
@@ -42,11 +43,35 @@ module Mihari
|
|
42
43
|
(1..Float::INFINITY).each do |page|
|
43
44
|
res = search_with_page(query, page: page)
|
44
45
|
responses << res
|
45
|
-
|
46
|
+
|
47
|
+
total = res.total
|
46
48
|
break if total <= page * PAGE_SIZE
|
47
49
|
end
|
48
50
|
responses
|
49
51
|
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Build an artifact from an Onyphe search API result
|
55
|
+
#
|
56
|
+
# @param [Structs::Onyphe::Result] result
|
57
|
+
#
|
58
|
+
# @return [Artifact]
|
59
|
+
#
|
60
|
+
def build_artifact(result)
|
61
|
+
as = AutonomousSystem.new(asn: normalize_asn(result.asn))
|
62
|
+
|
63
|
+
geolocation = Geolocation.new(
|
64
|
+
country: NormalizeCountry(result.country_code, to: :short),
|
65
|
+
country_code: result.country_code
|
66
|
+
)
|
67
|
+
|
68
|
+
Artifact.new(
|
69
|
+
data: result.ip,
|
70
|
+
source: source,
|
71
|
+
autonomous_system: as,
|
72
|
+
geolocation: geolocation
|
73
|
+
)
|
74
|
+
end
|
50
75
|
end
|
51
76
|
end
|
52
77
|
end
|
@@ -14,12 +14,11 @@ module Mihari
|
|
14
14
|
results = search
|
15
15
|
return [] unless results || results.empty?
|
16
16
|
|
17
|
+
results = results.map { |result| Structs::Shodan::Result.from_dynamic!(result) }
|
17
18
|
results.map do |result|
|
18
|
-
matches = result
|
19
|
-
matches.
|
20
|
-
|
21
|
-
end
|
22
|
-
end.flatten.compact.uniq
|
19
|
+
matches = result.matches || []
|
20
|
+
matches.map { |match| build_artifact match }
|
21
|
+
end.flatten.compact.uniq(&:data)
|
23
22
|
end
|
24
23
|
|
25
24
|
private
|
@@ -57,6 +56,28 @@ module Mihari
|
|
57
56
|
end
|
58
57
|
responses
|
59
58
|
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# Build an artifact from a Shodan search API response
|
62
|
+
#
|
63
|
+
# @param [Structs::Shodan::Match] match
|
64
|
+
#
|
65
|
+
# @return [Artifact]
|
66
|
+
#
|
67
|
+
def build_artifact(match)
|
68
|
+
as = AutonomousSystem.new(asn: normalize_asn(match.asn))
|
69
|
+
geolocation = Geolocation.new(
|
70
|
+
country: match.location.country_name,
|
71
|
+
country_code: match.location.country_code
|
72
|
+
)
|
73
|
+
|
74
|
+
Artifact.new(
|
75
|
+
data: match.ip_str,
|
76
|
+
source: source,
|
77
|
+
autonomous_system: as,
|
78
|
+
geolocation: geolocation
|
79
|
+
)
|
80
|
+
end
|
60
81
|
end
|
61
82
|
end
|
62
83
|
end
|
data/lib/mihari/cli/analyzer.rb
CHANGED
@@ -22,6 +22,10 @@ require "mihari/commands/json"
|
|
22
22
|
module Mihari
|
23
23
|
module CLI
|
24
24
|
class Analyzer < Base
|
25
|
+
class_option :ignore_old_artifacts, type: :boolean, default: false, desc: "Whether to ignore old artifacts from checking or not."
|
26
|
+
class_option :ignore_threshold, type: :numeric, default: 0, desc: "Number of days to define whether an artifact is old or not."
|
27
|
+
class_option :config, type: :string, desc: "Path to the config file"
|
28
|
+
|
25
29
|
include Mihari::Commands::BinaryEdge
|
26
30
|
include Mihari::Commands::Censys
|
27
31
|
include Mihari::Commands::CIRCL
|
data/lib/mihari/cli/base.rb
CHANGED
@@ -12,11 +12,6 @@ module Mihari
|
|
12
12
|
include Mihari::Mixins::Hash
|
13
13
|
include Mixins::Utils
|
14
14
|
|
15
|
-
class_option :config, type: :string, desc: "Path to the config file"
|
16
|
-
|
17
|
-
class_option :ignore_old_artifacts, type: :boolean, default: false, desc: "Whether to ignore old artifacts from checking or not. Only affects with analyze commands."
|
18
|
-
class_option :ignore_threshold, type: :numeric, default: 0, desc: "Number of days to define whether an artifact is old or not. Only affects with analyze commands."
|
19
|
-
|
20
15
|
class << self
|
21
16
|
def exit_on_failure?
|
22
17
|
true
|
data/lib/mihari/commands/init.rb
CHANGED
@@ -5,10 +5,10 @@ require "colorize"
|
|
5
5
|
module Mihari
|
6
6
|
module Commands
|
7
7
|
module Initialization
|
8
|
-
|
9
|
-
|
10
|
-
include Mixins::Rule
|
8
|
+
include Mixins::Configuration
|
9
|
+
include Mixins::Rule
|
11
10
|
|
11
|
+
def self.included(thor)
|
12
12
|
thor.class_eval do
|
13
13
|
desc "config", "Create a config file"
|
14
14
|
method_option :filename, type: :string, default: "mihari.yml"
|
@@ -37,7 +37,7 @@ module Mihari
|
|
37
37
|
|
38
38
|
initialize_rule_yaml filename
|
39
39
|
|
40
|
-
puts "The rule file is
|
40
|
+
puts "The rule file is initialized as #{filename}.".colorize(:blue)
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -8,17 +8,27 @@ module Mihari
|
|
8
8
|
def self.included(thor)
|
9
9
|
thor.class_eval do
|
10
10
|
desc "search [RULE]", "Search by a rule"
|
11
|
+
method_option :config, type: :string, desc: "Path to the config file"
|
11
12
|
def search_by_rule(rule)
|
12
13
|
# convert str(YAML) to hash or str(path/YAML file) to hash
|
13
14
|
rule = load_rule(rule)
|
14
15
|
|
15
16
|
# validate rule schema
|
16
|
-
validate_rule
|
17
|
+
rule = validate_rule(rule)
|
17
18
|
|
18
|
-
analyzer = build_rule_analyzer(
|
19
|
+
analyzer = build_rule_analyzer(
|
20
|
+
title: rule[:title],
|
21
|
+
description: rule[:description],
|
22
|
+
queries: rule[:queries],
|
23
|
+
tags: rule[:tags],
|
24
|
+
allowed_data_types: rule[:allowed_data_types],
|
25
|
+
disallowed_data_values: rule[:disallowed_data_values],
|
26
|
+
source: rule[:source],
|
27
|
+
id: rule[:id]
|
28
|
+
)
|
19
29
|
|
20
|
-
ignore_old_artifacts =
|
21
|
-
ignore_threshold =
|
30
|
+
ignore_old_artifacts = rule[:ignore_old_artifacts]
|
31
|
+
ignore_threshold = rule[:ignore_threshold]
|
22
32
|
|
23
33
|
with_error_handling do
|
24
34
|
run_rule_analyzer analyzer, ignore_old_artifacts: ignore_old_artifacts, ignore_threshold: ignore_threshold
|
@@ -42,7 +52,7 @@ module Mihari
|
|
42
52
|
#
|
43
53
|
# @return [Mihari::Analyzers::Rule]
|
44
54
|
#
|
45
|
-
def build_rule_analyzer(title:, description:, queries:, tags: nil, allowed_data_types: nil, disallowed_data_values: nil, source: nil)
|
55
|
+
def build_rule_analyzer(title:, description:, queries:, tags: nil, allowed_data_types: nil, disallowed_data_values: nil, source: nil, id: nil)
|
46
56
|
tags = [] if tags.nil?
|
47
57
|
allowed_data_types = ALLOWED_DATA_TYPES if allowed_data_types.nil?
|
48
58
|
disallowed_data_values = [] if disallowed_data_values.nil?
|
@@ -54,7 +64,8 @@ module Mihari
|
|
54
64
|
queries: queries,
|
55
65
|
allowed_data_types: allowed_data_types,
|
56
66
|
disallowed_data_values: disallowed_data_values,
|
57
|
-
source: source
|
67
|
+
source: source,
|
68
|
+
id: id
|
58
69
|
)
|
59
70
|
end
|
60
71
|
|
@@ -62,8 +73,6 @@ module Mihari
|
|
62
73
|
# Run rule analyzer
|
63
74
|
#
|
64
75
|
# @param [Mihari::Analyzer::Rule] analyzer
|
65
|
-
# @param [Boolean] ignore_old_artifacts
|
66
|
-
# @param [Integer] ignore_threshold
|
67
76
|
#
|
68
77
|
# @return [nil]
|
69
78
|
#
|
data/lib/mihari/commands/web.rb
CHANGED
@@ -8,6 +8,7 @@ module Mihari
|
|
8
8
|
desc "web", "Launch the web app"
|
9
9
|
method_option :port, type: :numeric, default: 9292
|
10
10
|
method_option :host, type: :string, default: "localhost"
|
11
|
+
method_option :config, type: :string, desc: "Path to the config file"
|
11
12
|
def web
|
12
13
|
port = options["port"].to_i || 9292
|
13
14
|
host = options["host"] || "localhost"
|
File without changes
|
data/lib/mihari/database.rb
CHANGED
@@ -32,12 +32,48 @@ class InitialSchema < ActiveRecord::Migration[6.1]
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
class
|
35
|
+
class AddeSourceToArtifactSchema < ActiveRecord::Migration[6.1]
|
36
36
|
def change
|
37
37
|
add_column :artifacts, :source, :string, if_not_exists: true
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
+
class EnrichmentsSchema < ActiveRecord::Migration[6.1]
|
42
|
+
def change
|
43
|
+
create_table :autonomous_systems, if_not_exists: true do |t|
|
44
|
+
t.integer :asn, null: false
|
45
|
+
t.belongs_to :artifact, foreign_key: true
|
46
|
+
end
|
47
|
+
|
48
|
+
create_table :geolocations, if_not_exists: true do |t|
|
49
|
+
t.string :country, null: false
|
50
|
+
t.string :country_code, null: false
|
51
|
+
t.belongs_to :artifact, foreign_key: true
|
52
|
+
end
|
53
|
+
|
54
|
+
create_table :whois_records, if_not_exists: true do |t|
|
55
|
+
t.string :domain, null: false
|
56
|
+
t.date :created_on
|
57
|
+
t.date :updated_on
|
58
|
+
t.date :expires_on
|
59
|
+
t.json :registrar
|
60
|
+
t.json :contacts
|
61
|
+
t.belongs_to :artifact, foreign_key: true
|
62
|
+
end
|
63
|
+
|
64
|
+
create_table :dns_records, if_not_exists: true do |t|
|
65
|
+
t.string :resource, null: false
|
66
|
+
t.string :value, null: false
|
67
|
+
t.belongs_to :artifact, foreign_key: true
|
68
|
+
end
|
69
|
+
|
70
|
+
create_table :reverse_dns_names, if_not_exists: true do |t|
|
71
|
+
t.string :name, null: false
|
72
|
+
t.belongs_to :artifact, foreign_key: true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
41
77
|
def adapter
|
42
78
|
return "postgresql" if Mihari.config.database.start_with?("postgresql://", "postgres://")
|
43
79
|
return "mysql2" if Mihari.config.database.start_with?("mysql2://")
|
@@ -59,10 +95,12 @@ module Mihari
|
|
59
95
|
)
|
60
96
|
end
|
61
97
|
|
98
|
+
# ActiveRecord::Base.logger = Logger.new STDOUT
|
62
99
|
ActiveRecord::Migration.verbose = false
|
63
100
|
|
64
101
|
InitialSchema.migrate(:up)
|
65
|
-
|
102
|
+
AddeSourceToArtifactSchema.migrate(:up)
|
103
|
+
EnrichmentsSchema.migrate(:up)
|
66
104
|
rescue StandardError
|
67
105
|
# Do nothing
|
68
106
|
end
|
@@ -76,7 +114,8 @@ module Mihari
|
|
76
114
|
return unless ActiveRecord::Base.connected?
|
77
115
|
|
78
116
|
InitialSchema.migrate(:down)
|
79
|
-
|
117
|
+
AddeSourceToArtifactSchema.migrate(:down)
|
118
|
+
EnrichmentsSchema.migrate(:down)
|
80
119
|
end
|
81
120
|
end
|
82
121
|
end
|