mihari 5.4.2 → 5.4.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/frontend/package-lock.json +2399 -1504
- data/frontend/package.json +22 -22
- data/lib/mihari/analyzers/base.rb +25 -14
- data/lib/mihari/analyzers/binaryedge.rb +2 -48
- data/lib/mihari/analyzers/censys.rb +4 -20
- data/lib/mihari/analyzers/circl.rb +3 -27
- data/lib/mihari/analyzers/crtsh.rb +2 -17
- data/lib/mihari/analyzers/dnstwister.rb +2 -4
- data/lib/mihari/analyzers/greynoise.rb +5 -4
- data/lib/mihari/analyzers/hunterhow.rb +8 -23
- data/lib/mihari/analyzers/onyphe.rb +5 -39
- data/lib/mihari/analyzers/otx.rb +3 -39
- data/lib/mihari/analyzers/passivetotal.rb +4 -42
- data/lib/mihari/analyzers/pulsedive.rb +1 -1
- data/lib/mihari/analyzers/rule.rb +18 -13
- data/lib/mihari/analyzers/securitytrails.rb +4 -42
- data/lib/mihari/analyzers/shodan.rb +7 -39
- data/lib/mihari/analyzers/urlscan.rb +3 -39
- data/lib/mihari/analyzers/virustotal.rb +1 -1
- data/lib/mihari/analyzers/virustotal_intelligence.rb +2 -25
- data/lib/mihari/analyzers/zoomeye.rb +18 -84
- data/lib/mihari/clients/base.rb +9 -1
- data/lib/mihari/clients/binaryedge.rb +26 -4
- data/lib/mihari/clients/censys.rb +32 -2
- data/lib/mihari/clients/circl.rb +28 -1
- data/lib/mihari/clients/crtsh.rb +7 -2
- data/lib/mihari/clients/dnstwister.rb +4 -2
- data/lib/mihari/clients/greynoise.rb +31 -4
- data/lib/mihari/clients/hunterhow.rb +41 -3
- data/lib/mihari/clients/onyphe.rb +25 -3
- data/lib/mihari/clients/otx.rb +40 -0
- data/lib/mihari/clients/passivetotal.rb +33 -15
- data/lib/mihari/clients/publsedive.rb +1 -1
- data/lib/mihari/clients/securitytrails.rb +44 -0
- data/lib/mihari/clients/shodan.rb +31 -3
- data/lib/mihari/clients/urlscan.rb +32 -6
- data/lib/mihari/clients/virustotal.rb +29 -4
- data/lib/mihari/clients/zoomeye.rb +53 -2
- data/lib/mihari/commands/alert.rb +42 -13
- data/lib/mihari/commands/rule.rb +11 -7
- data/lib/mihari/commands/search.rb +54 -22
- data/lib/mihari/commands/web.rb +1 -1
- data/lib/mihari/config.rb +6 -1
- data/lib/mihari/emitters/base.rb +9 -3
- data/lib/mihari/emitters/slack.rb +1 -1
- data/lib/mihari/enrichers/base.rb +13 -0
- data/lib/mihari/enrichers/google_public_dns.rb +16 -1
- data/lib/mihari/enrichers/ipinfo.rb +9 -13
- data/lib/mihari/enrichers/shodan.rb +1 -2
- data/lib/mihari/enrichers/whois.rb +2 -2
- data/lib/mihari/errors.rb +16 -10
- data/lib/mihari/feed/parser.rb +2 -2
- data/lib/mihari/models/artifact.rb +1 -1
- data/lib/mihari/models/autonomous_system.rb +11 -5
- data/lib/mihari/models/cpe.rb +10 -4
- data/lib/mihari/models/dns.rb +11 -16
- data/lib/mihari/models/geolocation.rb +11 -5
- data/lib/mihari/models/port.rb +10 -4
- data/lib/mihari/models/reverse_dns.rb +10 -4
- data/lib/mihari/models/whois.rb +4 -1
- data/lib/mihari/schemas/analyzer.rb +1 -0
- data/lib/mihari/services/alert_builder.rb +43 -0
- data/lib/mihari/services/alert_proxy.rb +7 -25
- data/lib/mihari/services/alert_runner.rb +9 -0
- data/lib/mihari/services/rule_builder.rb +47 -0
- data/lib/mihari/services/rule_proxy.rb +5 -61
- data/lib/mihari/services/rule_runner.rb +9 -4
- data/lib/mihari/structs/binaryedge.rb +89 -0
- data/lib/mihari/structs/censys.rb +11 -11
- data/lib/mihari/structs/greynoise.rb +17 -8
- data/lib/mihari/structs/onyphe.rb +7 -7
- data/lib/mihari/structs/shodan.rb +7 -6
- data/lib/mihari/structs/urlscan.rb +4 -6
- data/lib/mihari/structs/virustotal_intelligence.rb +4 -6
- data/lib/mihari/type_checker.rb +1 -1
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/endpoints/alerts.rb +33 -15
- data/lib/mihari/web/endpoints/artifacts.rb +53 -25
- data/lib/mihari/web/endpoints/configs.rb +2 -2
- data/lib/mihari/web/endpoints/ip_addresses.rb +3 -5
- data/lib/mihari/web/endpoints/rules.rb +97 -71
- data/lib/mihari/web/endpoints/tags.rb +15 -5
- data/lib/mihari/web/public/assets/index-ef33a6cd.js +1738 -0
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari/web/public/redoc-static.html +419 -382
- data/lib/mihari.rb +4 -0
- data/mihari.gemspec +10 -9
- metadata +38 -21
- data/lib/mihari/web/public/assets/index-4d7eda9f.js +0 -1738
data/lib/mihari/models/whois.rb
CHANGED
@@ -7,6 +7,8 @@ module Mihari
|
|
7
7
|
@memo = {}
|
8
8
|
|
9
9
|
class << self
|
10
|
+
include Dry::Monads[:result]
|
11
|
+
|
10
12
|
#
|
11
13
|
# Build whois record
|
12
14
|
#
|
@@ -15,7 +17,8 @@ module Mihari
|
|
15
17
|
# @return [WhoisRecord, nil]
|
16
18
|
#
|
17
19
|
def build_by_domain(domain)
|
18
|
-
Enrichers::Whois.
|
20
|
+
result = Enrichers::Whois.query_result(domain)
|
21
|
+
result.value_or nil
|
19
22
|
end
|
20
23
|
end
|
21
24
|
end
|
@@ -7,6 +7,7 @@ module Mihari
|
|
7
7
|
optional(:pagination_limit).value(:integer).default(Mihari.config.pagination_limit)
|
8
8
|
optional(:retry_times).value(:integer).default(Mihari.config.retry_times)
|
9
9
|
optional(:retry_interval).value(:integer).default(Mihari.config.retry_interval)
|
10
|
+
optional(:ignore_error).value(:bool).default(Mihari.config.ignore_error)
|
10
11
|
end
|
11
12
|
|
12
13
|
AnalyzerWithoutAPIKey = Dry::Schema.Params do
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
|
5
|
+
require "erb"
|
6
|
+
require "pathname"
|
7
|
+
require "yaml"
|
8
|
+
|
9
|
+
module Mihari
|
10
|
+
module Services
|
11
|
+
class AlertBuilder
|
12
|
+
include Dry::Monads[:result, :try]
|
13
|
+
|
14
|
+
# @return [String]
|
15
|
+
attr_reader :path
|
16
|
+
|
17
|
+
#
|
18
|
+
# Initialize
|
19
|
+
#
|
20
|
+
# @param [String] path
|
21
|
+
#
|
22
|
+
def initialize(path)
|
23
|
+
@path = path
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# @return [Hash]
|
28
|
+
#
|
29
|
+
def data
|
30
|
+
raise ArgumentError, "#{path} does not exist" unless Pathname(path).exist?
|
31
|
+
|
32
|
+
YAML.safe_load(
|
33
|
+
ERB.new(File.read(path)).result,
|
34
|
+
permitted_classes: [Date, Symbol]
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def result
|
39
|
+
Try[StandardError] { AlertProxy.new(data) }.to_result
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "json"
|
4
|
+
|
3
5
|
module Mihari
|
4
6
|
module Services
|
5
7
|
class AlertProxy
|
@@ -16,10 +18,9 @@ module Mihari
|
|
16
18
|
#
|
17
19
|
def initialize(data)
|
18
20
|
@data = data.deep_symbolize_keys
|
19
|
-
|
20
21
|
@errors = nil
|
21
22
|
|
22
|
-
validate
|
23
|
+
validate!
|
23
24
|
end
|
24
25
|
|
25
26
|
#
|
@@ -31,21 +32,14 @@ module Mihari
|
|
31
32
|
!@errors.empty?
|
32
33
|
end
|
33
34
|
|
34
|
-
def validate
|
35
|
+
def validate!
|
35
36
|
contract = Schemas::AlertContract.new
|
36
37
|
result = contract.call(data)
|
37
38
|
|
38
39
|
@data = result.to_h
|
39
40
|
@errors = result.errors
|
40
|
-
end
|
41
|
-
|
42
|
-
def validate!
|
43
|
-
return unless errors?
|
44
41
|
|
45
|
-
|
46
|
-
Mihari.logger.error JSON.pretty_generate(errors.to_h)
|
47
|
-
|
48
|
-
raise AlertValidationError, errors
|
42
|
+
raise ValidationError.new("Validation failed", errors) if errors?
|
49
43
|
end
|
50
44
|
|
51
45
|
def [](key)
|
@@ -74,7 +68,7 @@ module Mihari
|
|
74
68
|
# @return [Mihari::Services::RuleProxy]
|
75
69
|
#
|
76
70
|
def rule
|
77
|
-
@rule ||= Services::RuleProxy.
|
71
|
+
@rule ||= Services::RuleProxy.new(Mihari::Rule.find(rule_id).data)
|
78
72
|
end
|
79
73
|
|
80
74
|
class << self
|
@@ -86,19 +80,7 @@ module Mihari
|
|
86
80
|
# @return [Mihari::Services::Alert]
|
87
81
|
#
|
88
82
|
def from_yaml(yaml)
|
89
|
-
|
90
|
-
rescue Psych::SyntaxError => e
|
91
|
-
raise YAMLSyntaxError, e.message
|
92
|
-
end
|
93
|
-
|
94
|
-
# @param [String] path
|
95
|
-
#
|
96
|
-
# @return [Mihari::Services::Alert, nil]
|
97
|
-
#
|
98
|
-
def from_path(path)
|
99
|
-
return nil unless Pathname(path).exist?
|
100
|
-
|
101
|
-
from_yaml File.read(path)
|
83
|
+
new YAML.safe_load(yaml, permitted_classes: [Date, Symbol])
|
102
84
|
end
|
103
85
|
end
|
104
86
|
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module Mihari
|
4
4
|
module Services
|
5
5
|
class AlertRunner
|
6
|
+
include Dry::Monads[:result, :try]
|
7
|
+
|
6
8
|
# @return [Mihari::Services::AlertProxy]
|
7
9
|
attr_reader :alert
|
8
10
|
|
@@ -17,6 +19,13 @@ module Mihari
|
|
17
19
|
emitter = Mihari::Emitters::Database.new(artifacts: alert.artifacts, rule: alert.rule)
|
18
20
|
emitter.emit
|
19
21
|
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# @return [Dry::Monads::Result::Success<Mihari::Alert, nil>, Dry::Monads::Result::Failure]
|
25
|
+
#
|
26
|
+
def result
|
27
|
+
Try[StandardError] { run }.to_result
|
28
|
+
end
|
20
29
|
end
|
21
30
|
end
|
22
31
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
require "erb"
|
5
|
+
require "pathname"
|
6
|
+
require "yaml"
|
7
|
+
|
8
|
+
module Mihari
|
9
|
+
module Services
|
10
|
+
class RuleBuilder
|
11
|
+
include Dry::Monads[:result, :try]
|
12
|
+
|
13
|
+
# @return [String]
|
14
|
+
attr_reader :path_or_id
|
15
|
+
|
16
|
+
#
|
17
|
+
# Initialize
|
18
|
+
#
|
19
|
+
# @param [String] path_or_id
|
20
|
+
#
|
21
|
+
def initialize(path_or_id)
|
22
|
+
@path_or_id = path_or_id
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# @return [Hash]
|
27
|
+
#
|
28
|
+
def data
|
29
|
+
if Mihari::Rule.exists?(path_or_id)
|
30
|
+
rule = Mihari::Rule.find(path_or_id)
|
31
|
+
return rule.data
|
32
|
+
end
|
33
|
+
|
34
|
+
raise ArgumentError, "#{path_or_id} does not exist" unless Pathname(path_or_id).exist?
|
35
|
+
|
36
|
+
YAML.safe_load(
|
37
|
+
ERB.new(File.read(path_or_id)).result,
|
38
|
+
permitted_classes: [Date, Symbol]
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def result
|
43
|
+
Try[StandardError] { RuleProxy.new(data) }.to_result
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -1,11 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "date"
|
4
|
-
require "erb"
|
5
3
|
require "json"
|
6
|
-
require "pathname"
|
7
|
-
require "securerandom"
|
8
|
-
require "yaml"
|
9
4
|
|
10
5
|
module Mihari
|
11
6
|
module Services
|
@@ -29,10 +24,9 @@ module Mihari
|
|
29
24
|
#
|
30
25
|
def initialize(data)
|
31
26
|
@data = data.deep_symbolize_keys
|
32
|
-
|
33
27
|
@errors = nil
|
34
28
|
|
35
|
-
validate
|
29
|
+
validate!
|
36
30
|
end
|
37
31
|
|
38
32
|
#
|
@@ -44,21 +38,14 @@ module Mihari
|
|
44
38
|
!@errors.empty?
|
45
39
|
end
|
46
40
|
|
47
|
-
def validate
|
41
|
+
def validate!
|
48
42
|
contract = Schemas::RuleContract.new
|
49
43
|
result = contract.call(data)
|
50
44
|
|
51
45
|
@data = result.to_h
|
52
46
|
@errors = result.errors
|
53
|
-
end
|
54
47
|
|
55
|
-
|
56
|
-
return unless errors?
|
57
|
-
|
58
|
-
Mihari.logger.error "Failed to parse the input as a rule:"
|
59
|
-
Mihari.logger.error JSON.pretty_generate(errors.to_h)
|
60
|
-
|
61
|
-
raise RuleValidationError, errors
|
48
|
+
raise ValidationError.new("Validation failed", errors) if errors?
|
62
49
|
end
|
63
50
|
|
64
51
|
def [](key)
|
@@ -178,9 +165,7 @@ module Mihari
|
|
178
165
|
# @return [Mihari::Services::Rule]
|
179
166
|
#
|
180
167
|
def from_yaml(yaml)
|
181
|
-
|
182
|
-
rescue Psych::SyntaxError => e
|
183
|
-
raise YAMLSyntaxError, e.message
|
168
|
+
new YAML.safe_load(ERB.new(yaml).result, permitted_classes: [Date, Symbol])
|
184
169
|
end
|
185
170
|
|
186
171
|
#
|
@@ -189,48 +174,7 @@ module Mihari
|
|
189
174
|
# @return [Mihari::Services::Rule]
|
190
175
|
#
|
191
176
|
def from_model(model)
|
192
|
-
|
193
|
-
end
|
194
|
-
|
195
|
-
#
|
196
|
-
# Load a rule from path
|
197
|
-
#
|
198
|
-
# @param [String] path
|
199
|
-
#
|
200
|
-
# @return [Mihari::Services::Rule, nil]
|
201
|
-
#
|
202
|
-
def from_path(path)
|
203
|
-
return nil unless Pathname(path).exist?
|
204
|
-
|
205
|
-
from_yaml File.read(path)
|
206
|
-
end
|
207
|
-
|
208
|
-
#
|
209
|
-
# Load a rule from DB
|
210
|
-
#
|
211
|
-
# @param [String] id
|
212
|
-
#
|
213
|
-
# @return [Mihari::Services::Rule, nil]
|
214
|
-
#
|
215
|
-
def from_id(id)
|
216
|
-
return nil unless Mihari::Rule.exists?(id)
|
217
|
-
|
218
|
-
Services::RuleProxy.from_model Mihari::Rule.find(id)
|
219
|
-
end
|
220
|
-
|
221
|
-
#
|
222
|
-
# @param [String] path_or_id Path to YAML file or YAML string or ID of a rule in the database
|
223
|
-
#
|
224
|
-
# @return [Mihari::Services::Rule]
|
225
|
-
#
|
226
|
-
def from_path_or_id(path_or_id)
|
227
|
-
rule = from_path(path_or_id)
|
228
|
-
return rule unless rule.nil?
|
229
|
-
|
230
|
-
rule = from_id(path_or_id)
|
231
|
-
return rule unless rule.nil?
|
232
|
-
|
233
|
-
raise ArgumentError, "#{path_or_id} does not exist"
|
177
|
+
new model.data
|
234
178
|
end
|
235
179
|
end
|
236
180
|
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module Mihari
|
4
4
|
module Services
|
5
5
|
class RuleRunner
|
6
|
+
include Dry::Monads[:result, :try]
|
7
|
+
|
6
8
|
include Mixins::ErrorNotification
|
7
9
|
|
8
10
|
# @return [Mihari::Services::RuleProxy]
|
@@ -38,11 +40,14 @@ module Mihari
|
|
38
40
|
# @return [Mihari::Alert, nil]
|
39
41
|
#
|
40
42
|
def run
|
41
|
-
|
43
|
+
rule.analyzer.run
|
44
|
+
end
|
42
45
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
+
#
|
47
|
+
# @return [Dry::Monads::Result::Success<Mihari::Alert, nil>, Dry::Monads::Result::Failure]
|
48
|
+
#
|
49
|
+
def result
|
50
|
+
Try[StandardError] { run }.to_result
|
46
51
|
end
|
47
52
|
end
|
48
53
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Mihari
|
2
|
+
module Structs
|
3
|
+
module BinaryEdge
|
4
|
+
class Target < Dry::Struct
|
5
|
+
attribute :ip, Types::String
|
6
|
+
|
7
|
+
#
|
8
|
+
# @return [String]
|
9
|
+
#
|
10
|
+
def ip
|
11
|
+
attributes[:ip]
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def from_dynamic!(d)
|
16
|
+
d = Types::Hash[d]
|
17
|
+
new(
|
18
|
+
ip: d.fetch("ip")
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Event < Dry::Struct
|
25
|
+
attribute :target, Target
|
26
|
+
|
27
|
+
#
|
28
|
+
# @return [Target]
|
29
|
+
#
|
30
|
+
def target
|
31
|
+
attributes[:target]
|
32
|
+
end
|
33
|
+
|
34
|
+
class << self
|
35
|
+
def from_dynamic!(d)
|
36
|
+
d = Types::Hash[d]
|
37
|
+
new(
|
38
|
+
target: Target.from_dynamic!(d.fetch("target"))
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Response < Dry::Struct
|
45
|
+
# @!attribute [r] page
|
46
|
+
# @return [Integer]
|
47
|
+
attribute :page, Types::Integer
|
48
|
+
|
49
|
+
# @!attribute [r] pagesize
|
50
|
+
# @return [Integer]
|
51
|
+
attribute :pagesize, Types::Integer
|
52
|
+
|
53
|
+
# @!attribute [r] total
|
54
|
+
# @return [Integer]
|
55
|
+
attribute :total, Types::Integer
|
56
|
+
|
57
|
+
# @!attribute [r] events
|
58
|
+
# @return [Array<Event>]
|
59
|
+
attribute :events, Types.Array(Event)
|
60
|
+
|
61
|
+
#
|
62
|
+
# @return [Array<Event>]
|
63
|
+
#
|
64
|
+
def events
|
65
|
+
attributes[:events]
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# @return [Array<Artifact>]
|
70
|
+
#
|
71
|
+
def artifacts
|
72
|
+
events.map { |event| Artifact.new(data: event.target.ip) }
|
73
|
+
end
|
74
|
+
|
75
|
+
class << self
|
76
|
+
def from_dynamic!(d)
|
77
|
+
d = Types::Hash[d]
|
78
|
+
new(
|
79
|
+
page: d.fetch("page"),
|
80
|
+
pagesize: d.fetch("pagesize"),
|
81
|
+
total: d.fetch("total"),
|
82
|
+
events: d.fetch("events").map { |x| Event.from_dynamic!(x) }
|
83
|
+
)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -18,7 +18,7 @@ module Mihari
|
|
18
18
|
#
|
19
19
|
# @return [Mihari::AutonomousSystem]
|
20
20
|
#
|
21
|
-
def
|
21
|
+
def as
|
22
22
|
Mihari::AutonomousSystem.new(asn: normalize_asn(asn))
|
23
23
|
end
|
24
24
|
|
@@ -58,7 +58,7 @@ module Mihari
|
|
58
58
|
#
|
59
59
|
# @return [Mihari::Geolocation] <description>
|
60
60
|
#
|
61
|
-
def
|
61
|
+
def geolocation
|
62
62
|
# sometimes Censys overlooks country
|
63
63
|
# then set geolocation as nil
|
64
64
|
return nil if country.nil?
|
@@ -98,7 +98,7 @@ module Mihari
|
|
98
98
|
#
|
99
99
|
# @return [Mihari::Port]
|
100
100
|
#
|
101
|
-
def
|
101
|
+
def _port
|
102
102
|
Port.new(port: port)
|
103
103
|
end
|
104
104
|
|
@@ -162,20 +162,20 @@ module Mihari
|
|
162
162
|
#
|
163
163
|
# @return [Array<Mihari::Port>]
|
164
164
|
#
|
165
|
-
def
|
166
|
-
services.map(&:
|
165
|
+
def ports
|
166
|
+
services.map(&:_port)
|
167
167
|
end
|
168
168
|
|
169
169
|
#
|
170
170
|
# @return [Mihari::Artifact]
|
171
171
|
#
|
172
|
-
def
|
172
|
+
def artifact
|
173
173
|
Artifact.new(
|
174
174
|
data: ip,
|
175
175
|
metadata: metadata,
|
176
|
-
autonomous_system: autonomous_system.
|
177
|
-
geolocation: location.
|
178
|
-
ports:
|
176
|
+
autonomous_system: autonomous_system.as,
|
177
|
+
geolocation: location.geolocation,
|
178
|
+
ports: ports
|
179
179
|
)
|
180
180
|
end
|
181
181
|
|
@@ -269,8 +269,8 @@ module Mihari
|
|
269
269
|
#
|
270
270
|
# @return [Array<Mihari::Artifact>]
|
271
271
|
#
|
272
|
-
def
|
273
|
-
hits.map(&:
|
272
|
+
def artifacts
|
273
|
+
hits.map(&:artifact)
|
274
274
|
end
|
275
275
|
|
276
276
|
class << self
|
@@ -34,14 +34,14 @@ module Mihari
|
|
34
34
|
#
|
35
35
|
# @return [Mihari::AutonomousSystem]
|
36
36
|
#
|
37
|
-
def
|
37
|
+
def as
|
38
38
|
Mihari::AutonomousSystem.new(asn: normalize_asn(asn))
|
39
39
|
end
|
40
40
|
|
41
41
|
#
|
42
42
|
# @return [Mihari::Geolocation]
|
43
43
|
#
|
44
|
-
def
|
44
|
+
def geolocation
|
45
45
|
Mihari::Geolocation.new(
|
46
46
|
country: country,
|
47
47
|
country_code: country_code
|
@@ -94,12 +94,12 @@ module Mihari
|
|
94
94
|
#
|
95
95
|
# @return [Mihari::Artifact]
|
96
96
|
#
|
97
|
-
def
|
97
|
+
def artifact
|
98
98
|
Mihari::Artifact.new(
|
99
99
|
data: ip,
|
100
100
|
metadata: metadata_,
|
101
|
-
autonomous_system: metadata.
|
102
|
-
geolocation: metadata.
|
101
|
+
autonomous_system: metadata.as,
|
102
|
+
geolocation: metadata.geolocation
|
103
103
|
)
|
104
104
|
end
|
105
105
|
|
@@ -126,6 +126,7 @@ module Mihari
|
|
126
126
|
attribute :data, Types.Array(Datum)
|
127
127
|
attribute :message, Types::String
|
128
128
|
attribute :query, Types::String
|
129
|
+
attribute :scroll, Types::String.optional
|
129
130
|
|
130
131
|
#
|
131
132
|
# @return [Boolean]
|
@@ -162,11 +163,18 @@ module Mihari
|
|
162
163
|
attributes[:query]
|
163
164
|
end
|
164
165
|
|
166
|
+
#
|
167
|
+
# @return [String, nil]
|
168
|
+
#
|
169
|
+
def scroll
|
170
|
+
attributes[:scroll]
|
171
|
+
end
|
172
|
+
|
165
173
|
#
|
166
174
|
# @return [Array<Mihari::Artifact>]
|
167
175
|
#
|
168
|
-
def
|
169
|
-
data.map
|
176
|
+
def artifacts
|
177
|
+
data.map(&:artifact)
|
170
178
|
end
|
171
179
|
|
172
180
|
class << self
|
@@ -182,7 +190,8 @@ module Mihari
|
|
182
190
|
count: d.fetch("count"),
|
183
191
|
data: d.fetch("data").map { |x| Datum.from_dynamic!(x) },
|
184
192
|
message: d.fetch("message"),
|
185
|
-
query: d.fetch("query")
|
193
|
+
query: d.fetch("query"),
|
194
|
+
scroll: d["scroll"]
|
186
195
|
)
|
187
196
|
end
|
188
197
|
end
|
@@ -42,19 +42,19 @@ module Mihari
|
|
42
42
|
#
|
43
43
|
# @return [Mihari::Artifact]
|
44
44
|
#
|
45
|
-
def
|
45
|
+
def artifact
|
46
46
|
Mihari::Artifact.new(
|
47
47
|
data: ip,
|
48
48
|
metadata: metadata,
|
49
|
-
autonomous_system:
|
50
|
-
geolocation:
|
49
|
+
autonomous_system: as,
|
50
|
+
geolocation: geolocation
|
51
51
|
)
|
52
52
|
end
|
53
53
|
|
54
54
|
#
|
55
55
|
# @return [Mihari::Geolocation, nil]
|
56
56
|
#
|
57
|
-
def
|
57
|
+
def geolocation
|
58
58
|
return nil if country_code.nil?
|
59
59
|
|
60
60
|
Mihari::Geolocation.new(
|
@@ -66,7 +66,7 @@ module Mihari
|
|
66
66
|
#
|
67
67
|
# @return [Mihari::AutonomousSystem]
|
68
68
|
#
|
69
|
-
def
|
69
|
+
def as
|
70
70
|
Mihari::AutonomousSystem.new(asn: normalize_asn(asn))
|
71
71
|
end
|
72
72
|
|
@@ -150,8 +150,8 @@ module Mihari
|
|
150
150
|
#
|
151
151
|
# @return [Array<Mihari::Artifact>]
|
152
152
|
#
|
153
|
-
def
|
154
|
-
results.map(&:
|
153
|
+
def artifacts
|
154
|
+
results.map(&:artifact)
|
155
155
|
end
|
156
156
|
|
157
157
|
class << self
|
@@ -24,7 +24,7 @@ module Mihari
|
|
24
24
|
#
|
25
25
|
# @return [Mihari::Geolocation, nil]
|
26
26
|
#
|
27
|
-
def
|
27
|
+
def geolocation
|
28
28
|
return nil if country_name.nil? && country_code.nil?
|
29
29
|
|
30
30
|
Mihari::Geolocation.new(
|
@@ -105,7 +105,7 @@ module Mihari
|
|
105
105
|
#
|
106
106
|
# @return [Mihari::AutonomousSystem, nil]
|
107
107
|
#
|
108
|
-
def
|
108
|
+
def _asn
|
109
109
|
return nil if asn.nil?
|
110
110
|
|
111
111
|
Mihari::AutonomousSystem.new(asn: normalize_asn(asn))
|
@@ -140,7 +140,7 @@ module Mihari
|
|
140
140
|
end
|
141
141
|
end
|
142
142
|
|
143
|
-
class
|
143
|
+
class Response < Dry::Struct
|
144
144
|
attribute :matches, Types.Array(Match)
|
145
145
|
attribute :total, Types::Int
|
146
146
|
|
@@ -194,9 +194,10 @@ module Mihari
|
|
194
194
|
#
|
195
195
|
# @return [Array<Mihari::Artifact>]
|
196
196
|
#
|
197
|
-
def
|
197
|
+
def artifacts
|
198
198
|
matches.map do |match|
|
199
199
|
metadata = collect_metadata_by_ip(match.ip_str)
|
200
|
+
|
200
201
|
ports = collect_ports_by_ip(match.ip_str).map do |port|
|
201
202
|
Mihari::Port.new(port: port)
|
202
203
|
end
|
@@ -207,8 +208,8 @@ module Mihari
|
|
207
208
|
Mihari::Artifact.new(
|
208
209
|
data: match.ip_str,
|
209
210
|
metadata: metadata,
|
210
|
-
autonomous_system: match.
|
211
|
-
geolocation: match.location.
|
211
|
+
autonomous_system: match._asn,
|
212
|
+
geolocation: match.location.geolocation,
|
212
213
|
ports: ports,
|
213
214
|
reverse_dns_names: reverse_dns_names
|
214
215
|
)
|
@@ -83,11 +83,9 @@ module Mihari
|
|
83
83
|
#
|
84
84
|
# @return [Array<Mihari::Artifact>]
|
85
85
|
#
|
86
|
-
def
|
86
|
+
def artifacts
|
87
87
|
values = [page.url, page.domain, page.ip].compact
|
88
|
-
values.map
|
89
|
-
Mihari::Artifact.new(data: value, metadata: metadata)
|
90
|
-
end
|
88
|
+
values.map { |value| Mihari::Artifact.new(data: value, metadata: metadata) }
|
91
89
|
end
|
92
90
|
|
93
91
|
class << self
|
@@ -129,8 +127,8 @@ module Mihari
|
|
129
127
|
#
|
130
128
|
# @return [Array<Mihari::Artifact>]
|
131
129
|
#
|
132
|
-
def
|
133
|
-
results.map(&:
|
130
|
+
def artifacts
|
131
|
+
results.map(&:artifacts).flatten
|
134
132
|
end
|
135
133
|
|
136
134
|
class << self
|