mihari 4.5.1 → 4.6.0

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mihari/analyzers/rule.rb +6 -3
  3. data/lib/mihari/emitters/the_hive.rb +69 -10
  4. data/lib/mihari/emitters/webhook.rb +1 -1
  5. data/lib/mihari/schemas/emitter.rb +1 -0
  6. data/lib/mihari/structs/rule.rb +3 -0
  7. data/lib/mihari/version.rb +1 -1
  8. data/lib/mihari/web/endpoints/rules.rb +2 -1
  9. data/lib/mihari/web/public/index.html +1 -1
  10. data/lib/mihari/web/public/redoc-static.html +317 -314
  11. data/lib/mihari/web/public/static/css/{chunk-vendors.da2a7bfc.css → chunk-vendors.06251949.css} +2 -2
  12. data/lib/mihari/web/public/static/fonts/{fa-brands-400.f7223235.ttf → fa-brands-400.7fa789ab.ttf} +0 -0
  13. data/lib/mihari/web/public/static/fonts/fa-brands-400.859fc388.woff2 +0 -0
  14. data/lib/mihari/web/public/static/fonts/fa-regular-400.2ffd018f.woff2 +0 -0
  15. data/lib/mihari/web/public/static/fonts/{fa-regular-400.a7fde52b.ttf → fa-regular-400.da02cb7e.ttf} +0 -0
  16. data/lib/mihari/web/public/static/fonts/{fa-solid-900.5b03221c.ttf → fa-solid-900.3a463ec3.ttf} +0 -0
  17. data/lib/mihari/web/public/static/fonts/fa-solid-900.40ddefd7.woff2 +0 -0
  18. data/lib/mihari/web/public/static/fonts/{fa-v4compatibility.42932bea.ttf → fa-v4compatibility.924588dc.ttf} +0 -0
  19. data/lib/mihari/web/public/static/js/app-legacy.9d5c9c3d.js +2 -0
  20. data/lib/mihari/web/public/static/js/app-legacy.9d5c9c3d.js.map +1 -0
  21. data/lib/mihari/web/public/static/js/app.823b5af7.js +2 -0
  22. data/lib/mihari/web/public/static/js/app.823b5af7.js.map +1 -0
  23. data/lib/mihari/web/public/static/js/chunk-vendors-legacy.b110c129.js +25 -0
  24. data/lib/mihari/web/public/static/js/chunk-vendors-legacy.b110c129.js.map +1 -0
  25. data/lib/mihari/web/public/static/js/chunk-vendors.dde2116c.js +31 -0
  26. data/lib/mihari/web/public/static/js/chunk-vendors.dde2116c.js.map +1 -0
  27. data/lib/mihari.rb +49 -28
  28. data/mihari.gemspec +7 -8
  29. data/sig/lib/mihari/emitters/the_hive.rbs +4 -0
  30. data/sig/lib/mihari.rbs +1 -0
  31. metadata +32 -46
  32. data/lib/mihari/web/public/static/fonts/fa-brands-400.edf40f86.woff2 +0 -0
  33. data/lib/mihari/web/public/static/fonts/fa-regular-400.3665ebc7.woff2 +0 -0
  34. data/lib/mihari/web/public/static/fonts/fa-solid-900.0d2abd43.woff2 +0 -0
  35. data/lib/mihari/web/public/static/js/app-legacy.c3595dce.js +0 -2
  36. data/lib/mihari/web/public/static/js/app-legacy.c3595dce.js.map +0 -1
  37. data/lib/mihari/web/public/static/js/app.afd5025f.js +0 -2
  38. data/lib/mihari/web/public/static/js/app.afd5025f.js.map +0 -1
  39. data/lib/mihari/web/public/static/js/chunk-vendors-legacy.d6b76c57.js +0 -25
  40. data/lib/mihari/web/public/static/js/chunk-vendors-legacy.d6b76c57.js.map +0 -1
  41. data/lib/mihari/web/public/static/js/chunk-vendors.3bdbaffb.js +0 -31
  42. data/lib/mihari/web/public/static/js/chunk-vendors.3bdbaffb.js.map +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd4057ff69b6e8ee676c7ebf7e672b6830d26a02e22ebe372d2786f5220ae8d3
4
- data.tar.gz: 202c7bce234c823fb10fe40fc1f7af2c25d676f587871d0a49740fd8f3af4325
3
+ metadata.gz: 1f340898bd140d76041cde8c5cb266bcb379f056bac511fcd9de9a4dd20fc299
4
+ data.tar.gz: fb96310ecb6efb1dd5059feea692a8128bdff3610579473134653979c2f0512c
5
5
  SHA512:
6
- metadata.gz: ed3c42b58a305f20e7d981a1ae5e19d6efe493d7252645cf54f78c16fe38607305497e983f80d1d04ab8964f0166f19ace1ba62bece5ecdeadb0b6041d4be49f
7
- data.tar.gz: 12966b0cc1143bcff8e9a44dd5904c7fa70c234f26613df35e5be162c5e18805e15adb1a8fd1ddd8c1ad84d221b528d411daa29b764e67eed4357a86f6bf0cc7
6
+ metadata.gz: 8d9758d027fc056f52be261fb2d7c6fa81dc402d4f47c01a8e49c93e1bc084a501af74c0e51c73ac2967c7795529130f1c34801661f1a9935075e197eaf446b0
7
+ data.tar.gz: e48d29aa3756a260cc273f9b05e65aa28e6e9e67f377fcc9c4ff722931f7789f363478c9a33470aea41a1bd72a9c9e73c05b76583d52bdb80096c2fdaf627b54
@@ -127,9 +127,12 @@ module Mihari
127
127
  # @return [Boolean]
128
128
  #
129
129
  def disallowed_data_value?(value)
130
- normalized_disallowed_data_values.any? do |disallowed_data_value|
131
- return value == disallowed_data_value if disallowed_data_value.is_a?(String)
132
- return disallowed_data_value.match?(value) if disallowed_data_value.is_a?(Regexp)
130
+ return true if normalized_disallowed_data_values.include?(value)
131
+
132
+ normalized_disallowed_data_values.select do |disallowed_data_value|
133
+ disallowed_data_value.is_a?(Regexp)
134
+ end.any? do |disallowed_data_value|
135
+ disallowed_data_value.match?(value)
133
136
  end
134
137
  end
135
138
 
@@ -11,11 +11,15 @@ module Mihari
11
11
  # @return [String, nil]
12
12
  attr_reader :api_key
13
13
 
14
+ # @return [String, nil]
15
+ attr_reader :api_version
16
+
14
17
  def initialize(*args, **kwargs)
15
18
  super(*args, **kwargs)
16
19
 
17
20
  @api_endpoint = kwargs[:api_endpoint] || Mihari.config.thehive_api_endpoint
18
21
  @api_key = kwargs[:api_key] || Mihari.config.thehive_api_key
22
+ @api_version = kwargs[:api_version] || Mihari.config.thehive_api_version
19
23
  end
20
24
 
21
25
  # @return [Boolean]
@@ -26,14 +30,28 @@ module Mihari
26
30
  def emit(title:, description:, artifacts:, tags: [], **_options)
27
31
  return if artifacts.empty?
28
32
 
29
- api.alert.create(
30
- title: title,
31
- description: description,
32
- artifacts: artifacts.map { |artifact| { data: artifact.data, data_type: artifact.data_type, message: description } },
33
- tags: tags,
34
- type: "external",
35
- source: "mihari"
36
- )
33
+ payload = payload(title: title, description: description, artifacts: artifacts, tags: tags)
34
+ api.alert.create(**payload)
35
+ end
36
+
37
+ #
38
+ # Normalize API version for API client
39
+ #
40
+ # @param [String] version
41
+ #
42
+ # @return [String, nil]
43
+ #
44
+ def normalized_api_version
45
+ @normalized_api_version ||= [].tap do |out|
46
+ # v4 does not have version prefix in path (/api/)
47
+ # v5 has version prefix in path (/api/v1/)
48
+ table = {
49
+ "" => nil,
50
+ "v4" => nil,
51
+ "v5" => "v1"
52
+ }
53
+ out << table[api_version.to_s.downcase]
54
+ end.first
37
55
  end
38
56
 
39
57
  private
@@ -43,7 +61,7 @@ module Mihari
43
61
  end
44
62
 
45
63
  def api
46
- @api ||= Hachi::API.new(api_endpoint: api_endpoint, api_key: api_key)
64
+ @api ||= Hachi::API.new(api_endpoint: api_endpoint, api_key: api_key, api_version: normalized_api_version)
47
65
  end
48
66
 
49
67
  #
@@ -64,6 +82,35 @@ module Mihari
64
82
  !api_key.nil?
65
83
  end
66
84
 
85
+ def payload(title:, description:, artifacts:, tags: [])
86
+ return v4_payload(title: title, description: description, artifacts: artifacts, tags: tags) if normalized_api_version.nil?
87
+
88
+ v5_payload(title: title, description: description, artifacts: artifacts, tags: tags)
89
+ end
90
+
91
+ def v4_payload(title:, description:, artifacts:, tags: [])
92
+ {
93
+ title: title,
94
+ description: description,
95
+ artifacts: artifacts.map { |artifact| { data: artifact.data, data_type: artifact.data_type, message: description } },
96
+ tags: tags,
97
+ type: "external",
98
+ source: "mihari"
99
+ }
100
+ end
101
+
102
+ def v5_payload(title:, description:, artifacts:, tags: [])
103
+ {
104
+ title: title,
105
+ description: description,
106
+ observables: artifacts.map { |artifact| { data: artifact.data, data_type: artifact.data_type, message: description } },
107
+ tags: tags,
108
+ type: "external",
109
+ source: "mihari",
110
+ source_ref: "1"
111
+ }
112
+ end
113
+
67
114
  #
68
115
  # Check whether an API endpoint is reachable or not
69
116
  #
@@ -71,9 +118,21 @@ module Mihari
71
118
  #
72
119
  def ping?
73
120
  base_url = api_endpoint.end_with?("/") ? api_endpoint[0..-2] : api_endpoint
74
- url = "#{base_url}/index.html"
121
+
122
+ if normalized_api_version.nil?
123
+ # for v4
124
+ base_url = api_endpoint.end_with?("/") ? api_endpoint[0..-2] : api_endpoint
125
+ url = "#{base_url}/index.html"
126
+ else
127
+ # for v5
128
+ url = "#{base_url}/api/v1/status/public"
129
+ end
75
130
 
76
131
  http = Net::Ping::HTTP.new(url)
132
+
133
+ # use GET for v5
134
+ http.get_request = true if normalized_api_version
135
+
77
136
  http.ping?
78
137
  end
79
138
  end
@@ -11,7 +11,7 @@ module Mihari
11
11
  def emit(title:, description:, artifacts:, source:, tags:)
12
12
  return if artifacts.empty?
13
13
 
14
- headers = { 'content-type': "application/x-www-form-urlencoded" }
14
+ headers = { "content-type": "application/x-www-form-urlencoded" }
15
15
  headers["content-type"] = "application/json" if use_json_body?
16
16
 
17
17
  emitter = Emitters::HTTP.new(uri: Mihari.config.webhook_url)
@@ -16,6 +16,7 @@ module Mihari
16
16
  required(:emitter).value(Types::String.enum("the_hive"))
17
17
  optional(:api_endpoint).value(:string)
18
18
  optional(:api_key).value(:string)
19
+ optional(:api_version).value(Types::String.enum("v4", "v5")).default("v4")
19
20
  end
20
21
 
21
22
  Slack = Dry::Schema.Params do
@@ -36,6 +36,9 @@ module Mihari
36
36
  # @return [Array, nil]
37
37
  attr_reader :errors
38
38
 
39
+ # @return [String]
40
+ attr_writer :id
41
+
39
42
  def initialize(data, yaml)
40
43
  @data = data.deep_symbolize_keys
41
44
  @yaml = yaml
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- VERSION = "4.5.1"
4
+ VERSION = "4.6.0"
5
5
  end
@@ -145,6 +145,7 @@ module Mihari
145
145
  end
146
146
 
147
147
  rule = Structs::Rule::Rule.from_yaml(yaml)
148
+ rule.id = id
148
149
 
149
150
  begin
150
151
  rule.validate!
@@ -159,7 +160,7 @@ module Mihari
159
160
  model = rule.to_model
160
161
  model.save
161
162
  rescue ActiveRecord::RecordNotUnique
162
- error!({ message: "ID:#{rule.id} is already registered" }, 400)
163
+ error!({ message: "ID:#{model.id} is already registered" }, 400)
163
164
  end
164
165
 
165
166
  status 201
@@ -1 +1 @@
1
- <!doctype html><html lang="en"><head><meta charset="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="viewport" content="width=device-width,initial-scale=1"/><link rel="icon" href="/static/favicon.ico"/><title>Mihari</title><script defer="defer" type="module" src="/static/js/chunk-vendors.3bdbaffb.js"></script><script defer="defer" type="module" src="/static/js/app.afd5025f.js"></script><link href="/static/css/chunk-vendors.da2a7bfc.css" rel="stylesheet"><link href="/static/css/app.2a5d3d21.css" rel="stylesheet"><script defer="defer" src="/static/js/chunk-vendors-legacy.d6b76c57.js" nomodule></script><script defer="defer" src="/static/js/app-legacy.c3595dce.js" nomodule></script></head><body><noscript><strong>We're sorry but Mihari doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
1
+ <!doctype html><html lang="en"><head><meta charset="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="viewport" content="width=device-width,initial-scale=1"/><link rel="icon" href="/static/favicon.ico"/><title>Mihari</title><script defer="defer" type="module" src="/static/js/chunk-vendors.dde2116c.js"></script><script defer="defer" type="module" src="/static/js/app.823b5af7.js"></script><link href="/static/css/chunk-vendors.06251949.css" rel="stylesheet"><link href="/static/css/app.2a5d3d21.css" rel="stylesheet"><script defer="defer" src="/static/js/chunk-vendors-legacy.b110c129.js" nomodule></script><script defer="defer" src="/static/js/app-legacy.9d5c9c3d.js" nomodule></script></head><body><noscript><strong>We're sorry but Mihari doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>