mihari 5.7.1 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/config.ru +2 -0
  3. data/lib/mihari/analyzers/dnstwister.rb +2 -4
  4. data/lib/mihari/analyzers/urlscan.rb +1 -4
  5. data/lib/mihari/cli/main.rb +4 -12
  6. data/lib/mihari/clients/base.rb +23 -1
  7. data/lib/mihari/clients/binaryedge.rb +1 -3
  8. data/lib/mihari/clients/censys.rb +1 -2
  9. data/lib/mihari/clients/crtsh.rb +2 -3
  10. data/lib/mihari/clients/dnstwister.rb +1 -2
  11. data/lib/mihari/clients/fofa.rb +1 -3
  12. data/lib/mihari/clients/greynoise.rb +1 -2
  13. data/lib/mihari/clients/hunterhow.rb +1 -2
  14. data/lib/mihari/clients/misp.rb +1 -2
  15. data/lib/mihari/clients/onyphe.rb +1 -2
  16. data/lib/mihari/clients/otx.rb +2 -14
  17. data/lib/mihari/clients/passivetotal.rb +3 -16
  18. data/lib/mihari/clients/publsedive.rb +2 -17
  19. data/lib/mihari/clients/securitytrails.rb +3 -25
  20. data/lib/mihari/clients/shodan.rb +1 -2
  21. data/lib/mihari/clients/the_hive.rb +1 -2
  22. data/lib/mihari/clients/urlscan.rb +1 -2
  23. data/lib/mihari/clients/virustotal.rb +3 -17
  24. data/lib/mihari/clients/zoomeye.rb +9 -19
  25. data/lib/mihari/commands/alert.rb +11 -11
  26. data/lib/mihari/commands/database.rb +4 -2
  27. data/lib/mihari/commands/mixins.rb +11 -0
  28. data/lib/mihari/commands/search.rb +15 -15
  29. data/lib/mihari/constants.rb +1 -1
  30. data/lib/mihari/database.rb +3 -5
  31. data/lib/mihari/emitters/slack.rb +3 -6
  32. data/lib/mihari/emitters/the_hive.rb +3 -7
  33. data/lib/mihari/enrichers/google_public_dns.rb +2 -7
  34. data/lib/mihari/enrichers/ipinfo.rb +1 -3
  35. data/lib/mihari/enrichers/shodan.rb +1 -3
  36. data/lib/mihari/enrichers/whois.rb +0 -4
  37. data/lib/mihari/http.rb +13 -11
  38. data/lib/mihari/mixins/refang.rb +1 -4
  39. data/lib/mihari/mixins/unwrap_error.rb +27 -0
  40. data/lib/mihari/models/alert.rb +1 -3
  41. data/lib/mihari/models/artifact.rb +5 -7
  42. data/lib/mihari/models/rule.rb +1 -2
  43. data/lib/mihari/rule.rb +14 -10
  44. data/lib/mihari/service.rb +2 -0
  45. data/lib/mihari/services/rule_builder.rb +2 -4
  46. data/lib/mihari/structs/fofa.rb +2 -0
  47. data/lib/mihari/version.rb +1 -1
  48. data/lib/mihari/web/app.rb +3 -1
  49. data/lib/mihari/web/endpoints/alerts.rb +14 -18
  50. data/lib/mihari/web/endpoints/artifacts.rb +17 -22
  51. data/lib/mihari/web/endpoints/configs.rb +0 -1
  52. data/lib/mihari/web/endpoints/ip_addresses.rb +1 -1
  53. data/lib/mihari/web/endpoints/rules.rb +27 -32
  54. data/lib/mihari/web/endpoints/tags.rb +7 -9
  55. data/lib/mihari/web/middleware/connection_adapter.rb +3 -5
  56. data/lib/mihari/web/middleware/error_notification_adapter.rb +15 -6
  57. data/lib/mihari/web/public/assets/{index-07fafab5.js → index-07cddfcd.js} +44 -44
  58. data/lib/mihari/web/public/index.html +1 -1
  59. data/lib/mihari/web/public/redoc-static.html +381 -401
  60. data/lib/mihari.rb +1 -2
  61. data/mihari.gemspec +14 -16
  62. data/mkdocs.yml +14 -8
  63. data/requirements.txt +1 -1
  64. metadata +81 -39
  65. data/lib/mihari/mixins/error_notification.rb +0 -21
  66. data/lib/mihari/services/rule_runner.rb +0 -19
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Make possible to use upper case acronyms in class names
4
- ActiveSupport::Inflector.inflections(:en) do |inflect|
5
- inflect.acronym "CPE"
6
- end
4
+ ActiveSupport::Inflector.inflections(:en) { |inflect| inflect.acronym "CPE" }
7
5
 
8
6
  def env
9
7
  ENV["APP_ENV"] || ENV["RACK_ENV"]
@@ -134,7 +132,7 @@ module Mihari
134
132
  class Database
135
133
  class << self
136
134
  #
137
- # DB migraration
135
+ # DB migration
138
136
  #
139
137
  # @param [Symbol] direction
140
138
  #
@@ -175,7 +173,7 @@ module Mihari
175
173
  Mihari::Database.connect
176
174
  yield
177
175
  rescue ActiveRecord::StatementInvalid
178
- Mihari.logger.error("You haven't finished the DB migration! Please run 'mihari db migrate'.")
176
+ Mihari.logger.error("The DB migration is not yet complete. Please run 'mihari db migrate'.")
179
177
  ensure
180
178
  Mihari::Database.close
181
179
  end
@@ -192,9 +192,7 @@ module Mihari
192
192
  # @return [Array<Mihari::Emitters::Attachment>]
193
193
  #
194
194
  def attachments
195
- artifacts.map do |artifact|
196
- Attachment.new(data: artifact.data, data_type: artifact.data_type).to_a
197
- end.flatten
195
+ artifacts.map { |artifact| Attachment.new(data: artifact.data, data_type: artifact.data_type).to_a }.flatten
198
196
  end
199
197
 
200
198
  #
@@ -205,7 +203,6 @@ module Mihari
205
203
  def text
206
204
  tags = rule.tags
207
205
  tags = ["N/A"] if tags.empty?
208
-
209
206
  [
210
207
  "*#{rule.title}*",
211
208
  "*Desc.*: #{rule.description}",
@@ -217,10 +214,10 @@ module Mihari
217
214
  # @param [Array<Mihari::Models::Artifact>] artifacts
218
215
  #
219
216
  def call(artifacts)
220
- return if artifacts.empty?
221
-
222
217
  @artifacts = artifacts
223
218
 
219
+ return if artifacts.empty?
220
+
224
221
  notifier.post(text: text, attachments: attachments, mrkdwn: true)
225
222
  end
226
223
 
@@ -43,10 +43,10 @@ module Mihari
43
43
  # @param [Array<Mihari::Models::Artifact>] artifacts
44
44
  #
45
45
  def call(artifacts)
46
- return if artifacts.empty?
47
-
48
46
  @artifacts = artifacts
49
47
 
48
+ return if artifacts.empty?
49
+
50
50
  client.alert payload
51
51
  end
52
52
 
@@ -61,11 +61,7 @@ module Mihari
61
61
  @normalized_api_version ||= [].tap do |out|
62
62
  # v4 does not have version prefix in path (/api/)
63
63
  # v5 has version prefix in path (/api/v1/)
64
- table = {
65
- "" => nil,
66
- "v4" => nil,
67
- "v5" => "v1"
68
- }
64
+ table = { "" => nil, "v4" => nil, "v5" => "v1" }
69
65
  out << table[api_version.to_s.downcase]
70
66
  end.first
71
67
  end
@@ -14,9 +14,7 @@ module Mihari
14
14
  # @return [Array<Mihari::Structs::GooglePublicDNS::Response>]
15
15
  #
16
16
  def call(name)
17
- %w[A AAAA CNAME TXT NS].filter_map do |resource_type|
18
- query_by_type(name, resource_type)
19
- end
17
+ %w[A AAAA CNAME TXT NS].filter_map { |resource_type| query_by_type(name, resource_type) }
20
18
  end
21
19
 
22
20
  #
@@ -31,10 +29,7 @@ module Mihari
31
29
  url = "https://dns.google/resolve"
32
30
  params = { name: name, type: resource_type }
33
31
  res = http.get(url, params: params)
34
-
35
- data = JSON.parse(res.body.to_s)
36
-
37
- Structs::GooglePublicDNS::Response.from_dynamic! data
32
+ Structs::GooglePublicDNS::Response.from_dynamic! JSON.parse(res.body.to_s)
38
33
  rescue HTTPError
39
34
  nil
40
35
  end
@@ -33,9 +33,7 @@ module Mihari
33
33
  def call(ip)
34
34
  url = "https://ipinfo.io/#{ip}/json"
35
35
  res = http.get(url)
36
- data = JSON.parse(res.body.to_s)
37
-
38
- Structs::IPInfo::Response.from_dynamic! data
36
+ Structs::IPInfo::Response.from_dynamic! JSON.parse(res.body.to_s)
39
37
  end
40
38
 
41
39
  private
@@ -16,9 +16,7 @@ module Mihari
16
16
  def call(ip)
17
17
  url = "https://internetdb.shodan.io/#{ip}"
18
18
  res = http.get(url)
19
- data = JSON.parse(res.body.to_s)
20
-
21
- Structs::Shodan::InternetDBResponse.from_dynamic! data
19
+ Structs::Shodan::InternetDBResponse.from_dynamic! JSON.parse(res.body.to_s)
22
20
  end
23
21
 
24
22
  private
@@ -52,10 +52,6 @@ module Mihari
52
52
  whois_record
53
53
  end
54
54
 
55
- def reset_cache
56
- @memo = {}
57
- end
58
-
59
55
  private
60
56
 
61
57
  #
data/lib/mihari/http.rb CHANGED
@@ -9,14 +9,13 @@ module Mihari
9
9
  #
10
10
  class BetterError < ::HTTP::Feature
11
11
  def wrap_response(response)
12
- unless response.status.success?
13
- raise StatusCodeError.new(
14
- "Unsuccessful response code returned: #{response.code}",
15
- response.code,
16
- response.body.to_s
17
- )
18
- end
19
- response
12
+ return response if response.status.success?
13
+
14
+ raise StatusCodeError.new(
15
+ "Unsuccessful response code returned: #{response.code}",
16
+ response.code,
17
+ response.body.to_s
18
+ )
20
19
  end
21
20
 
22
21
  def on_error(_request, error)
@@ -35,12 +34,15 @@ module Mihari
35
34
  #
36
35
  # @param [Integer, nil] timeout
37
36
  # @param [Hash] headers
37
+ # @param [Boolean] raise_exception
38
38
  #
39
39
  # @return [::HTTP::Client]
40
40
  #
41
- def build(headers: {}, timeout: nil)
42
- client = ::HTTP.use(:better_error).headers(headers)
43
- client.timeout(timeout) unless timeout.nil?
41
+ # @param [Object] raise_exception
42
+ def build(headers: {}, timeout: nil, raise_exception: true)
43
+ client = raise_exception ? ::HTTP.use(:better_error) : ::HTTP
44
+ client = client.headers(headers)
45
+ client = client.timeout(timeout) unless timeout.nil?
44
46
  client
45
47
  end
46
48
  end
@@ -14,10 +14,7 @@ module Mihari
14
14
  # @return [String]
15
15
  #
16
16
  def refang(indicator)
17
- return indicator.gsub("[.]", ".").gsub("(.)", ".") if indicator.is_a?(String)
18
-
19
- # for RSpec & Ruby 2.7
20
- indicator
17
+ indicator.gsub("[.]", ".").gsub("(.)", ".")
21
18
  end
22
19
  end
23
20
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Mixins
5
+ #
6
+ # Unwrap error mixins
7
+ #
8
+ module UnwrapError
9
+ def unwrap_error(err)
10
+ return err unless err.is_a?(Dry::Monads::UnwrapError)
11
+
12
+ # NOTE: UnwrapError's receiver can be either of:
13
+ # - Dry::Monads::Try::Error
14
+ # - Dry::Monads::Result::Failure
15
+ receiver = err.receiver
16
+ case receiver
17
+ when Dry::Monads::Try::Error
18
+ receiver.exception
19
+ when Dry::Monads::Failure
20
+ receiver.failure
21
+ else
22
+ err
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -30,7 +30,6 @@ module Mihari
30
30
  offset = (page - 1) * limit
31
31
 
32
32
  relation = build_relation(filter.without_pagination)
33
-
34
33
  alert_ids = relation.limit(limit).offset(offset).order(id: :desc).pluck(:id).uniq
35
34
  eager_load(:artifacts, :tags).where(id: [alert_ids]).order(id: :desc)
36
35
  end
@@ -75,8 +74,7 @@ module Mihari
75
74
  def build_relation(filter)
76
75
  artifact_ids = get_artifact_ids_by_filter(filter)
77
76
 
78
- relation = self
79
- relation = relation.includes(:artifacts, :tags)
77
+ relation = includes(:artifacts, :tags)
80
78
 
81
79
  relation = relation.where(artifacts: { id: artifact_ids }) unless artifact_ids.empty?
82
80
  relation = relation.where(tags: { name: filter.tag_name }) if filter.tag_name
@@ -78,7 +78,7 @@ module Mihari
78
78
  end
79
79
 
80
80
  #
81
- # Enrich(add) whois record
81
+ # Enrich whois record
82
82
  #
83
83
  # @param [Mihari::Enrichers::Whois] enricher
84
84
  #
@@ -89,7 +89,7 @@ module Mihari
89
89
  end
90
90
 
91
91
  #
92
- # Enrich(add) DNS records
92
+ # Enrich DNS records
93
93
  #
94
94
  # @param [Mihari::Enrichers::GooglePublicDNS] enricher
95
95
  #
@@ -100,7 +100,7 @@ module Mihari
100
100
  end
101
101
 
102
102
  #
103
- # Enrich(add) reverse DNS names
103
+ # Enrich reverse DNS names
104
104
  #
105
105
  # @param [Mihari::Enrichers::Shodan] enricher
106
106
  #
@@ -111,7 +111,7 @@ module Mihari
111
111
  end
112
112
 
113
113
  #
114
- # Enrich(add) geolocation
114
+ # Enrich geolocation
115
115
  #
116
116
  # @param [Mihari::Enrichers::IPInfo] enricher
117
117
  #
@@ -192,9 +192,7 @@ module Mihari
192
192
  #
193
193
  def enrich_by_enricher(enricher)
194
194
  methods = ENRICH_METHODS_BY_ENRICHER[enricher.class] || []
195
- methods.each do |method|
196
- send(method, enricher) if respond_to?(method)
197
- end
195
+ methods.each { |method| send(method, enricher) if respond_to?(method) }
198
196
  end
199
197
 
200
198
  private
@@ -66,8 +66,7 @@ module Mihari
66
66
  # @return [Mihari::Models::Rule]
67
67
  #
68
68
  def build_relation(filter)
69
- relation = self
70
- relation = relation.includes(alerts: :tags)
69
+ relation = includes(alerts: :tags)
71
70
 
72
71
  relation = relation.where(alerts: { tags: { name: filter.tag_name } }) if filter.tag_name
73
72
 
data/lib/mihari/rule.rb CHANGED
@@ -113,15 +113,15 @@ module Mihari
113
113
  analyzers.flat_map do |analyzer|
114
114
  # @type [Dry::Monads::Result::Success<Array<Mihari::Models::Artifact>>, Dry::Monads::Result::Failure]
115
115
  result = analyzer.result
116
-
117
- if result.failure?
118
- raise result.failure unless analyzer.ignore_error?
119
- else
116
+ case result
117
+ when Success
120
118
  artifacts = result.value!
121
119
  artifacts.map do |artifact|
122
120
  artifact.rule_id = id
123
121
  artifact
124
122
  end
123
+ else
124
+ raise result.failure unless analyzer.ignore_error?
125
125
  end
126
126
  end.compact
127
127
  end
@@ -177,8 +177,14 @@ module Mihari
177
177
  results = Parallel.map(emitters) { |emitter| emitter.result enriched_artifacts }
178
178
  results.zip(emitters).map do |result_and_emitter|
179
179
  result, emitter = result_and_emitter
180
- Mihari.logger.info "Emission by #{emitter.class} is failed: #{result.failure}" if result.failure?
181
- Mihari.logger.info "Emission by #{emitter.class} is succeeded" if result.success?
180
+
181
+ case result
182
+ when Success
183
+ Mihari.logger.info "Emission by #{emitter.class} succeed"
184
+ else
185
+ Mihari.logger.info "Emission by #{emitter.class} failed: #{result.failure}"
186
+ end
187
+
182
188
  result.value_or nil
183
189
  end.compact
184
190
  end
@@ -289,8 +295,7 @@ module Mihari
289
295
  @analyzers ||= queries.map do |query_params|
290
296
  analyzer_name = query_params[:analyzer]
291
297
  klass = get_analyzer_class(analyzer_name)
292
- klass.from_query(query_params)
293
- end.map do |analyzer|
298
+ analyzer = klass.from_query(query_params)
294
299
  analyzer.validate_configuration!
295
300
  analyzer
296
301
  end
@@ -320,8 +325,7 @@ module Mihari
320
325
  %i[emitter options].each { |key| params.delete key }
321
326
 
322
327
  klass = get_emitter_class(name)
323
- klass.new(rule: self, options: options, **params)
324
- end.map do |emitter|
328
+ emitter = klass.new(rule: self, options: options, **params)
325
329
  emitter.validate_configuration!
326
330
  emitter
327
331
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Mihari
2
4
  #
3
5
  # Base class for services
@@ -20,10 +20,8 @@ module Mihari
20
20
  # @return [Hash]
21
21
  #
22
22
  def data
23
- if Mihari::Models::Rule.exists?(path_or_id)
24
- rule = Mihari::Models::Rule.find(path_or_id)
25
- return rule.data
26
- end
23
+ result = Try { Mihari::Models::Rule.find path_or_id }.to_result
24
+ return result.value! if result.success?
27
25
 
28
26
  raise ArgumentError, "#{path_or_id} does not exist" unless Pathname(path_or_id).exist?
29
27
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Mihari
2
4
  module Structs
3
5
  module Fofa
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- VERSION = "5.7.1"
4
+ VERSION = "6.0.0"
5
5
  end
@@ -39,7 +39,7 @@ module Mihari
39
39
 
40
40
  def call(env)
41
41
  status, headers, body = API.call(env)
42
- return [status, headers, body] unless headers["X-Cascade"] == "pass"
42
+ return [status, headers, body] unless headers["x-cascade"] == "pass"
43
43
 
44
44
  # Check if the App wants us to pass the response along to others
45
45
  request_path = env["PATH_INFO"]
@@ -64,6 +64,8 @@ module Mihari
64
64
  use Middleware::ConnectionAdapter
65
65
  use Middleware::ErrorNotificationAdapter
66
66
 
67
+ use BetterErrors::Middleware if ENV["RACK_ENV"] == "development" && defined?(BetterErrors::Middleware)
68
+
67
69
  run App.new
68
70
  end.to_app
69
71
  end
@@ -77,7 +77,6 @@ module Mihari
77
77
  desc "Search alerts", {
78
78
  is_array: true,
79
79
  success: Entities::AlertsWithPagination,
80
- failure: [{ code: 404, message: "Not found", model: Entities::Message }],
81
80
  summary: "Search alerts"
82
81
  }
83
82
  params do
@@ -103,31 +102,30 @@ module Mihari
103
102
  end
104
103
 
105
104
  desc "Delete an alert", {
106
- success: Entities::Message,
107
- failure: [{ code: 404, message: "Not found", model: Entities::Message }],
105
+ success: { code: 204, model: Entities::Message },
106
+ failure: [{ code: 404, model: Entities::Message }],
108
107
  summary: "Delete an alert"
109
108
  }
110
109
  params do
111
110
  requires :id, type: Integer
112
111
  end
113
112
  delete "/:id" do
113
+ status 204
114
+
114
115
  id = params["id"].to_i
115
116
  result = AlertDestroyer.result(id)
116
- if result.success?
117
- status 204
118
- return present({ message: "" }, with: Entities::Message)
119
- end
117
+ return present({ message: "" }, with: Entities::Message) if result.success?
120
118
 
121
- failure = result.failure
122
- case failure
119
+ case result.failure
123
120
  when ActiveRecord::RecordNotFound
124
121
  error!({ message: "ID:#{id} is not found" }, 404)
125
122
  end
126
- raise failure
123
+ raise result.failure
127
124
  end
128
125
 
129
126
  desc "Create an alert", {
130
- success: Entities::Alert,
127
+ success: { code: 201, model: Entities::Alert },
128
+ failure: [{ code: 404, model: Entities::Message }],
131
129
  summary: "Create an alert"
132
130
  }
133
131
  params do
@@ -135,18 +133,16 @@ module Mihari
135
133
  requires :artifacts, type: Array, documentation: { type: String, is_array: true, param_type: "body" }
136
134
  end
137
135
  post "/" do
136
+ status 201
137
+
138
138
  result = AlertCreator.result(params)
139
- if result.success?
140
- status 201
141
- return present(result.value!, with: Entities::Alert)
142
- end
139
+ return present(result.value!, with: Entities::Alert) if result.success?
143
140
 
144
- failure = result.failure
145
- case failure
141
+ case result.failure
146
142
  when ActiveRecord::RecordNotFound
147
143
  error!({ message: "Rule:#{params["ruleId"]} is not found" }, 404)
148
144
  end
149
- raise failure
145
+ raise result.failure
150
146
  end
151
147
  end
152
148
  end
@@ -64,7 +64,7 @@ module Mihari
64
64
  namespace :artifacts do
65
65
  desc "Get an artifact", {
66
66
  success: Entities::Artifact,
67
- failure: [{ code: 404, message: "Not found", model: Entities::Message }],
67
+ failure: [{ code: 404, model: Entities::Message }],
68
68
  summary: "Get an artifact"
69
69
  }
70
70
  params do
@@ -75,60 +75,55 @@ module Mihari
75
75
  result = ArtifactGetter.result(id)
76
76
  return present(result.value!, with: Entities::Artifact) if result.success?
77
77
 
78
- failure = result.failure
79
- case failure
78
+ case result.failure
80
79
  when ActiveRecord::RecordNotFound
81
80
  error!({ message: "ID:#{id} is not found" }, 404)
82
81
  end
83
- raise failure
82
+ raise result.failure
84
83
  end
85
84
 
86
85
  desc "Enrich an artifact", {
87
- success: Entities::Message,
88
- failure: [{ code: 404, message: "Not found", model: Entities::Message }],
86
+ success: { code: 201, model: Entities::Message },
87
+ failure: [{ code: 404, model: Entities::Message }],
89
88
  summary: "Enrich an artifact"
90
89
  }
91
90
  params do
92
91
  requires :id, type: Integer
93
92
  end
94
93
  get "/:id/enrich" do
94
+ status 201
95
+
95
96
  id = params["id"].to_i
96
97
  result = ArtifactEnricher.result(id)
97
- if result.success?
98
- status 201
99
- return present({ message: "" }, with: Entities::Message)
100
- end
98
+ return present({ message: "#{id} has been enriched" }, with: Entities::Message) if result.success?
101
99
 
102
- failure = result.failure
103
- case failure
100
+ case result.failure
104
101
  when ActiveRecord::RecordNotFound
105
102
  error!({ message: "ID:#{id} is not found" }, 404)
106
103
  end
107
- raise failure
104
+ raise result.failure
108
105
  end
109
106
 
110
107
  desc "Delete an artifact", {
111
- success: Entities::Message,
112
- failure: [{ code: 404, message: "Not found", model: Entities::Message }],
108
+ success: { code: 204, model: Entities::Message },
109
+ failure: [{ code: 404, model: Entities::Message }],
113
110
  summary: "Delete an artifact"
114
111
  }
115
112
  params do
116
113
  requires :id, type: Integer
117
114
  end
118
115
  delete "/:id" do
116
+ status 204
117
+
119
118
  id = params["id"].to_i
120
119
  result = ArtifactDestroyer.result(id)
121
- if result.success?
122
- status 204
123
- return present({ message: "" }, with: Entities::Message)
124
- end
120
+ return present({ message: "" }, with: Entities::Message) if result.success?
125
121
 
126
- failure = result.failure
127
- case failure
122
+ case result.failure
128
123
  when ActiveRecord::RecordNotFound
129
124
  error!({ message: "ID:#{id} is not found" }, 404)
130
125
  end
131
- raise failure
126
+ raise result.failure
132
127
  end
133
128
  end
134
129
  end
@@ -17,7 +17,6 @@ module Mihari
17
17
  configs = (Mihari.analyzers + Mihari.emitters + Mihari.enrichers).filter_map do |klass|
18
18
  Mihari::Structs::Config.from_class(klass)
19
19
  end
20
-
21
20
  present(configs, with: Entities::Config)
22
21
  end
23
22
  end
@@ -21,7 +21,7 @@ module Mihari
21
21
  namespace :ip_addresses do
22
22
  desc "Get an IP address", {
23
23
  success: Entities::IPAddress,
24
- failure: [{ code: 404, message: "Not found", model: Entities::Message }],
24
+ failure: [{ code: 404, model: Entities::Message }],
25
25
  summary: "Get an IP address"
26
26
  }
27
27
  params do