mihari 5.6.2 → 5.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -1
  3. data/README.md +1 -0
  4. data/config.ru +1 -1
  5. data/docs/analyzers/fofa.md +31 -0
  6. data/docs/analyzers/index.md +1 -0
  7. data/frontend/package-lock.json +73 -73
  8. data/frontend/package.json +5 -5
  9. data/frontend/src/components/alert/Form.vue +1 -14
  10. data/frontend/src/components/artifact/AS.vue +2 -8
  11. data/frontend/src/components/artifact/DnsRecords.vue +2 -8
  12. data/frontend/src/components/artifact/ReverseDnsNames.vue +2 -10
  13. data/frontend/src/components/artifact/WhoisRecord.vue +1 -1
  14. data/lib/mihari/actor.rb +14 -4
  15. data/lib/mihari/analyzers/base.rb +13 -12
  16. data/lib/mihari/analyzers/binaryedge.rb +4 -1
  17. data/lib/mihari/analyzers/censys.rb +4 -2
  18. data/lib/mihari/analyzers/circl.rb +4 -1
  19. data/lib/mihari/analyzers/crtsh.rb +4 -1
  20. data/lib/mihari/analyzers/dnstwister.rb +4 -1
  21. data/lib/mihari/analyzers/feed.rb +3 -0
  22. data/lib/mihari/analyzers/fofa.rb +65 -0
  23. data/lib/mihari/analyzers/greynoise.rb +4 -1
  24. data/lib/mihari/analyzers/hunterhow.rb +6 -1
  25. data/lib/mihari/analyzers/onyphe.rb +4 -1
  26. data/lib/mihari/analyzers/otx.rb +4 -1
  27. data/lib/mihari/analyzers/passivetotal.rb +4 -1
  28. data/lib/mihari/analyzers/pulsedive.rb +3 -0
  29. data/lib/mihari/analyzers/securitytrails.rb +4 -1
  30. data/lib/mihari/analyzers/shodan.rb +4 -1
  31. data/lib/mihari/analyzers/urlscan.rb +4 -1
  32. data/lib/mihari/analyzers/virustotal.rb +4 -1
  33. data/lib/mihari/analyzers/virustotal_intelligence.rb +4 -1
  34. data/lib/mihari/analyzers/zoomeye.rb +5 -2
  35. data/lib/mihari/cli/alert.rb +3 -0
  36. data/lib/mihari/cli/base.rb +3 -0
  37. data/lib/mihari/cli/database.rb +3 -0
  38. data/lib/mihari/cli/main.rb +3 -0
  39. data/lib/mihari/cli/rule.rb +3 -0
  40. data/lib/mihari/clients/base.rb +3 -0
  41. data/lib/mihari/clients/binaryedge.rb +5 -2
  42. data/lib/mihari/clients/censys.rb +7 -4
  43. data/lib/mihari/clients/circl.rb +3 -0
  44. data/lib/mihari/clients/crtsh.rb +3 -0
  45. data/lib/mihari/clients/dnstwister.rb +3 -0
  46. data/lib/mihari/clients/fofa.rb +83 -0
  47. data/lib/mihari/clients/greynoise.rb +5 -2
  48. data/lib/mihari/clients/hunterhow.rb +5 -2
  49. data/lib/mihari/clients/misp.rb +3 -0
  50. data/lib/mihari/clients/onyphe.rb +5 -2
  51. data/lib/mihari/clients/otx.rb +3 -0
  52. data/lib/mihari/clients/passivetotal.rb +3 -0
  53. data/lib/mihari/clients/publsedive.rb +4 -1
  54. data/lib/mihari/clients/securitytrails.rb +3 -0
  55. data/lib/mihari/clients/shodan.rb +5 -2
  56. data/lib/mihari/clients/the_hive.rb +3 -0
  57. data/lib/mihari/clients/urlscan.rb +7 -4
  58. data/lib/mihari/clients/virustotal.rb +5 -2
  59. data/lib/mihari/clients/zoomeye.rb +3 -0
  60. data/lib/mihari/commands/alert.rb +5 -14
  61. data/lib/mihari/commands/database.rb +3 -0
  62. data/lib/mihari/commands/rule.rb +10 -1
  63. data/lib/mihari/commands/search.rb +9 -6
  64. data/lib/mihari/commands/version.rb +3 -0
  65. data/lib/mihari/commands/web.rb +4 -1
  66. data/lib/mihari/config.rb +139 -150
  67. data/lib/mihari/constants.rb +1 -1
  68. data/lib/mihari/database.rb +6 -0
  69. data/lib/mihari/emitters/base.rb +13 -11
  70. data/lib/mihari/emitters/database.rb +4 -1
  71. data/lib/mihari/emitters/misp.rb +7 -4
  72. data/lib/mihari/emitters/slack.rb +3 -3
  73. data/lib/mihari/emitters/the_hive.rb +3 -3
  74. data/lib/mihari/emitters/webhook.rb +4 -3
  75. data/lib/mihari/enrichers/base.rb +15 -9
  76. data/lib/mihari/enrichers/google_public_dns.rb +6 -5
  77. data/lib/mihari/enrichers/ipinfo.rb +10 -8
  78. data/lib/mihari/enrichers/shodan.rb +4 -6
  79. data/lib/mihari/enrichers/whois.rb +12 -9
  80. data/lib/mihari/errors.rb +6 -0
  81. data/lib/mihari/feed/parser.rb +3 -0
  82. data/lib/mihari/feed/reader.rb +3 -0
  83. data/lib/mihari/http.rb +6 -0
  84. data/lib/mihari/mixins/autonomous_system.rb +3 -0
  85. data/lib/mihari/mixins/configurable.rb +3 -0
  86. data/lib/mihari/mixins/error_notification.rb +3 -0
  87. data/lib/mihari/mixins/falsepositive.rb +3 -0
  88. data/lib/mihari/mixins/refang.rb +3 -0
  89. data/lib/mihari/mixins/retriable.rb +6 -2
  90. data/lib/mihari/models/alert.rb +7 -4
  91. data/lib/mihari/models/artifact.rb +6 -0
  92. data/lib/mihari/models/autonomous_system.rb +4 -1
  93. data/lib/mihari/models/cpe.rb +4 -1
  94. data/lib/mihari/models/dns.rb +4 -1
  95. data/lib/mihari/models/geolocation.rb +4 -1
  96. data/lib/mihari/models/port.rb +4 -1
  97. data/lib/mihari/models/reverse_dns.rb +4 -1
  98. data/lib/mihari/models/rule.rb +6 -3
  99. data/lib/mihari/models/tag.rb +3 -0
  100. data/lib/mihari/models/tagging.rb +3 -0
  101. data/lib/mihari/models/whois.rb +4 -3
  102. data/lib/mihari/rule.rb +17 -12
  103. data/lib/mihari/schemas/alert.rb +3 -0
  104. data/lib/mihari/schemas/analyzer.rb +11 -0
  105. data/lib/mihari/schemas/emitter.rb +3 -0
  106. data/lib/mihari/schemas/enricher.rb +3 -0
  107. data/lib/mihari/schemas/macros.rb +4 -0
  108. data/lib/mihari/schemas/mixins.rb +5 -0
  109. data/lib/mihari/schemas/rule.rb +3 -0
  110. data/lib/mihari/service.rb +16 -0
  111. data/lib/mihari/services/alert_builder.rb +8 -5
  112. data/lib/mihari/services/alert_proxy.rb +6 -1
  113. data/lib/mihari/services/alert_runner.rb +8 -12
  114. data/lib/mihari/services/rule_builder.rb +8 -5
  115. data/lib/mihari/services/rule_runner.rb +8 -10
  116. data/lib/mihari/structs/binaryedge.rb +13 -28
  117. data/lib/mihari/structs/censys.rb +48 -127
  118. data/lib/mihari/structs/config.rb +19 -30
  119. data/lib/mihari/structs/filters.rb +38 -0
  120. data/lib/mihari/structs/fofa.rb +44 -0
  121. data/lib/mihari/structs/google_public_dns.rb +10 -28
  122. data/lib/mihari/structs/greynoise.rb +33 -84
  123. data/lib/mihari/structs/hunterhow.rb +24 -22
  124. data/lib/mihari/structs/ipinfo.rb +14 -35
  125. data/lib/mihari/structs/onyphe.rb +31 -76
  126. data/lib/mihari/structs/shodan.rb +47 -112
  127. data/lib/mihari/structs/urlscan.rb +24 -63
  128. data/lib/mihari/structs/virustotal_intelligence.rb +20 -56
  129. data/lib/mihari/type_checker.rb +4 -0
  130. data/lib/mihari/types.rb +3 -0
  131. data/lib/mihari/version.rb +1 -1
  132. data/lib/mihari/web/api.rb +15 -10
  133. data/lib/mihari/web/app.rb +59 -54
  134. data/lib/mihari/web/endpoints/alerts.rb +94 -89
  135. data/lib/mihari/web/endpoints/artifacts.rb +115 -110
  136. data/lib/mihari/web/endpoints/configs.rb +18 -13
  137. data/lib/mihari/web/endpoints/ip_addresses.rb +21 -16
  138. data/lib/mihari/web/endpoints/rules.rb +203 -198
  139. data/lib/mihari/web/endpoints/tags.rb +41 -36
  140. data/lib/mihari/web/middleware/connection_adapter.rb +16 -9
  141. data/lib/mihari/web/middleware/error_notification_adapter.rb +17 -10
  142. data/lib/mihari/web/public/assets/{index-28d4c79d.js → index-821134e2.js} +30 -30
  143. data/lib/mihari/web/public/assets/mode-yaml-24faa242.js +8 -0
  144. data/lib/mihari/web/public/index.html +1 -1
  145. data/lib/mihari.rb +24 -5
  146. data/mihari.gemspec +8 -1
  147. data/mkdocs.yml +3 -2
  148. metadata +39 -7
  149. data/lib/mihari/templates/rule.yml.erb +0 -5
  150. data/lib/mihari/web/public/assets/mode-yaml-a21faa53.js +0 -8
@@ -4,6 +4,9 @@ require "normalize_country"
4
4
 
5
5
  module Mihari
6
6
  module Models
7
+ #
8
+ # Geolocation model
9
+ #
7
10
  class Geolocation < ActiveRecord::Base
8
11
  belongs_to :artifact
9
12
 
@@ -19,7 +22,7 @@ module Mihari
19
22
  # @return [Mihari::Geolocation, nil]
20
23
  #
21
24
  def build_by_ip(ip, enricher: Enrichers::IPInfo.new)
22
- result = enricher.query_result(ip).bind do |res|
25
+ result = enricher.result(ip).bind do |res|
23
26
  value = res&.country_code
24
27
  if value.nil?
25
28
  Success nil
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Models
5
+ #
6
+ # Port model
7
+ #
5
8
  class Port < ActiveRecord::Base
6
9
  belongs_to :artifact
7
10
 
@@ -17,7 +20,7 @@ module Mihari
17
20
  # @return [Array<Mihari::Port>]
18
21
  #
19
22
  def build_by_ip(ip, enricher: Enrichers::Shodan.new)
20
- result = enricher.query_result(ip).bind do |res|
23
+ result = enricher.result(ip).bind do |res|
21
24
  if res.nil?
22
25
  Success []
23
26
  else
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Models
5
+ #
6
+ # Reverse DNS name model
7
+ #
5
8
  class ReverseDnsName < ActiveRecord::Base
6
9
  belongs_to :artifact
7
10
 
@@ -17,7 +20,7 @@ module Mihari
17
20
  # @return [Array<Mihari::Models::ReverseDnsName>]
18
21
  #
19
22
  def build_by_ip(ip, enricher: Enrichers::Shodan.new)
20
- result = enricher.query_result(ip).bind do |res|
23
+ result = enricher.result(ip).bind do |res|
21
24
  if res.nil?
22
25
  Success []
23
26
  else
@@ -4,6 +4,9 @@ require "yaml"
4
4
 
5
5
  module Mihari
6
6
  module Models
7
+ #
8
+ # Rule model
9
+ #
7
10
  class Rule < ActiveRecord::Base
8
11
  has_many :alerts, dependent: :destroy
9
12
 
@@ -23,7 +26,7 @@ module Mihari
23
26
  #
24
27
  # Search rules
25
28
  #
26
- # @param [Structs::Filters::Rule::SearchFilterWithPagination] filter
29
+ # @param [Mihari::Structs::Filters::Rule::SearchFilterWithPagination] filter
27
30
  #
28
31
  # @return [Array<Rule>]
29
32
  #
@@ -46,7 +49,7 @@ module Mihari
46
49
  #
47
50
  # Count alerts
48
51
  #
49
- # @param [Structs::Filters::Rule::SearchFilterWithPagination] filter
52
+ # @param [Mihari::Structs::Filters::Rule::SearchFilterWithPagination] filter
50
53
  #
51
54
  # @return [Integer]
52
55
  #
@@ -58,7 +61,7 @@ module Mihari
58
61
  private
59
62
 
60
63
  #
61
- # @param [Structs::Filters::Rule::SearchFilter] filter
64
+ # @param [Mihari::Structs::Filters::Rule::SearchFilter] filter
62
65
  #
63
66
  # @return [Mihari::Models::Rule]
64
67
  #
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Models
5
+ #
6
+ # Tag model
7
+ #
5
8
  class Tag < ActiveRecord::Base
6
9
  has_many :taggings, dependent: :destroy
7
10
  has_many :tags, through: :taggings
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Models
5
+ #
6
+ # Tagging model
7
+ #
5
8
  class Tagging < ActiveRecord::Base
6
9
  belongs_to :alert
7
10
  belongs_to :tag
@@ -2,14 +2,15 @@
2
2
 
3
3
  module Mihari
4
4
  module Models
5
+ #
6
+ # Whois record model
7
+ #
5
8
  class WhoisRecord < ActiveRecord::Base
6
9
  belongs_to :artifact
7
10
 
8
11
  @memo = {}
9
12
 
10
13
  class << self
11
- include Dry::Monads[:result]
12
-
13
14
  #
14
15
  # Build whois record
15
16
  #
@@ -19,7 +20,7 @@ module Mihari
19
20
  # @return [WhoisRecord, nil]
20
21
  #
21
22
  def build_by_domain(domain, enricher: Enrichers::Whois.new)
22
- result = enricher.query_result(domain)
23
+ result = enricher.result(domain)
23
24
  result.value_or nil
24
25
  end
25
26
  end
data/lib/mihari/rule.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- class Rule
4
+ class Rule < Service
5
5
  include Mixins::FalsePositive
6
6
 
7
7
  # @return [Hash]
@@ -19,6 +19,8 @@ module Mihari
19
19
  # @param [Hash] data
20
20
  #
21
21
  def initialize(**data)
22
+ super()
23
+
22
24
  @data = data.deep_symbolize_keys
23
25
  @errors = nil
24
26
  @base_time = Time.now.utc
@@ -109,16 +111,19 @@ module Mihari
109
111
  #
110
112
  def artifacts
111
113
  analyzers.flat_map do |analyzer|
114
+ # @type [Dry::Monads::Result::Success<Array<Mihari::Models::Artifact>>, Dry::Monads::Result::Failure]
112
115
  result = analyzer.result
113
116
 
114
- raise result.failure if result.failure? && !analyzer.ignore_error?
115
-
116
- artifacts = result.value!
117
- artifacts.map do |artifact|
118
- artifact.rule_id = id
119
- artifact
117
+ if result.failure?
118
+ raise result.failure unless analyzer.ignore_error?
119
+ else
120
+ artifacts = result.value!
121
+ artifacts.map do |artifact|
122
+ artifact.rule_id = id
123
+ artifact
124
+ end
120
125
  end
121
- end
126
+ end.compact
122
127
  end
123
128
 
124
129
  #
@@ -169,7 +174,7 @@ module Mihari
169
174
 
170
175
  # NOTE: separate parallel execution and logging
171
176
  # because the logger does not work along with Parallel
172
- results = Parallel.map(emitters) { |emitter| emitter.emit_result(enriched_artifacts) }
177
+ results = Parallel.map(emitters) { |emitter| emitter.result enriched_artifacts }
173
178
  results.zip(emitters).map do |result_and_emitter|
174
179
  result, emitter = result_and_emitter
175
180
  Mihari.logger.info "Emission by #{emitter.class} is failed: #{result.failure}" if result.failure?
@@ -183,7 +188,7 @@ module Mihari
183
188
  #
184
189
  # @return [Mihari::Models::Alert, nil]
185
190
  #
186
- def run
191
+ def call
187
192
  # Validate analyzers & emitters before using them
188
193
  analyzers
189
194
  emitters
@@ -219,7 +224,7 @@ module Mihari
219
224
  #
220
225
  # @param [String] yaml
221
226
  #
222
- # @return [Mihari::Services::Rule]
227
+ # @return [Mihari::Rule]
223
228
  #
224
229
  def from_yaml(yaml)
225
230
  data = YAML.safe_load(ERB.new(yaml).result, permitted_classes: [Date, Symbol])
@@ -229,7 +234,7 @@ module Mihari
229
234
  #
230
235
  # @param [Mihari::Models::Rule] model
231
236
  #
232
- # @return [Mihari::Services::Rule]
237
+ # @return [Mihari::Rule]
233
238
  #
234
239
  def from_model(model)
235
240
  new(**model.data)
@@ -7,6 +7,9 @@ module Mihari
7
7
  required(:artifacts).value(array[:string])
8
8
  end
9
9
 
10
+ #
11
+ # Alert schema contract
12
+ #
10
13
  class AlertContract < Dry::Validation::Contract
11
14
  params(Alert)
12
15
  end
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Schemas
5
+ #
6
+ # Analyzer schemas
7
+ #
5
8
  module Analyzers
6
9
  extend Schemas::Mixins
7
10
 
@@ -61,6 +64,14 @@ module Mihari
61
64
  optional(:options).hash(AnalyzerOptions)
62
65
  end
63
66
 
67
+ Fofa = Dry::Schema.Params do
68
+ required(:analyzer).value(Types::String.enum(*Mihari::Analyzers::Fofa.class_keys))
69
+ required(:query).value(:string)
70
+ optional(:api_key).value(:string)
71
+ optional(:email).value(:string)
72
+ optional(:options).hash(AnalyzerPaginationOptions)
73
+ end
74
+
64
75
  PassiveTotal = Dry::Schema.Params do
65
76
  required(:analyzer).value(Types::String.enum(*Mihari::Analyzers::PassiveTotal.class_keys))
66
77
  required(:query).value(:string)
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Schemas
5
+ #
6
+ # Emitter schemas
7
+ #
5
8
  module Emitters
6
9
  extend Schemas::Mixins
7
10
 
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Schemas
5
+ #
6
+ # Enricher schemas
7
+ #
5
8
  module Enrichers
6
9
  extend Schemas::Mixins
7
10
 
@@ -3,6 +3,10 @@
3
3
  module Dry
4
4
  module Schema
5
5
  module Macros
6
+ #
7
+ # Macros DSL for options with default values
8
+ # (see https://github.com/dry-rb/dry-schema/issues/70)
9
+ #
6
10
  class DSL
7
11
  def default(value)
8
12
  schema_dsl.before(:rule_applier) do |result|
@@ -1,5 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Mihari
2
4
  module Schemas
5
+ #
6
+ # Mixins for schemas
7
+ #
3
8
  module Mixins
4
9
  def get_or_composition
5
10
  schemas = constants.map { |sym| const_get sym }
@@ -33,6 +33,9 @@ module Mihari
33
33
  optional(:artifact_ttl).value(:integer)
34
34
  end
35
35
 
36
+ #
37
+ # Rule schema contract
38
+ #
36
39
  class RuleContract < Dry::Validation::Contract
37
40
  include Mihari::Mixins::FalsePositive
38
41
 
@@ -0,0 +1,16 @@
1
+ module Mihari
2
+ #
3
+ # Base class for services
4
+ #
5
+ class Service
6
+ include Dry::Monads[:result, :try]
7
+
8
+ def call(*args, **kwargs)
9
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
10
+ end
11
+
12
+ def result
13
+ Try[StandardError] { call }.to_result
14
+ end
15
+ end
16
+ end
@@ -8,9 +8,10 @@ require "yaml"
8
8
 
9
9
  module Mihari
10
10
  module Services
11
- class AlertBuilder
12
- include Dry::Monads[:result, :try]
13
-
11
+ #
12
+ # Alert builder
13
+ #
14
+ class AlertBuilder < Service
14
15
  # @return [String]
15
16
  attr_reader :path
16
17
 
@@ -20,6 +21,8 @@ module Mihari
20
21
  # @param [String] path
21
22
  #
22
23
  def initialize(path)
24
+ super()
25
+
23
26
  @path = path
24
27
  end
25
28
 
@@ -35,8 +38,8 @@ module Mihari
35
38
  )
36
39
  end
37
40
 
38
- def result
39
- Try[StandardError] { AlertProxy.new(**data) }.to_result
41
+ def call
42
+ AlertProxy.new(**data)
40
43
  end
41
44
  end
42
45
  end
@@ -4,7 +4,10 @@ require "json"
4
4
 
5
5
  module Mihari
6
6
  module Services
7
- class AlertProxy
7
+ #
8
+ # Alert proxy
9
+ #
10
+ class AlertProxy < Service
8
11
  # @return [Hash]
9
12
  attr_reader :data
10
13
 
@@ -17,6 +20,8 @@ module Mihari
17
20
  # @param [Hash] data
18
21
  #
19
22
  def initialize(**data)
23
+ super()
24
+
20
25
  @data = data.deep_symbolize_keys
21
26
  @errors = nil
22
27
 
@@ -2,29 +2,25 @@
2
2
 
3
3
  module Mihari
4
4
  module Services
5
- class AlertRunner
6
- include Dry::Monads[:result, :try]
7
-
5
+ #
6
+ # Alert runner
7
+ #
8
+ class AlertRunner < Service
8
9
  # @return [Mihari::Services::AlertProxy]
9
10
  attr_reader :alert
10
11
 
11
12
  def initialize(alert)
13
+ super()
14
+
12
15
  @alert = alert
13
16
  end
14
17
 
15
18
  #
16
19
  # @return [Mihari::Models::Alert]
17
20
  #
18
- def run
21
+ def call
19
22
  emitter = Emitters::Database.new(rule: alert.rule)
20
- emitter.emit alert.artifacts
21
- end
22
-
23
- #
24
- # @return [Dry::Monads::Result::Success<Mihari::Models::Alert, nil>, Dry::Monads::Result::Failure]
25
- #
26
- def result
27
- Try[StandardError] { run }.to_result
23
+ emitter.call alert.artifacts
28
24
  end
29
25
  end
30
26
  end
@@ -7,9 +7,10 @@ require "yaml"
7
7
 
8
8
  module Mihari
9
9
  module Services
10
- class RuleBuilder
11
- include Dry::Monads[:result, :try]
12
-
10
+ #
11
+ # Rule builder
12
+ #
13
+ class RuleBuilder < Service
13
14
  # @return [String]
14
15
  attr_reader :path_or_id
15
16
 
@@ -19,6 +20,8 @@ module Mihari
19
20
  # @param [String] path_or_id
20
21
  #
21
22
  def initialize(path_or_id)
23
+ super()
24
+
22
25
  @path_or_id = path_or_id
23
26
  end
24
27
 
@@ -39,8 +42,8 @@ module Mihari
39
42
  )
40
43
  end
41
44
 
42
- def result
43
- Try[StandardError] { Rule.new(**data) }.to_result
45
+ def call
46
+ Rule.new(**data)
44
47
  end
45
48
  end
46
49
  end
@@ -2,13 +2,18 @@
2
2
 
3
3
  module Mihari
4
4
  module Services
5
- class RuleRunner
5
+ #
6
+ # Rule runner
7
+ #
8
+ class RuleRunner < Service
6
9
  include Dry::Monads[:result, :try]
7
10
 
8
11
  # @return [Mihari::Rule]
9
12
  attr_reader :rule
10
13
 
11
14
  def initialize(rule)
15
+ super()
16
+
12
17
  @rule = rule
13
18
  end
14
19
 
@@ -29,15 +34,8 @@ module Mihari
29
34
  #
30
35
  # @return [Mihari::Models::Alert, nil]
31
36
  #
32
- def run
33
- rule.run
34
- end
35
-
36
- #
37
- # @return [Dry::Monads::Result::Success<Mihari::Models::Alert, nil>, Dry::Monads::Result::Failure]
38
- #
39
- def result
40
- Try[StandardError] { run }.to_result
37
+ def call
38
+ rule.call
41
39
  end
42
40
  end
43
41
  end
@@ -1,16 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Mihari
2
4
  module Structs
3
5
  module BinaryEdge
4
6
  class Target < Dry::Struct
7
+ # @!attribute [r] ip
8
+ # @return [String]
5
9
  attribute :ip, Types::String
6
10
 
7
- #
8
- # @return [String]
9
- #
10
- def ip
11
- attributes[:ip]
12
- end
13
-
14
11
  class << self
15
12
  def from_dynamic!(d)
16
13
  d = Types::Hash[d]
@@ -22,15 +19,10 @@ module Mihari
22
19
  end
23
20
 
24
21
  class Event < Dry::Struct
22
+ # @!attribute [r] target
23
+ # @return [Target]
25
24
  attribute :target, Target
26
25
 
27
- #
28
- # @return [Target]
29
- #
30
- def target
31
- attributes[:target]
32
- end
33
-
34
26
  class << self
35
27
  def from_dynamic!(d)
36
28
  d = Types::Hash[d]
@@ -43,28 +35,21 @@ module Mihari
43
35
 
44
36
  class Response < Dry::Struct
45
37
  # @!attribute [r] page
46
- # @return [Integer]
47
- attribute :page, Types::Integer
38
+ # @return [Integer]
39
+ attribute :page, Types::Int
48
40
 
49
41
  # @!attribute [r] pagesize
50
- # @return [Integer]
51
- attribute :pagesize, Types::Integer
42
+ # @return [Integer]
43
+ attribute :pagesize, Types::Int
52
44
 
53
45
  # @!attribute [r] total
54
- # @return [Integer]
55
- attribute :total, Types::Integer
46
+ # @return [Integer]
47
+ attribute :total, Types::Int
56
48
 
57
49
  # @!attribute [r] events
58
- # @return [Array<Event>]
50
+ # @return [Array<Event>]
59
51
  attribute :events, Types.Array(Event)
60
52
 
61
- #
62
- # @return [Array<Event>]
63
- #
64
- def events
65
- attributes[:events]
66
- end
67
-
68
53
  #
69
54
  # @return [Array<Artifact>]
70
55
  #