mihari 3.3.0 → 3.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|