mihari 5.2.1 → 5.2.3
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/.rubocop.yml +2 -0
- data/lib/mihari/analyzers/base.rb +20 -115
- data/lib/mihari/analyzers/binaryedge.rb +0 -1
- data/lib/mihari/analyzers/censys.rb +26 -3
- data/lib/mihari/analyzers/circl.rb +1 -1
- data/lib/mihari/analyzers/onyphe.rb +1 -1
- data/lib/mihari/analyzers/passivetotal.rb +1 -1
- data/lib/mihari/analyzers/rule.rb +122 -75
- data/lib/mihari/analyzers/shodan.rb +1 -1
- data/lib/mihari/analyzers/urlscan.rb +6 -9
- data/lib/mihari/analyzers/virustotal_intelligence.rb +1 -6
- data/lib/mihari/cli/main.rb +2 -2
- data/lib/mihari/clients/base.rb +1 -1
- data/lib/mihari/commands/database.rb +12 -11
- data/lib/mihari/commands/rule.rb +47 -45
- data/lib/mihari/commands/search.rb +88 -0
- data/lib/mihari/commands/version.rb +8 -6
- data/lib/mihari/commands/web.rb +26 -23
- data/lib/mihari/emitters/base.rb +14 -1
- data/lib/mihari/emitters/database.rb +3 -10
- data/lib/mihari/emitters/misp.rb +16 -5
- data/lib/mihari/emitters/slack.rb +13 -15
- data/lib/mihari/emitters/the_hive.rb +17 -19
- data/lib/mihari/emitters/webhook.rb +23 -23
- data/lib/mihari/enrichers/whois.rb +1 -0
- data/lib/mihari/feed/parser.rb +1 -0
- data/lib/mihari/feed/reader.rb +29 -14
- data/lib/mihari/mixins/configurable.rb +13 -4
- data/lib/mihari/mixins/error_notification.rb +0 -2
- data/lib/mihari/models/artifact.rb +1 -1
- data/lib/mihari/schemas/rule.rb +2 -17
- data/lib/mihari/structs/censys.rb +226 -56
- data/lib/mihari/structs/config.rb +48 -18
- data/lib/mihari/structs/google_public_dns.rb +56 -14
- data/lib/mihari/structs/greynoise.rb +122 -29
- data/lib/mihari/structs/ipinfo.rb +40 -0
- data/lib/mihari/structs/onyphe.rb +112 -26
- data/lib/mihari/structs/rule.rb +4 -2
- data/lib/mihari/structs/shodan.rb +189 -47
- data/lib/mihari/structs/urlscan.rb +123 -20
- data/lib/mihari/structs/virustotal_intelligence.rb +129 -26
- data/lib/mihari/type_checker.rb +10 -8
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari.rb +1 -0
- data/mihari.gemspec +11 -10
- metadata +35 -36
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -43
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -15
- data/.github/workflows/test.yml +0 -90
- data/config/pre_commit.yml +0 -3
- data/docker/Dockerfile +0 -14
- data/examples/ipinfo_hosted_domains.rb +0 -45
- data/images/Tines-Full_Logo-Tines_Black.png +0 -0
- data/images/alert.png +0 -0
- data/images/logo.png +0 -0
- data/images/misp.png +0 -0
- data/images/overview.jpg +0 -0
- data/images/slack.png +0 -0
- data/images/tines.png +0 -0
- data/images/web_alerts.png +0 -0
- data/images/web_config.png +0 -0
- data/lib/mihari/commands/searcher.rb +0 -61
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a66fb2d71bcae401062277921a8ade6a3e9e9d961b193a80deacd3a8a934d4c
|
4
|
+
data.tar.gz: b4dcccfa58019f819241f8679b5d1ae846002f0a95307cd95856f2b6d04a6dd1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e215400c8dce2b864bc26a951ed8ea35757441e7d25bdba6c66632d6716991bad202170f9984d09b7a709f6c9aceb731e5b40396efe621ffc55810a10db45db2
|
7
|
+
data.tar.gz: 745522a9cefaed75e5b266a429dea7afc0efe34f26f8591af18e3bc27a0746659ed8d64f6aa64f6edc0f9195acbf26e4a7ee078c052bab760f985da779c4e6e4
|
data/.rubocop.yml
CHANGED
@@ -5,32 +5,34 @@ module Mihari
|
|
5
5
|
class Base
|
6
6
|
extend Dry::Initializer
|
7
7
|
|
8
|
-
option :rule, default: proc {}
|
9
|
-
|
10
8
|
include Mixins::Configurable
|
11
9
|
include Mixins::Retriable
|
12
10
|
|
13
|
-
# @return [Mihari::
|
14
|
-
|
15
|
-
|
16
|
-
def initialize(*args, **kwargs)
|
17
|
-
super(*args, **kwargs)
|
18
|
-
|
19
|
-
@base_time = Time.now.utc
|
11
|
+
# @return [Array<String>, Array<Mihari::Artifact>]
|
12
|
+
def artifacts
|
13
|
+
raise NotImplementedError, "You must implement #{self.class}##{__method__}"
|
20
14
|
end
|
21
15
|
|
22
16
|
#
|
23
|
-
#
|
17
|
+
# Normalize artifacts
|
18
|
+
# - Convert data (string) into an artifact
|
19
|
+
# - Reject an invalid artifact
|
24
20
|
#
|
25
|
-
# @
|
21
|
+
# @return [Array<Mihari::Artifact>]
|
26
22
|
#
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
23
|
+
def normalized_artifacts
|
24
|
+
retry_on_error do
|
25
|
+
@normalized_artifacts ||= artifacts.compact.sort.map do |artifact|
|
26
|
+
# No need to set data_type manually
|
27
|
+
# It is set automatically in #initialize
|
28
|
+
artifact = artifact.is_a?(Artifact) ? artifact : Artifact.new(data: artifact)
|
29
|
+
artifact
|
30
|
+
end.select(&:valid?).uniq(&:data).map do |artifact|
|
31
|
+
# set source
|
32
|
+
artifact.source = source
|
33
|
+
artifact
|
34
|
+
end
|
35
|
+
end
|
34
36
|
end
|
35
37
|
|
36
38
|
# @return [String]
|
@@ -43,109 +45,12 @@ module Mihari
|
|
43
45
|
self.class.to_s.split("::").last
|
44
46
|
end
|
45
47
|
|
46
|
-
#
|
47
|
-
# Set artifacts & run emitters in parallel
|
48
|
-
#
|
49
|
-
# @return [Mihari::Alert, nil]
|
50
|
-
#
|
51
|
-
def run
|
52
|
-
raise ConfigurationError, "#{class_name} is not configured correctly" unless configured?
|
53
|
-
|
54
|
-
alert_or_something = bulk_emit
|
55
|
-
# returns Mihari::Alert created by the database emitter
|
56
|
-
alert_or_something.find { |res| res.is_a?(Mihari::Alert) }
|
57
|
-
end
|
58
|
-
|
59
|
-
#
|
60
|
-
# Bulk emit
|
61
|
-
#
|
62
|
-
# @return [Array<Mihari::Alert>]
|
63
|
-
#
|
64
|
-
def bulk_emit
|
65
|
-
Parallel.map(valid_emitters) { |emitter| emit emitter }.compact
|
66
|
-
end
|
67
|
-
|
68
|
-
#
|
69
|
-
# Emit an alert
|
70
|
-
#
|
71
|
-
# @param [Mihari::Emitters::Base] emitter
|
72
|
-
#
|
73
|
-
# @return [Mihari::Alert, nil]
|
74
|
-
#
|
75
|
-
def emit(emitter)
|
76
|
-
return if enriched_artifacts.empty?
|
77
|
-
|
78
|
-
alert_or_something = emitter.run(artifacts: enriched_artifacts, rule: rule)
|
79
|
-
|
80
|
-
Mihari.logger.info "Emission by #{emitter.class} is succedded"
|
81
|
-
|
82
|
-
alert_or_something
|
83
|
-
rescue StandardError => e
|
84
|
-
Mihari.logger.info "Emission by #{emitter.class} is failed: #{e}"
|
85
|
-
end
|
86
|
-
|
87
48
|
class << self
|
88
49
|
def inherited(child)
|
89
50
|
super
|
90
51
|
Mihari.analyzers << child
|
91
52
|
end
|
92
53
|
end
|
93
|
-
|
94
|
-
#
|
95
|
-
# Normalize artifacts
|
96
|
-
# - Convert data (string) into an artifact
|
97
|
-
# - Set rule ID
|
98
|
-
# - Reject an invalid artifact
|
99
|
-
# - Uniquefy artifacts by data
|
100
|
-
#
|
101
|
-
# @return [Array<Mihari::Artifact>]
|
102
|
-
#
|
103
|
-
def normalized_artifacts
|
104
|
-
@normalized_artifacts ||= artifacts.compact.sort.map do |artifact|
|
105
|
-
# No need to set data_type manually
|
106
|
-
# It is set automatically in #initialize
|
107
|
-
artifact = artifact.is_a?(Artifact) ? artifact : Artifact.new(data: artifact, source: source)
|
108
|
-
artifact.rule_id = rule&.id
|
109
|
-
artifact
|
110
|
-
end.select(&:valid?).uniq(&:data)
|
111
|
-
end
|
112
|
-
|
113
|
-
private
|
114
|
-
|
115
|
-
#
|
116
|
-
# Uniquefy artifacts (assure rule level uniqueness)
|
117
|
-
#
|
118
|
-
# @return [Array<Mihari::Artifact>]
|
119
|
-
#
|
120
|
-
def unique_artifacts
|
121
|
-
@unique_artifacts ||= normalized_artifacts.select do |artifact|
|
122
|
-
artifact.unique?(base_time: @base_time, artifact_lifetime: rule&.artifact_lifetime)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
#
|
127
|
-
# Enriched artifacts
|
128
|
-
#
|
129
|
-
# @return [Array<Mihari::Artifact>]
|
130
|
-
#
|
131
|
-
def enriched_artifacts
|
132
|
-
@enriched_artifacts ||= Parallel.map(unique_artifacts) do |artifact|
|
133
|
-
artifact.enrich_all
|
134
|
-
artifact
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
#
|
139
|
-
# Select valid emitters
|
140
|
-
#
|
141
|
-
# @return [Array<Mihari::Emitters::Base>]
|
142
|
-
#
|
143
|
-
def valid_emitters
|
144
|
-
@valid_emitters ||= Mihari.emitters.filter_map do |klass|
|
145
|
-
emitter = klass.new
|
146
|
-
emitter.valid? ? emitter : nil
|
147
|
-
end.compact
|
148
|
-
end
|
149
54
|
end
|
150
55
|
end
|
151
56
|
end
|
@@ -26,15 +26,23 @@ module Mihari
|
|
26
26
|
@secret = kwargs[:secret] || Mihari.config.censys_secret
|
27
27
|
end
|
28
28
|
|
29
|
+
#
|
30
|
+
# @return [Array<Mihari::Artifact>]
|
31
|
+
#
|
29
32
|
def artifacts
|
30
33
|
artifacts = []
|
31
34
|
|
32
35
|
cursor = nil
|
33
36
|
loop do
|
34
37
|
response = client.search(query, cursor: cursor)
|
35
|
-
artifacts << response.result.to_artifacts
|
38
|
+
artifacts << response.result.to_artifacts
|
36
39
|
cursor = response.result.links.next
|
37
|
-
|
40
|
+
# NOTE: Censys's search API is unstable recently
|
41
|
+
# it may returns empty links or empty string cursors
|
42
|
+
# - Empty links: "links": {}
|
43
|
+
# - Empty cursors: "links": { "next": "", "prev": "" }
|
44
|
+
# So it needs to check both cases
|
45
|
+
break if cursor.nil? || cursor.empty?
|
38
46
|
|
39
47
|
# sleep #{interval} seconds to avoid the rate limitation (if it is set)
|
40
48
|
sleep interval
|
@@ -43,24 +51,39 @@ module Mihari
|
|
43
51
|
artifacts.flatten.uniq(&:data)
|
44
52
|
end
|
45
53
|
|
54
|
+
#
|
55
|
+
# @return [Boolean]
|
56
|
+
#
|
46
57
|
def configured?
|
47
|
-
configuration_keys
|
58
|
+
configuration_keys? || (id? && secret?)
|
48
59
|
end
|
49
60
|
|
50
61
|
private
|
51
62
|
|
63
|
+
#
|
64
|
+
# @return [Array<String>]
|
65
|
+
#
|
52
66
|
def configuration_keys
|
53
67
|
%w[censys_id censys_secret]
|
54
68
|
end
|
55
69
|
|
70
|
+
#
|
71
|
+
# @return [Mihari::Clients::Censys]
|
72
|
+
#
|
56
73
|
def client
|
57
74
|
@client ||= Clients::Censys.new(id: id, secret: secret)
|
58
75
|
end
|
59
76
|
|
77
|
+
#
|
78
|
+
# @return [Boolean]
|
79
|
+
#
|
60
80
|
def id?
|
61
81
|
!id.nil?
|
62
82
|
end
|
63
83
|
|
84
|
+
#
|
85
|
+
# @return [Boolean]
|
86
|
+
#
|
64
87
|
def secret?
|
65
88
|
!secret.nil?
|
66
89
|
end
|
@@ -34,59 +34,40 @@ module Mihari
|
|
34
34
|
"webhook" => Emitters::Webhook
|
35
35
|
}.freeze
|
36
36
|
|
37
|
-
|
38
|
-
attr_reader :rule
|
39
|
-
|
40
|
-
class Rule < Base
|
37
|
+
class Rule
|
41
38
|
include Mixins::FalsePositive
|
42
39
|
|
43
|
-
|
44
|
-
|
40
|
+
# @return [Mihari::Structs::Rule]
|
41
|
+
attr_reader :rule
|
42
|
+
|
43
|
+
# @return [Time]
|
44
|
+
attr_reader :base_time
|
45
|
+
|
46
|
+
#
|
47
|
+
# @param [Mihari::Structs::Rule] rule
|
48
|
+
#
|
49
|
+
def initialize(rule:)
|
50
|
+
@rule = rule
|
51
|
+
@base_time = Time.now.utc
|
45
52
|
|
46
53
|
validate_analyzer_configurations
|
47
54
|
end
|
48
55
|
|
49
56
|
#
|
50
|
-
# Returns a list of artifacts matched with queries
|
57
|
+
# Returns a list of artifacts matched with queries/analyzers
|
51
58
|
#
|
52
59
|
# @return [Array<Mihari::Artifact>]
|
53
60
|
#
|
54
61
|
def artifacts
|
55
|
-
|
56
|
-
|
57
|
-
rule.queries.each do |original_params|
|
58
|
-
parmas = original_params.deep_dup
|
59
|
-
|
60
|
-
analyzer_name = parmas[:analyzer]
|
61
|
-
klass = get_analyzer_class(analyzer_name)
|
62
|
-
|
63
|
-
query = parmas[:query]
|
64
|
-
|
65
|
-
# set interval in the top level
|
66
|
-
options = parmas[:options] || {}
|
67
|
-
interval = options[:interval]
|
68
|
-
|
69
|
-
parmas[:interval] = interval if interval
|
70
|
-
|
71
|
-
# set rule
|
72
|
-
parmas[:rule] = rule
|
73
|
-
|
74
|
-
analyzer = klass.new(query, **parmas)
|
75
|
-
|
76
|
-
# Use #normalized_artifacts method to get atrifacts as Array<Mihari::Artifact>
|
77
|
-
# So Mihari::Artifact object has "source" attribute (e.g. "Shodan")
|
78
|
-
artifacts << analyzer.normalized_artifacts
|
79
|
-
end
|
80
|
-
|
81
|
-
artifacts.flatten
|
62
|
+
analyzers.flat_map(&:normalized_artifacts)
|
82
63
|
end
|
83
64
|
|
84
65
|
#
|
85
66
|
# Normalize artifacts
|
86
|
-
# -
|
87
|
-
# - Reject an invalid artifact (for just in case)
|
67
|
+
# - Reject invalid artifacts (for just in case)
|
88
68
|
# - Select artifacts with allowed data types
|
89
|
-
# - Reject artifacts with
|
69
|
+
# - Reject artifacts with false positive values
|
70
|
+
# - Set rule ID
|
90
71
|
#
|
91
72
|
# @return [Array<Mihari::Artifact>]
|
92
73
|
#
|
@@ -95,6 +76,20 @@ module Mihari
|
|
95
76
|
rule.data_types.include? artifact.data_type
|
96
77
|
end.reject do |artifact|
|
97
78
|
falsepositive? artifact.data
|
79
|
+
end.map do |artifact|
|
80
|
+
artifact.rule_id = rule.id
|
81
|
+
artifact
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Uniquify artifacts (assure rule level uniqueness)
|
87
|
+
#
|
88
|
+
# @return [Array<Mihari::Artifact>]
|
89
|
+
#
|
90
|
+
def unique_artifacts
|
91
|
+
@unique_artifacts ||= normalized_artifacts.select do |artifact|
|
92
|
+
artifact.unique?(base_time: base_time, artifact_lifetime: rule.artifact_lifetime)
|
98
93
|
end
|
99
94
|
end
|
100
95
|
|
@@ -105,39 +100,105 @@ module Mihari
|
|
105
100
|
#
|
106
101
|
def enriched_artifacts
|
107
102
|
@enriched_artifacts ||= Parallel.map(unique_artifacts) do |artifact|
|
108
|
-
rule.enrichers.each
|
109
|
-
artifact.enrich_by_enricher(enricher[:enricher])
|
110
|
-
end
|
111
|
-
|
103
|
+
rule.enrichers.each { |enricher| artifact.enrich_by_enricher enricher[:enricher] }
|
112
104
|
artifact
|
113
105
|
end
|
114
106
|
end
|
115
107
|
|
116
108
|
#
|
117
|
-
#
|
109
|
+
# Bulk emit
|
118
110
|
#
|
119
|
-
# @return [Array<
|
111
|
+
# @return [Array<Mihari::Alert>]
|
120
112
|
#
|
121
|
-
def
|
122
|
-
|
113
|
+
def bulk_emit
|
114
|
+
return [] if enriched_artifacts.empty?
|
115
|
+
|
116
|
+
Parallel.map(valid_emitters) do |emitter|
|
117
|
+
emission = emitter.emit
|
118
|
+
Mihari.logger.info "Emission by #{emitter.class} is succeeded"
|
119
|
+
emission
|
120
|
+
rescue StandardError => e
|
121
|
+
Mihari.logger.info "Emission by #{emitter.class} is failed: #{e}"
|
122
|
+
end.compact
|
123
123
|
end
|
124
124
|
|
125
|
+
#
|
126
|
+
# Set artifacts & run emitters in parallel
|
127
|
+
#
|
128
|
+
# @return [Mihari::Alert, nil]
|
129
|
+
#
|
130
|
+
def run
|
131
|
+
# memoize enriched artifacts
|
132
|
+
enriched_artifacts
|
133
|
+
|
134
|
+
alert_or_something = bulk_emit
|
135
|
+
# returns Mihari::Alert created by the database emitter
|
136
|
+
alert_or_something.find { |res| res.is_a?(Mihari::Alert) }
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
125
141
|
#
|
126
142
|
# Check whether a value is a falsepositive value or not
|
127
143
|
#
|
128
144
|
# @return [Boolean]
|
129
145
|
#
|
130
146
|
def falsepositive?(value)
|
131
|
-
return true if
|
147
|
+
return true if rule.falsepositives.include?(value)
|
132
148
|
|
133
|
-
|
149
|
+
rule.falsepositives.select do |falsepositive|
|
134
150
|
falsepositive.is_a?(Regexp)
|
135
151
|
end.any? do |falseposistive|
|
136
152
|
falseposistive.match?(value)
|
137
153
|
end
|
138
154
|
end
|
139
155
|
|
140
|
-
|
156
|
+
#
|
157
|
+
# Deep copied queries
|
158
|
+
#
|
159
|
+
# @return [Array<Hash>]
|
160
|
+
#
|
161
|
+
def queries
|
162
|
+
rule.queries.map(&:deep_dup)
|
163
|
+
end
|
164
|
+
|
165
|
+
#
|
166
|
+
# Get analyzer class
|
167
|
+
#
|
168
|
+
# @param [String] analyzer_name
|
169
|
+
#
|
170
|
+
# @return [Class<Mihari::Analyzers::Base>] analyzer class
|
171
|
+
#
|
172
|
+
def get_analyzer_class(analyzer_name)
|
173
|
+
analyzer = ANALYZER_TO_CLASS[analyzer_name]
|
174
|
+
return analyzer if analyzer
|
175
|
+
|
176
|
+
raise ArgumentError, "#{analyzer_name} is not supported"
|
177
|
+
end
|
178
|
+
|
179
|
+
#
|
180
|
+
# @return [Array<Mihari::Analyzers::Base>] <description>
|
181
|
+
#
|
182
|
+
def analyzers
|
183
|
+
@analyzers ||= queries.map do |params|
|
184
|
+
analyzer_name = params[:analyzer]
|
185
|
+
klass = get_analyzer_class(analyzer_name)
|
186
|
+
|
187
|
+
# set interval in the top level
|
188
|
+
options = params[:options] || {}
|
189
|
+
interval = options[:interval]
|
190
|
+
params[:interval] = interval if interval
|
191
|
+
|
192
|
+
# set rule
|
193
|
+
params[:rule] = rule
|
194
|
+
query = params[:query]
|
195
|
+
|
196
|
+
analyzer = klass.new(query, **params)
|
197
|
+
raise ConfigurationError, "#{analyzer.source} is not configured correctly" unless analyzer.configured?
|
198
|
+
|
199
|
+
analyzer
|
200
|
+
end
|
201
|
+
end
|
141
202
|
|
142
203
|
#
|
143
204
|
# Get emitter class
|
@@ -153,48 +214,34 @@ module Mihari
|
|
153
214
|
raise ArgumentError, "#{emitter_name} is not supported"
|
154
215
|
end
|
155
216
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
217
|
+
#
|
218
|
+
# Deep copied emitters
|
219
|
+
#
|
220
|
+
# @return [Array<Mihari::Emitters::Base>]
|
221
|
+
#
|
222
|
+
def emitters
|
223
|
+
rule.emitters.map(&:deep_dup).map do |params|
|
160
224
|
name = params[:emitter]
|
161
225
|
params.delete(:emitter)
|
162
226
|
|
163
227
|
klass = get_emitter_class(name)
|
164
|
-
|
165
|
-
|
166
|
-
emitter.valid? ? emitter : nil
|
228
|
+
klass.new(artifacts: enriched_artifacts, rule: rule, **params)
|
167
229
|
end
|
168
230
|
end
|
169
231
|
|
170
232
|
#
|
171
|
-
#
|
172
|
-
#
|
173
|
-
# @param [String] analyzer_name
|
174
|
-
#
|
175
|
-
# @return [Class<Mihari::Analyzers::Base>] analyzer class
|
233
|
+
# @return [Array<Mihari::Emitters::Base>]
|
176
234
|
#
|
177
|
-
def
|
178
|
-
|
179
|
-
return analyzer if analyzer
|
180
|
-
|
181
|
-
raise ArgumentError, "#{analyzer_name} is not supported"
|
235
|
+
def valid_emitters
|
236
|
+
@valid_emitters ||= emitters.select(&:valid?)
|
182
237
|
end
|
183
238
|
|
184
239
|
#
|
185
240
|
# Validate configuration of analyzers
|
186
241
|
#
|
187
242
|
def validate_analyzer_configurations
|
188
|
-
|
189
|
-
|
190
|
-
klass = get_analyzer_class(analyzer_name)
|
191
|
-
|
192
|
-
instance = klass.new("dummy")
|
193
|
-
unless instance.configured?
|
194
|
-
klass_name = klass.to_s.split("::").last
|
195
|
-
raise ConfigurationError, "#{klass_name} is not configured correctly"
|
196
|
-
end
|
197
|
-
end
|
243
|
+
# memoize analyzers & raise ConfigurationError if there is an analyzer which is not configured
|
244
|
+
analyzers
|
198
245
|
end
|
199
246
|
end
|
200
247
|
end
|
@@ -36,15 +36,12 @@ module Mihari
|
|
36
36
|
|
37
37
|
def artifacts
|
38
38
|
responses = search
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
data.nil? ? nil : Artifact.new(data: data, source: source, metadata: result)
|
46
|
-
end
|
47
|
-
end.flatten
|
39
|
+
# @type [Array<Mihari::Artifact>]
|
40
|
+
artifacts = responses.map { |res| res.to_artifacts }.flatten
|
41
|
+
|
42
|
+
artifacts.select do |artifact|
|
43
|
+
allowed_data_types.include? artifact.data_type
|
44
|
+
end
|
48
45
|
end
|
49
46
|
|
50
47
|
private
|
@@ -25,12 +25,7 @@ module Mihari
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def artifacts
|
28
|
-
|
29
|
-
responses.map do |response|
|
30
|
-
response.data.map do |datum|
|
31
|
-
Artifact.new(data: datum.value, source: source, metadata: datum.metadata)
|
32
|
-
end
|
33
|
-
end.flatten
|
28
|
+
search_with_cursor.map(&:to_artifacts).flatten
|
34
29
|
end
|
35
30
|
|
36
31
|
private
|
data/lib/mihari/cli/main.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require "thor"
|
4
4
|
|
5
5
|
# Commands
|
6
|
-
require "mihari/commands/
|
6
|
+
require "mihari/commands/search"
|
7
7
|
require "mihari/commands/version"
|
8
8
|
require "mihari/commands/web"
|
9
9
|
require "mihari/commands/database"
|
@@ -17,7 +17,7 @@ require "mihari/cli/rule"
|
|
17
17
|
module Mihari
|
18
18
|
module CLI
|
19
19
|
class Main < Base
|
20
|
-
include Mihari::Commands::
|
20
|
+
include Mihari::Commands::Search
|
21
21
|
include Mihari::Commands::Version
|
22
22
|
include Mihari::Commands::Web
|
23
23
|
|
data/lib/mihari/clients/base.rb
CHANGED
@@ -3,18 +3,19 @@
|
|
3
3
|
module Mihari
|
4
4
|
module Commands
|
5
5
|
module Database
|
6
|
-
|
7
|
-
thor
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
6
|
+
class << self
|
7
|
+
def included(thor)
|
8
|
+
thor.class_eval do
|
9
|
+
desc "migrate", "Migrate DB schemas"
|
10
|
+
method_option :verbose, type: :boolean, default: true
|
11
|
+
#
|
12
|
+
# @param [String] direction
|
13
|
+
#
|
14
|
+
def migrate(direction = "up")
|
15
|
+
ActiveRecord::Migration.verbose = options["verbose"]
|
16
16
|
|
17
|
-
|
17
|
+
Mihari::Database.with_db_connection { Mihari::Database.migrate direction.to_sym }
|
18
|
+
end
|
18
19
|
end
|
19
20
|
end
|
20
21
|
end
|