mihari 5.6.1 → 5.6.2

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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/frontend/package-lock.json +173 -176
  3. data/frontend/package.json +9 -9
  4. data/lib/mihari/{base.rb → actor.rb} +16 -2
  5. data/lib/mihari/analyzers/base.rb +5 -10
  6. data/lib/mihari/analyzers/censys.rb +1 -1
  7. data/lib/mihari/analyzers/hunterhow.rb +1 -1
  8. data/lib/mihari/analyzers/passivetotal.rb +1 -1
  9. data/lib/mihari/analyzers/pulsedive.rb +1 -1
  10. data/lib/mihari/analyzers/securitytrails.rb +1 -1
  11. data/lib/mihari/analyzers/urlscan.rb +1 -1
  12. data/lib/mihari/analyzers/virustotal.rb +5 -5
  13. data/lib/mihari/analyzers/zoomeye.rb +3 -3
  14. data/lib/mihari/clients/crtsh.rb +2 -2
  15. data/lib/mihari/clients/passivetotal.rb +4 -4
  16. data/lib/mihari/clients/securitytrails.rb +3 -3
  17. data/lib/mihari/commands/rule.rb +2 -11
  18. data/lib/mihari/commands/search.rb +1 -1
  19. data/lib/mihari/emitters/base.rb +13 -24
  20. data/lib/mihari/emitters/database.rb +7 -9
  21. data/lib/mihari/emitters/misp.rb +14 -38
  22. data/lib/mihari/emitters/slack.rb +14 -11
  23. data/lib/mihari/emitters/the_hive.rb +16 -44
  24. data/lib/mihari/emitters/webhook.rb +31 -21
  25. data/lib/mihari/enrichers/base.rb +1 -6
  26. data/lib/mihari/enrichers/whois.rb +1 -1
  27. data/lib/mihari/models/alert.rb +75 -73
  28. data/lib/mihari/models/artifact.rb +182 -180
  29. data/lib/mihari/models/autonomous_system.rb +22 -20
  30. data/lib/mihari/models/cpe.rb +21 -19
  31. data/lib/mihari/models/dns.rb +24 -22
  32. data/lib/mihari/models/geolocation.rb +22 -20
  33. data/lib/mihari/models/port.rb +21 -19
  34. data/lib/mihari/models/reverse_dns.rb +21 -19
  35. data/lib/mihari/models/rule.rb +67 -65
  36. data/lib/mihari/models/tag.rb +5 -3
  37. data/lib/mihari/models/tagging.rb +5 -3
  38. data/lib/mihari/models/whois.rb +18 -16
  39. data/lib/mihari/rule.rb +352 -0
  40. data/lib/mihari/schemas/analyzer.rb +94 -87
  41. data/lib/mihari/schemas/emitter.rb +9 -5
  42. data/lib/mihari/schemas/enricher.rb +8 -4
  43. data/lib/mihari/schemas/mixins.rb +15 -0
  44. data/lib/mihari/schemas/rule.rb +3 -10
  45. data/lib/mihari/services/alert_builder.rb +1 -1
  46. data/lib/mihari/services/alert_proxy.rb +10 -6
  47. data/lib/mihari/services/alert_runner.rb +4 -4
  48. data/lib/mihari/services/rule_builder.rb +3 -3
  49. data/lib/mihari/services/rule_runner.rb +5 -5
  50. data/lib/mihari/structs/binaryedge.rb +1 -1
  51. data/lib/mihari/structs/censys.rb +6 -6
  52. data/lib/mihari/structs/config.rb +1 -1
  53. data/lib/mihari/structs/greynoise.rb +5 -5
  54. data/lib/mihari/structs/hunterhow.rb +3 -3
  55. data/lib/mihari/structs/onyphe.rb +5 -5
  56. data/lib/mihari/structs/shodan.rb +6 -6
  57. data/lib/mihari/structs/urlscan.rb +3 -3
  58. data/lib/mihari/structs/virustotal_intelligence.rb +3 -3
  59. data/lib/mihari/version.rb +1 -1
  60. data/lib/mihari/web/endpoints/alerts.rb +4 -4
  61. data/lib/mihari/web/endpoints/artifacts.rb +6 -6
  62. data/lib/mihari/web/endpoints/rules.rb +10 -17
  63. data/lib/mihari/web/endpoints/tags.rb +2 -2
  64. data/lib/mihari/web/public/assets/{index-9cc489e6.js → index-28d4c79d.js} +48 -48
  65. data/lib/mihari/web/public/index.html +1 -1
  66. data/lib/mihari.rb +6 -8
  67. data/mihari.gemspec +1 -2
  68. data/requirements.txt +1 -1
  69. metadata +8 -22
  70. data/lib/mihari/analyzers/rule.rb +0 -232
  71. data/lib/mihari/services/rule_proxy.rb +0 -182
@@ -19,8 +19,8 @@
19
19
  "@fortawesome/vue-fontawesome": "^3.0.3",
20
20
  "@vueuse/core": "^10.5.0",
21
21
  "@vueuse/router": "^10.5.0",
22
- "ace-builds": "^1.30.0",
23
- "axios": "^1.5.1",
22
+ "ace-builds": "^1.31.0",
23
+ "axios": "^1.6.0",
24
24
  "bulma": "^0.9.4",
25
25
  "bulma-helpers": "^0.4.3",
26
26
  "dayjs": "^1.11.10",
@@ -30,21 +30,21 @@
30
30
  "ts-dedent": "^2.2.0",
31
31
  "url-parse": "^1.5.10",
32
32
  "uuidv4": "^6.2.13",
33
- "vue": "^3.3.6",
33
+ "vue": "^3.3.7",
34
34
  "vue-concurrency": "4.0.1",
35
35
  "vue-json-pretty": "^2.2.4",
36
36
  "vue-router": "^4.2.5",
37
37
  "vue3-ace-editor": "^2.2.3"
38
38
  },
39
39
  "devDependencies": {
40
- "@redocly/cli": "1.3.0",
40
+ "@redocly/cli": "1.4.0",
41
41
  "@rushstack/eslint-patch": "^1.5.1",
42
42
  "@tsconfig/node20": "^20.1.2",
43
43
  "@types/jsdom": "^21.1.4",
44
- "@types/node": "^20.8.7",
44
+ "@types/node": "^20.8.9",
45
45
  "@types/url-parse": "^1.4.10",
46
- "@typescript-eslint/eslint-plugin": "^6.8.0",
47
- "@typescript-eslint/parser": "^6.8.0",
46
+ "@typescript-eslint/eslint-plugin": "^6.9.0",
47
+ "@typescript-eslint/parser": "^6.9.0",
48
48
  "@vitejs/plugin-vue": "^4.4.0",
49
49
  "@vue/eslint-config-prettier": "^8.0.0",
50
50
  "@vue/eslint-config-typescript": "^12.0.0",
@@ -54,7 +54,7 @@
54
54
  "eslint-config-prettier": "^9.0.0",
55
55
  "eslint-plugin-prettier": "^5.0.1",
56
56
  "eslint-plugin-simple-import-sort": "^10.0.0",
57
- "eslint-plugin-vue": "^9.17.0",
57
+ "eslint-plugin-vue": "^9.18.1",
58
58
  "husky": "^8.0.3",
59
59
  "jsdom": "^22.1.0",
60
60
  "npm-run-all": "^4.1.5",
@@ -62,6 +62,6 @@
62
62
  "typescript": "~5.2.2",
63
63
  "vite": "^4.5.0",
64
64
  "vitest": "^0.34.6",
65
- "vue-tsc": "^1.8.19"
65
+ "vue-tsc": "^1.8.22"
66
66
  }
67
67
  }
@@ -4,7 +4,12 @@ module Mihari
4
4
  #
5
5
  # Base class for Analyzer, Emitter and Enricher
6
6
  #
7
- class Base
7
+ class Actor
8
+ include Dry::Monads[:result, :try]
9
+
10
+ include Mixins::Configurable
11
+ include Mixins::Retriable
12
+
8
13
  # @return [Hash]
9
14
  attr_reader :options
10
15
 
@@ -43,6 +48,15 @@ module Mihari
43
48
  options[:timeout]
44
49
  end
45
50
 
51
+ def validate_configuration!
52
+ return if configured?
53
+
54
+ joined = configuration_keys.join(", ")
55
+ be = (configuration_keys.length > 1) ? "are" : "is"
56
+ message = "#{self.class.class_key} is not configured correctly. #{joined} #{be} missing."
57
+ raise ConfigurationError, message
58
+ end
59
+
46
60
  class << self
47
61
  #
48
62
  # @return [String]
@@ -62,7 +76,7 @@ module Mihari
62
76
  # @return [Array<String>]
63
77
  #
64
78
  def class_keys
65
- ([class_key] + [class_key_aliases]).flatten.compact
79
+ ([class_key] + [class_key_aliases]).flatten.compact.map(&:downcase)
66
80
  end
67
81
  end
68
82
  end
@@ -2,12 +2,7 @@
2
2
 
3
3
  module Mihari
4
4
  module Analyzers
5
- class Base < Mihari::Base
6
- include Dry::Monads[:result, :try]
7
-
8
- include Mixins::Configurable
9
- include Mixins::Retriable
10
-
5
+ class Base < Actor
11
6
  # @return [String]
12
7
  attr_reader :query
13
8
 
@@ -45,7 +40,7 @@ module Mihari
45
40
  Mihari.config.ignore_error
46
41
  end
47
42
 
48
- # @return [Array<String>, Array<Mihari::Artifact>]
43
+ # @return [Array<String>, Array<Mihari::Models::Artifact>]
49
44
  def artifacts
50
45
  raise NotImplementedError, "You must implement #{self.class}##{__method__}"
51
46
  end
@@ -55,14 +50,14 @@ module Mihari
55
50
  # - Convert data (string) into an artifact
56
51
  # - Reject an invalid artifact
57
52
  #
58
- # @return [Array<Mihari::Artifact>]
53
+ # @return [Array<Mihari::Models::Artifact>]
59
54
  #
60
55
  def normalized_artifacts
61
56
  retry_on_error(times: retry_times, interval: retry_interval, exponential_backoff: retry_exponential_backoff) do
62
57
  artifacts.compact.sort.map do |artifact|
63
58
  # No need to set data_type manually
64
59
  # It is set automatically in #initialize
65
- artifact = artifact.is_a?(Artifact) ? artifact : Artifact.new(data: artifact)
60
+ artifact = artifact.is_a?(Models::Artifact) ? artifact : Models::Artifact.new(data: artifact)
66
61
  artifact.source = self.class.class_key
67
62
  artifact
68
63
  end.select(&:valid?).uniq(&:data)
@@ -70,7 +65,7 @@ module Mihari
70
65
  end
71
66
 
72
67
  #
73
- # @return [Dry::Monads::Result::Success<Array<Mihari::Artifact>>, Dry::Monads::Result::Failure]
68
+ # @return [Dry::Monads::Result::Success<Array<Mihari::Models::Artifact>>, Dry::Monads::Result::Failure]
74
69
  #
75
70
  def result
76
71
  Try[StandardError] { normalized_artifacts }.to_result
@@ -24,7 +24,7 @@ module Mihari
24
24
  end
25
25
 
26
26
  #
27
- # @return [Array<Mihari::Artifact>]
27
+ # @return [Array<Mihari::Models::Artifact>]
28
28
  #
29
29
  def artifacts
30
30
  client.search_with_pagination(query, pagination_limit: pagination_limit).map do |res|
@@ -27,7 +27,7 @@ module Mihari
27
27
  end
28
28
 
29
29
  #
30
- # @return [Array<Mihari::Artifact>]
30
+ # @return [Array<Mihari::Models::Artifact>]
31
31
  #
32
32
  def artifacts
33
33
  client.search_with_pagination(
@@ -54,7 +54,7 @@ module Mihari
54
54
  #
55
55
  # @return [Array<String>, nil]
56
56
  #
57
- def key_aliases
57
+ def class_key_aliases
58
58
  ["pt"]
59
59
  end
60
60
  end
@@ -35,7 +35,7 @@ module Mihari
35
35
  nil
36
36
  else
37
37
  data = property["value"]
38
- Artifact.new(data: data, metadata: property)
38
+ Models::Artifact.new(data: data, metadata: property)
39
39
  end
40
40
  end
41
41
  end
@@ -48,7 +48,7 @@ module Mihari
48
48
  #
49
49
  # @return [Array<String>, nil]
50
50
  #
51
- def key_aliases
51
+ def class_key_aliases
52
52
  ["st"]
53
53
  end
54
54
  end
@@ -29,7 +29,7 @@ module Mihari
29
29
  end
30
30
 
31
31
  def artifacts
32
- # @type [Array<Mihari::Artifact>]
32
+ # @type [Array<Mihari::Models::Artifact>]
33
33
  artifacts = client.search_with_pagination(query, pagination_limit: pagination_limit).map(&:artifacts).flatten
34
34
 
35
35
  artifacts.select do |artifact|
@@ -43,7 +43,7 @@ module Mihari
43
43
  #
44
44
  # @return [Array<String>, nil]
45
45
  #
46
- def key_aliases
46
+ def class_key_aliases
47
47
  ["vt"]
48
48
  end
49
49
  end
@@ -66,7 +66,7 @@ module Mihari
66
66
  #
67
67
  # Domain search
68
68
  #
69
- # @return [Array<Mihari::Artifact>]
69
+ # @return [Array<Mihari::Models::Artifact>]
70
70
  #
71
71
  def domain_search
72
72
  res = client.domain_search(query)
@@ -74,14 +74,14 @@ module Mihari
74
74
  data = res["data"] || []
75
75
  data.filter_map do |item|
76
76
  data = item.dig("attributes", "ip_address")
77
- data.nil? ? nil : Artifact.new(data: data, metadata: item)
77
+ data.nil? ? nil : Models::Artifact.new(data: data, metadata: item)
78
78
  end
79
79
  end
80
80
 
81
81
  #
82
82
  # IP search
83
83
  #
84
- # @return [Array<Mihari::Artifact>]
84
+ # @return [Array<Mihari::Models::Artifact>]
85
85
  #
86
86
  def ip_search
87
87
  res = client.ip_search(query)
@@ -89,7 +89,7 @@ module Mihari
89
89
  data = res["data"] || []
90
90
  data.filter_map do |item|
91
91
  data = item.dig("attributes", "host_name")
92
- Artifact.new(data: data, metadata: item)
92
+ Models::Artifact.new(data: data, metadata: item)
93
93
  end.uniq
94
94
  end
95
95
  end
@@ -65,7 +65,7 @@ module Mihari
65
65
  #
66
66
  # @param [Hash] response
67
67
  #
68
- # @return [Array<Mihari::Artifact>]
68
+ # @return [Array<Mihari::Models::Artifact>]
69
69
  #
70
70
  def convert(res)
71
71
  matches = res["matches"] || []
@@ -73,9 +73,9 @@ module Mihari
73
73
  data = match["ip"]
74
74
 
75
75
  if data.is_a?(Array)
76
- data.map { |d| Artifact.new(data: d, metadata: match) }
76
+ data.map { |d| Models::Artifact.new(data: d, metadata: match) }
77
77
  else
78
- Artifact.new(data: data, metadata: match)
78
+ Models::Artifact.new(data: data, metadata: match)
79
79
  end
80
80
  end.flatten
81
81
  end
@@ -19,7 +19,7 @@ module Mihari
19
19
  # @param [String, nil] match "=", "ILIKE", "LIKE", "single", "any" or nil
20
20
  # @param [String, nil] exclude "expired" or nil
21
21
  #
22
- # @return [Array<Mihari::Artifact>]
22
+ # @return [Array<Mihari::Models::Artifact>]
23
23
  #
24
24
  def search(identity, match: nil, exclude: nil)
25
25
  params = { identity: identity, match: match, exclude: exclude, output: "json" }.compact
@@ -29,7 +29,7 @@ module Mihari
29
29
 
30
30
  parsed.map do |result|
31
31
  values = result["name_value"].to_s.lines.map(&:chomp)
32
- values.map { |value| Artifact.new(data: value, metadata: result) }
32
+ values.map { |value| Models::Artifact.new(data: value, metadata: result) }
33
33
  end.flatten
34
34
  end
35
35
  end
@@ -39,7 +39,7 @@ module Mihari
39
39
  #
40
40
  # @param [String] query
41
41
  #
42
- # @return [Array<Mihari::Artifact>]
42
+ # @return [Array<Mihari::Models::Artifact>]
43
43
  #
44
44
  def reverse_whois_search(query)
45
45
  params = {
@@ -50,7 +50,7 @@ module Mihari
50
50
  results = res["results"] || []
51
51
  results.map do |result|
52
52
  data = result["domain"]
53
- Artifact.new(data: data, metadata: result)
53
+ Models::Artifact.new(data: data, metadata: result)
54
54
  end.flatten
55
55
  end
56
56
 
@@ -59,7 +59,7 @@ module Mihari
59
59
  #
60
60
  # @param [String] query
61
61
  #
62
- # @return [Array<Mihari::Artifact>]
62
+ # @return [Array<Mihari::Models::Artifact>]
63
63
  #
64
64
  def ssl_search(query)
65
65
  params = { query: query }
@@ -67,7 +67,7 @@ module Mihari
67
67
  results = res["results"] || []
68
68
  results.map do |result|
69
69
  data = result["ipAddresses"]
70
- data.map { |d| Artifact.new(data: d, metadata: result) }
70
+ data.map { |d| Models::Artifact.new(data: d, metadata: result) }
71
71
  end.flatten
72
72
  end
73
73
 
@@ -36,13 +36,13 @@ module Mihari
36
36
  #
37
37
  # @param [String] query
38
38
  #
39
- # @return [Array<Mihari::Artifact>]
39
+ # @return [Array<Mihari::Models::Artifact>]
40
40
  #
41
41
  def ip_search(query)
42
42
  records = search_by_ip(query)
43
43
  records.filter_map do |record|
44
44
  data = record["hostname"]
45
- Artifact.new(data: data, metadata: record)
45
+ Models::Artifact.new(data: data, metadata: record)
46
46
  end
47
47
  end
48
48
 
@@ -57,7 +57,7 @@ module Mihari
57
57
  records = search_by_mail(query)
58
58
  records.filter_map do |record|
59
59
  data = record["hostname"]
60
- Artifact.new(data: data, metadata: record)
60
+ Models::Artifact.new(data: data, metadata: record)
61
61
  end
62
62
  end
63
63
 
@@ -17,10 +17,7 @@ module Mihari
17
17
  # @param [String] path
18
18
  #
19
19
  def validate(path)
20
- res = Dry::Monads::Try[ValidationError] do
21
- Services::RuleProxy.from_yaml File.read(path)
22
- end
23
-
20
+ res = Dry::Monads::Try[ValidationError] { Mihari::Rule.from_yaml File.read(path) }
24
21
  rule = res.value!
25
22
  puts rule.data.to_yaml
26
23
  end
@@ -42,13 +39,6 @@ module Mihari
42
39
  end
43
40
 
44
41
  no_commands do
45
- #
46
- # @return [Mihari::Services::Rule]
47
- #
48
- def rule
49
- Services::RuleProxy.from_yaml File.read(File.expand_path("../templates/rule.yml.erb", __dir__))
50
- end
51
-
52
42
  #
53
43
  # Create a new rule
54
44
  #
@@ -58,6 +48,7 @@ module Mihari
58
48
  # @return [nil]
59
49
  #
60
50
  def initialize_rule(path, files = Dry::Files.new)
51
+ rule = Mihari::Rule.from_yaml File.read(File.expand_path("../templates/rule.yml.erb", __dir__))
61
52
  files.write(path, rule.yaml)
62
53
  end
63
54
  end
@@ -32,7 +32,7 @@ module Mihari
32
32
 
33
33
  no_commands do
34
34
  #
35
- # @param [Mihari::Services::RuleProxy] rule
35
+ # @param [Mihari::Services::RuleRunner] rule
36
36
  #
37
37
  def check_diff(rule)
38
38
  force_overwrite = options["force_overwrite"] || false
@@ -2,49 +2,38 @@
2
2
 
3
3
  module Mihari
4
4
  module Emitters
5
- class Base < Mihari::Base
6
- include Dry::Monads[:result, :try]
7
-
8
- include Mixins::Configurable
9
- include Mixins::Retriable
10
-
11
- # @return [Array<Mihari::Artifact>]
12
- attr_reader :artifacts
13
-
14
- # @return [Mihari::Services::Rule]
5
+ class Base < Actor
6
+ # @return [Mihari::Rule]
15
7
  attr_reader :rule
16
8
 
17
9
  #
18
- # @param [Array<Mihari::Artifact>] artifacts
19
- # @param [Mihari::Services::RuleProxy] rule
10
+ # @param [Mihari::Rule] rule
20
11
  # @param [Hash, nil] options
21
12
  # @param [Hash] **_params
22
13
  #
23
- def initialize(artifacts:, rule:, options: nil, **_params)
14
+ def initialize(rule:, options: nil, **_params)
24
15
  super(options: options)
25
16
 
26
- @artifacts = artifacts
27
17
  @rule = rule
28
18
  end
29
19
 
30
- # @return [Boolean]
31
- def valid?
32
- raise NotImplementedError, "You must implement #{self.class}##{__method__}"
33
- end
34
-
35
- def result
20
+ #
21
+ # @param [Array<Mihari::Models::Artifact>] artifacts
22
+ #
23
+ def emit_result(artifacts)
36
24
  Try[StandardError] do
37
25
  retry_on_error(
38
26
  times: retry_times,
39
27
  interval: retry_interval,
40
28
  exponential_backoff: retry_exponential_backoff
41
- ) do
42
- emit
43
- end
29
+ ) { emit artifacts }
44
30
  end.to_result
45
31
  end
46
32
 
47
- def emit
33
+ #
34
+ # @param [Array<Mihari::Models::Artifact>] artifacts
35
+ #
36
+ def emit(artifacts)
48
37
  raise NotImplementedError, "You must implement #{self.class}##{__method__}"
49
38
  end
50
39
 
@@ -3,22 +3,20 @@
3
3
  module Mihari
4
4
  module Emitters
5
5
  class Database < Base
6
- def valid?
7
- configured?
8
- end
9
-
10
6
  #
11
7
  # Create an alert
12
8
  #
13
- # @return [Mihari::Alert, nil]
9
+ # @param [Array<Mihari::Models::Artifact>] artifacts
10
+ #
11
+ # @return [Mihari::Models::Alert, nil]
14
12
  #
15
- def emit
13
+ def emit(artifacts)
16
14
  return if artifacts.empty?
17
15
 
18
- tags = rule.tags.filter_map { |name| Tag.find_or_create_by(name: name) }.uniq
19
- taggings = tags.map { |tag| Tagging.new(tag_id: tag.id) }
16
+ tags = rule.tags.filter_map { |name| Models::Tag.find_or_create_by(name: name) }.uniq
17
+ taggings = tags.map { |tag| Models::Tagging.new(tag_id: tag.id) }
20
18
 
21
- alert = Alert.new(artifacts: artifacts, taggings: taggings, rule_id: rule.id)
19
+ alert = Models::Alert.new(artifacts: artifacts, taggings: taggings, rule_id: rule.id)
22
20
  alert.save
23
21
  alert
24
22
  end
@@ -9,50 +9,39 @@ module Mihari
9
9
  # @return [String, nil]
10
10
  attr_reader :api_key
11
11
 
12
- # @return [Array<Mihari::Artifact>]
13
- attr_reader :artifacts
14
-
15
12
  # @return [Mihari::Services::Rule]
16
13
  attr_reader :rule
17
14
 
15
+ # @return [Array<Mihari::Models::Artifact>]
16
+ attr_accessor :artifacts
17
+
18
18
  #
19
- # @param [Array<Mihari::Artifact>] artifacts
20
19
  # @param [Mihari::Services::Rule] rule
21
20
  # @param [Hash, nil] options
22
21
  # @param [Hash] **params
23
22
  #
24
- def initialize(artifacts:, rule:, options: nil, **params)
25
- super(artifacts: artifacts, rule: rule, options: options)
23
+ def initialize(rule:, options: nil, **params)
24
+ super(rule: rule, options: options)
26
25
 
27
26
  @url = params[:url] || Mihari.config.misp_url
28
27
  @api_key = params[:api_key] || Mihari.config.misp_api_key
28
+
29
+ @artifacts = []
29
30
  end
30
31
 
32
+ #
31
33
  # @return [Boolean]
32
- def valid?
33
- unless url? && api_key?
34
- Mihari.logger.info("MISP URL is not set") unless url?
35
- Mihari.logger.info("MISP API key is not set") unless api_key?
36
- return false
37
- end
38
-
39
- unless ping?
40
- Mihari.logger.info("MISP URL (#{url}) is not reachable")
41
- return false
42
- end
43
-
44
- true
34
+ #
35
+ def configured?
36
+ api_key? && url?
45
37
  end
46
38
 
47
39
  #
48
40
  # Create a MISP event
49
41
  #
50
- # @param [Arra<Mihari::Artifact>] artifacts
51
- # @param [Mihari::Services::Rule] rule
52
- #
53
- # @return [::MISP::Event]
42
+ # @param [Array<Mihari::Models::Artifact>] artifacts
54
43
  #
55
- def emit
44
+ def emit(artifacts)
56
45
  return if artifacts.empty?
57
46
 
58
47
  client.create_event({
@@ -77,7 +66,7 @@ module Mihari
77
66
  #
78
67
  # Build a MISP attribute
79
68
  #
80
- # @param [Mihari::Artifact] artifact
69
+ # @param [Mihari::Models::Artifact] artifact
81
70
  #
82
71
  # @return [Hash]
83
72
  #
@@ -143,19 +132,6 @@ module Mihari
143
132
  def api_key?
144
133
  !api_key.nil? && !api_key.empty?
145
134
  end
146
-
147
- #
148
- # Check whether a URL is reachable or not
149
- #
150
- # @return [Boolean]
151
- #
152
- def ping?
153
- base_url = url.end_with?("/") ? url[0..-2] : url
154
- login_url = "#{base_url}/users/login"
155
-
156
- http = Net::Ping::HTTP.new(login_url)
157
- http.ping?
158
- end
159
135
  end
160
136
  end
161
137
  end
@@ -131,18 +131,22 @@ module Mihari
131
131
  # @return [String]
132
132
  attr_reader :username
133
133
 
134
+ # @return [Array<Mihari::Models::Artifact>]
135
+ attr_accessor :artifacts
136
+
134
137
  #
135
- # @param [Array<Mihari::Artifact>] artifacts
136
138
  # @param [Mihari::Services::Rule] rule
137
139
  # @param [Hash, nil] options
138
140
  # @param [Hash] **params
139
141
  #
140
- def initialize(artifacts:, rule:, options: nil, **params)
141
- super(artifacts: artifacts, rule: rule, options: options)
142
+ def initialize(rule:, options: nil, **params)
143
+ super(rule: rule, options: options)
142
144
 
143
145
  @webhook_url = params[:webhook_url] || Mihari.config.slack_webhook_url
144
146
  @channel = params[:channel] || Mihari.config.slack_channel || DEFAULT_CHANNEL
145
147
  @username = DEFAULT_USERNAME
148
+
149
+ @artifacts = []
146
150
  end
147
151
 
148
152
  #
@@ -154,12 +158,10 @@ module Mihari
154
158
  !webhook_url.nil?
155
159
  end
156
160
 
157
- #
158
- # Check webhook URL is set. Alias of #webhook_url?
159
161
  #
160
162
  # @return [Boolean]
161
163
  #
162
- def valid?
164
+ def configured?
163
165
  webhook_url?
164
166
  end
165
167
 
@@ -211,19 +213,20 @@ module Mihari
211
213
  ].join("\n")
212
214
  end
213
215
 
214
- def emit
216
+ #
217
+ # @param [Array<Mihari::Models::Artifact>] artifacts
218
+ #
219
+ def emit(artifacts)
215
220
  return if artifacts.empty?
216
221
 
222
+ @artifacts = artifacts
223
+
217
224
  notifier.post(text: text, attachments: attachments, mrkdwn: true)
218
225
  end
219
226
 
220
227
  def configuration_keys
221
228
  %w[slack_webhook_url slack_channel]
222
229
  end
223
-
224
- def configured?
225
- valid?
226
- end
227
230
  end
228
231
  end
229
232
  end