mihari 3.6.0 → 3.7.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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +3 -0
  3. data/Steepfile +32 -0
  4. data/lib/mihari/analyzers/base.rb +7 -22
  5. data/lib/mihari/analyzers/binaryedge.rb +13 -0
  6. data/lib/mihari/analyzers/censys.rb +5 -0
  7. data/lib/mihari/analyzers/circl.rb +15 -0
  8. data/lib/mihari/analyzers/crtsh.rb +5 -0
  9. data/lib/mihari/analyzers/dnpedia.rb +5 -0
  10. data/lib/mihari/analyzers/dnstwister.rb +17 -0
  11. data/lib/mihari/analyzers/onyphe.rb +20 -4
  12. data/lib/mihari/analyzers/otx.rb +20 -0
  13. data/lib/mihari/analyzers/passivetotal.rb +25 -0
  14. data/lib/mihari/analyzers/pulsedive.rb +10 -0
  15. data/lib/mihari/analyzers/rule.rb +18 -0
  16. data/lib/mihari/analyzers/securitytrails.rb +25 -0
  17. data/lib/mihari/analyzers/shodan.rb +13 -0
  18. data/lib/mihari/analyzers/spyse.rb +20 -0
  19. data/lib/mihari/analyzers/urlscan.rb +10 -0
  20. data/lib/mihari/analyzers/virustotal.rb +20 -0
  21. data/lib/mihari/analyzers/zoomeye.rb +38 -0
  22. data/lib/mihari/database.rb +13 -0
  23. data/lib/mihari/emitters/base.rb +1 -1
  24. data/lib/mihari/emitters/misp.rb +38 -5
  25. data/lib/mihari/emitters/slack.rb +20 -2
  26. data/lib/mihari/emitters/the_hive.rb +16 -3
  27. data/lib/mihari/emitters/webhook.rb +18 -3
  28. data/lib/mihari/enrichers/base.rb +18 -0
  29. data/lib/mihari/enrichers/ipinfo.rb +49 -0
  30. data/lib/mihari/mixins/autonomous_system.rb +19 -0
  31. data/lib/mihari/mixins/disallowed_data_value.rb +1 -1
  32. data/lib/mihari/models/artifact.rb +42 -3
  33. data/lib/mihari/models/autonomous_system.rb +18 -1
  34. data/lib/mihari/models/dns.rb +2 -0
  35. data/lib/mihari/models/geolocation.rb +21 -1
  36. data/lib/mihari/models/reverse_dns.rb +2 -0
  37. data/lib/mihari/models/whois.rb +1 -1
  38. data/lib/mihari/status.rb +7 -2
  39. data/lib/mihari/structs/ipinfo.rb +39 -0
  40. data/lib/mihari/structs/onyphe.rb +2 -2
  41. data/lib/mihari/type_checker.rb +9 -9
  42. data/lib/mihari/version.rb +1 -1
  43. data/lib/mihari/web/controllers/artifacts_controller.rb +27 -1
  44. data/lib/mihari/web/controllers/ip_address_controller.rb +4 -19
  45. data/lib/mihari/web/public/index.html +1 -1
  46. data/lib/mihari/web/public/redoc-static.html +7 -6
  47. data/lib/mihari/web/public/static/js/app.06d5cf1c.js +36 -0
  48. data/lib/mihari/web/public/static/js/app.06d5cf1c.js.map +1 -0
  49. data/lib/mihari.rb +40 -26
  50. data/mihari.gemspec +7 -4
  51. data/sig/lib/mihari/analyzers/base.rbs +90 -0
  52. data/sig/lib/mihari/analyzers/basic.rbs +17 -0
  53. data/sig/lib/mihari/analyzers/binaryedge.rbs +25 -0
  54. data/sig/lib/mihari/analyzers/censys.rbs +38 -0
  55. data/sig/lib/mihari/analyzers/circl.rbs +29 -0
  56. data/sig/lib/mihari/analyzers/crtsh.rbs +19 -0
  57. data/sig/lib/mihari/analyzers/dnpedia.rbs +18 -0
  58. data/sig/lib/mihari/analyzers/dnstwister.rbs +27 -0
  59. data/sig/lib/mihari/analyzers/onyphe.rbs +33 -0
  60. data/sig/lib/mihari/analyzers/otx.rbs +33 -0
  61. data/sig/lib/mihari/analyzers/passivetotal.rbs +33 -0
  62. data/sig/lib/mihari/analyzers/pulsedive.rbs +27 -0
  63. data/sig/lib/mihari/analyzers/rule.rbs +68 -0
  64. data/sig/lib/mihari/analyzers/securitytrails.rbs +33 -0
  65. data/sig/lib/mihari/analyzers/shodan.rbs +33 -0
  66. data/sig/lib/mihari/analyzers/spyse.rbs +29 -0
  67. data/sig/lib/mihari/analyzers/urlscan.rbs +28 -0
  68. data/sig/lib/mihari/analyzers/virustotal.rbs +31 -0
  69. data/sig/lib/mihari/analyzers/zoomeye.rbs +33 -0
  70. data/sig/lib/mihari/cli/analyzer.rbs +39 -0
  71. data/sig/lib/mihari/cli/base.rbs +11 -0
  72. data/sig/lib/mihari/cli/init.rbs +7 -0
  73. data/sig/lib/mihari/cli/main.rbs +9 -0
  74. data/sig/lib/mihari/cli/mixins/utils.rbs +50 -0
  75. data/sig/lib/mihari/cli/validator.rbs +7 -0
  76. data/sig/lib/mihari/commands/binaryedge.rbs +7 -0
  77. data/sig/lib/mihari/commands/censys.rbs +7 -0
  78. data/sig/lib/mihari/commands/circl.rbs +7 -0
  79. data/sig/lib/mihari/commands/crtsh.rbs +7 -0
  80. data/sig/lib/mihari/commands/dnpedia.rbs +7 -0
  81. data/sig/lib/mihari/commands/dnstwister.rbs +7 -0
  82. data/sig/lib/mihari/commands/init.rbs +11 -0
  83. data/sig/lib/mihari/commands/json.rbs +7 -0
  84. data/sig/lib/mihari/commands/onyphe.rbs +7 -0
  85. data/sig/lib/mihari/commands/otx.rbs +7 -0
  86. data/sig/lib/mihari/commands/passivetotal.rbs +7 -0
  87. data/sig/lib/mihari/commands/pulsedive.rbs +7 -0
  88. data/sig/lib/mihari/commands/search.rbs +35 -0
  89. data/sig/lib/mihari/commands/securitytrails.rbs +7 -0
  90. data/sig/lib/mihari/commands/shodan.rbs +7 -0
  91. data/sig/lib/mihari/commands/spyse.rbs +7 -0
  92. data/sig/lib/mihari/commands/urlscan.rbs +7 -0
  93. data/sig/lib/mihari/commands/validator.rbs +11 -0
  94. data/sig/lib/mihari/commands/virustotal.rbs +7 -0
  95. data/sig/lib/mihari/commands/web.rbs +7 -0
  96. data/sig/lib/mihari/commands/zoomeye.rbs +7 -0
  97. data/sig/lib/mihari/constants.rbs +3 -0
  98. data/sig/lib/mihari/database.rbs +25 -0
  99. data/sig/lib/mihari/emitters/base.rbs +18 -0
  100. data/sig/lib/mihari/emitters/database.rbs +9 -0
  101. data/sig/lib/mihari/emitters/misp.rbs +28 -0
  102. data/sig/lib/mihari/emitters/slack.rbs +58 -0
  103. data/sig/lib/mihari/emitters/stdout.rbs +9 -0
  104. data/sig/lib/mihari/emitters/the_hive.rbs +24 -0
  105. data/sig/lib/mihari/emitters/webhook.rbs +20 -0
  106. data/sig/lib/mihari/enrichers/base.rbs +12 -0
  107. data/sig/lib/mihari/enrichers/ipinfo.rbs +16 -0
  108. data/sig/lib/mihari/errors.rbs +10 -0
  109. data/sig/lib/mihari/mixins/autonomous_system.rbs +14 -0
  110. data/sig/lib/mihari/mixins/configurable.rbs +26 -0
  111. data/sig/lib/mihari/mixins/configuration.rbs +45 -0
  112. data/sig/lib/mihari/mixins/disallowed_data_value.rbs +25 -0
  113. data/sig/lib/mihari/mixins/hash.rbs +14 -0
  114. data/sig/lib/mihari/mixins/refang.rbs +14 -0
  115. data/sig/lib/mihari/mixins/retriable.rbs +15 -0
  116. data/sig/lib/mihari/mixins/rule.rbs +41 -0
  117. data/sig/lib/mihari/models/alert.rbs +46 -0
  118. data/sig/lib/mihari/models/artifact.rbs +65 -0
  119. data/sig/lib/mihari/models/autonomous_system.rbs +14 -0
  120. data/sig/lib/mihari/models/dns.rbs +19 -0
  121. data/sig/lib/mihari/models/geolocation.rbs +15 -0
  122. data/sig/lib/mihari/models/reverse_dns.rbs +14 -0
  123. data/sig/lib/mihari/models/tag.rbs +5 -0
  124. data/sig/lib/mihari/models/tagging.rbs +4 -0
  125. data/sig/lib/mihari/models/whois.rbs +66 -0
  126. data/sig/lib/mihari/notifiers/base.rbs +18 -0
  127. data/sig/lib/mihari/notifiers/exception_notifier.rbs +75 -0
  128. data/sig/lib/mihari/notifiers/slack.rbs +50 -0
  129. data/sig/lib/mihari/status.rbs +25 -0
  130. data/sig/lib/mihari/structs/censys.rbs +50 -0
  131. data/sig/lib/mihari/structs/ipinfo.rbs +17 -0
  132. data/sig/lib/mihari/structs/onyphe.rbs +25 -0
  133. data/sig/lib/mihari/structs/shodan.rbs +28 -0
  134. data/sig/lib/mihari/type_checker.rbs +48 -0
  135. data/sig/lib/mihari/types.rbs +17 -0
  136. data/sig/lib/mihari/version.rbs +3 -0
  137. data/sig/lib/mihari/web/app.rbs +5 -0
  138. data/sig/lib/mihari.rbs +59 -0
  139. metadata +148 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c9c1cbdf0570c25e2d89d7f6fd402b64991dfaebc75cf3cf5422a56504287ae9
4
- data.tar.gz: d5b7a0db7b49f245e3c949135011fb674e28a9d3c251e165f827e8f3d90673b1
3
+ metadata.gz: e4ce5b3ce24278b8141bf2078dce45d572846a4838a0dc00c34e695201c36d77
4
+ data.tar.gz: '0992223bccd1d9732e0cc9cb6063f822efef8f0db34a27a45ad829efc930a60f'
5
5
  SHA512:
6
- metadata.gz: e76a216dedbc1aec17748c37a1b874c2c825fed6f7716ef356a48ddf2861584da299c384737e588a48b67165874f495192bb42a4c20c2f29f4620f8b559d1a83
7
- data.tar.gz: 2f3e380b252ba238594ccacd2df8e362a62b9685aafeff34d6506e7301184cf5b38c4244db9498842f4aee9df109d7c43a9ad99cecc3b63616d333a7f5093333
6
+ metadata.gz: 26aa441c9e982df2a84e5d3f8cc5bc261b49b9dae618fc73384a116927481125b4a87dac8317a6fb319caf5523398020ebcf8973eee6229d128a377f1054c4db
7
+ data.tar.gz: bfee6864b187018a6a9f9b5f4c68cfdea496b36ebad0b796425642ed9b80b2f7c70c4d74ef16964838e16b2985acddb11d4b0c0a6c4cca73dfb93d7a1ff83875
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "vendor/rbs/gem_rbs_collection"]
2
+ path = vendor/rbs/gem_rbs_collection
3
+ url = https://github.com/ruby/gem_rbs_collection.git
data/Steepfile ADDED
@@ -0,0 +1,32 @@
1
+ target :lib do
2
+ signature "sig"
3
+ check "lib"
4
+
5
+ repo_path "vendor/rbs/gem_rbs_collection/gems"
6
+
7
+ library "date"
8
+ library "json"
9
+ library "logger"
10
+ library "monitor"
11
+ library "mutex_m"
12
+ library "pathname"
13
+ library "securerandom"
14
+ library "singleton"
15
+ library "time"
16
+ library "tsort"
17
+ library "uri"
18
+ library "resolv"
19
+ library "timeout"
20
+ library "socket"
21
+
22
+ library "rack"
23
+
24
+ library "actionpack"
25
+ library "actionview"
26
+ library "activejob"
27
+ library "activemodel"
28
+ library "activerecord"
29
+ library "activesupport"
30
+ library "parallel"
31
+ library "railties"
32
+ end
@@ -8,6 +8,7 @@ module Mihari
8
8
  class Base
9
9
  extend Dry::Initializer
10
10
 
11
+ include Mixins::AutonomousSystem
11
12
  include Mixins::Configurable
12
13
  include Mixins::Retriable
13
14
 
@@ -27,7 +28,7 @@ module Mihari
27
28
 
28
29
  # @return [String]
29
30
  def title
30
- self.class.to_s.split("::").last
31
+ self.class.to_s.split("::").last.to_s
31
32
  end
32
33
 
33
34
  # @return [String]
@@ -37,7 +38,7 @@ module Mihari
37
38
 
38
39
  # @return [String]
39
40
  def source
40
- self.class.to_s.split("::").last
41
+ self.class.to_s.split("::").last.to_s
41
42
  end
42
43
 
43
44
  # @return [Array<String>]
@@ -111,9 +112,7 @@ module Mihari
111
112
  #
112
113
  def enriched_artifacts
113
114
  @enriched_artifacts ||= unique_artifacts.map do |artifact|
114
- artifact.enrich_whois
115
- artifact.enrich_dns
116
- artifact.enrich_reverse_dns
115
+ artifact.enrich_all
117
116
  artifact
118
117
  end
119
118
  end
@@ -125,9 +124,9 @@ module Mihari
125
124
  #
126
125
  def set_enriched_artifacts
127
126
  retry_on_error { enriched_artifacts }
128
- rescue ArgumentError => _e
127
+ rescue ArgumentError => e
129
128
  klass = self.class.to_s.split("::").last.to_s
130
- raise Error, "Please configure #{klass} API settings properly"
129
+ raise Error, "Please configure #{klass} settings properly. (#{e})"
131
130
  end
132
131
 
133
132
  #
@@ -139,21 +138,7 @@ module Mihari
139
138
  @valid_emitters ||= Mihari.emitters.filter_map do |klass|
140
139
  emitter = klass.new
141
140
  emitter.valid? ? emitter : nil
142
- end
143
- end
144
-
145
- #
146
- # Normalize ASN value
147
- #
148
- # @param [String, Integer] asn
149
- #
150
- # @return [Integer]
151
- #
152
- def normalize_asn(asn)
153
- return asn if asn.is_a?(Integer)
154
- return asn.to_i unless asn.start_with?("AS")
155
-
156
- asn.delete_prefix("AS").to_i
141
+ end.compact
157
142
  end
158
143
  end
159
144
  end
@@ -26,6 +26,14 @@ module Mihari
26
26
 
27
27
  PAGE_SIZE = 20
28
28
 
29
+ #
30
+ # Search with pagination
31
+ #
32
+ # @param [String] query
33
+ # @param [Integer] page
34
+ #
35
+ # @return [Hash]
36
+ #
29
37
  def search_with_page(query, page: 1)
30
38
  api.host.search(query, page: page)
31
39
  rescue ::BinaryEdge::Error => e
@@ -34,6 +42,11 @@ module Mihari
34
42
  raise e
35
43
  end
36
44
 
45
+ #
46
+ # Search
47
+ #
48
+ # @return [Array<Hash>]
49
+ #
37
50
  def search
38
51
  responses = []
39
52
  (1..Float::INFINITY).each do |page|
@@ -16,6 +16,11 @@ module Mihari
16
16
 
17
17
  private
18
18
 
19
+ #
20
+ # Search
21
+ #
22
+ # @return [Array<String>]
23
+ #
19
24
  def search
20
25
  artifacts = []
21
26
 
@@ -35,6 +35,11 @@ module Mihari
35
35
  @api ||= ::PassiveCIRCL::API.new(username: Mihari.config.circl_passive_username, password: Mihari.config.circl_passive_password)
36
36
  end
37
37
 
38
+ #
39
+ # Passive DNS/SSL search
40
+ #
41
+ # @return [Array<String>]
42
+ #
38
43
  def search
39
44
  case @type
40
45
  when "domain"
@@ -46,6 +51,11 @@ module Mihari
46
51
  end
47
52
  end
48
53
 
54
+ #
55
+ # Passive DNS search
56
+ #
57
+ # @return [Array<String>]
58
+ #
49
59
  def passive_dns_search
50
60
  results = api.dns.query(@query)
51
61
  results.filter_map do |result|
@@ -54,6 +64,11 @@ module Mihari
54
64
  end.uniq
55
65
  end
56
66
 
67
+ #
68
+ # Passive SSL search
69
+ #
70
+ # @return [Array<String>]
71
+ #
57
72
  def passive_ssl_search
58
73
  result = api.ssl.cquery(@query)
59
74
  seen = result["seen"] || []
@@ -23,6 +23,11 @@ module Mihari
23
23
  @api ||= ::Crtsh::API.new
24
24
  end
25
25
 
26
+ #
27
+ # Search
28
+ #
29
+ # @return [Array<Hash>]
30
+ #
26
31
  def search
27
32
  exclude = exclude_expired ? "expired" : nil
28
33
  api.search(query, exclude: exclude)
@@ -20,6 +20,11 @@ module Mihari
20
20
  @api ||= ::DNPedia::API.new
21
21
  end
22
22
 
23
+ #
24
+ # Search
25
+ #
26
+ # @return [Array<String>]
27
+ #
23
28
  def search
24
29
  res = api.search(query)
25
30
  rows = res["rows"] || []
@@ -29,6 +29,11 @@ module Mihari
29
29
 
30
30
  private
31
31
 
32
+ #
33
+ # Check whether a type is valid or not
34
+ #
35
+ # @return [Boolean]
36
+ #
32
37
  def valid_type?
33
38
  type == "domain"
34
39
  end
@@ -37,6 +42,13 @@ module Mihari
37
42
  @api ||= ::DNSTwister::API.new
38
43
  end
39
44
 
45
+ #
46
+ # Check whether a domain is resolvable or not
47
+ #
48
+ # @param [String] domain
49
+ #
50
+ # @return [Boolean]
51
+ #
40
52
  def resolvable?(domain)
41
53
  Resolv.getaddress domain
42
54
  true
@@ -44,6 +56,11 @@ module Mihari
44
56
  false
45
57
  end
46
58
 
59
+ #
60
+ # Search
61
+ #
62
+ # @return [Array<String>]
63
+ #
47
64
  def search
48
65
  raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
49
66
 
@@ -33,11 +33,24 @@ module Mihari
33
33
  @api ||= ::Onyphe::API.new(Mihari.config.onyphe_api_key)
34
34
  end
35
35
 
36
+ #
37
+ # Search with pagination
38
+ #
39
+ # @param [String] query
40
+ # @param [Integer] page
41
+ #
42
+ # @return [Structs::Onyphe::Response]
43
+ #
36
44
  def search_with_page(query, page: 1)
37
45
  res = api.simple.datascan(query, page: page)
38
46
  Structs::Onyphe::Response.from_dynamic!(res)
39
47
  end
40
48
 
49
+ #
50
+ # Search
51
+ #
52
+ # @return [Array<Structs::Onyphe::Response>]
53
+ #
41
54
  def search
42
55
  responses = []
43
56
  (1..Float::INFINITY).each do |page|
@@ -60,10 +73,13 @@ module Mihari
60
73
  def build_artifact(result)
61
74
  as = AutonomousSystem.new(asn: normalize_asn(result.asn))
62
75
 
63
- geolocation = Geolocation.new(
64
- country: NormalizeCountry(result.country_code, to: :short),
65
- country_code: result.country_code
66
- )
76
+ geolocation = nil
77
+ unless result.country_code.nil?
78
+ geolocation = Geolocation.new(
79
+ country: NormalizeCountry(result.country_code, to: :short),
80
+ country_code: result.country_code
81
+ )
82
+ end
67
83
 
68
84
  Artifact.new(
69
85
  data: result.ip,
@@ -39,10 +39,20 @@ module Mihari
39
39
  @ip_client ||= ::OTX::IP.new(Mihari.config.otx_api_key)
40
40
  end
41
41
 
42
+ #
43
+ # Check whether a type is valid or not
44
+ #
45
+ # @return [Boolean]
46
+ #
42
47
  def valid_type?
43
48
  %w[ip domain].include? type
44
49
  end
45
50
 
51
+ #
52
+ # IP/domain search
53
+ #
54
+ # @return [Array<String>]
55
+ #
46
56
  def search
47
57
  case type
48
58
  when "domain"
@@ -54,6 +64,11 @@ module Mihari
54
64
  end
55
65
  end
56
66
 
67
+ #
68
+ # Domain search
69
+ #
70
+ # @return [Array<String>]
71
+ #
57
72
  def domain_search
58
73
  records = domain_client.get_passive_dns(query)
59
74
  records.filter_map do |record|
@@ -61,6 +76,11 @@ module Mihari
61
76
  end.uniq
62
77
  end
63
78
 
79
+ #
80
+ # IP search
81
+ #
82
+ # @return [Array<String>]
83
+ #
64
84
  def ip_search
65
85
  records = ip_client.get_passive_dns(query)
66
86
  records.filter_map do |record|
@@ -35,10 +35,20 @@ module Mihari
35
35
  @api ||= ::PassiveTotal::API.new(username: Mihari.config.passivetotal_username, api_key: Mihari.config.passivetotal_api_key)
36
36
  end
37
37
 
38
+ #
39
+ # Check whether a type is valid or not
40
+ #
41
+ # @return [Boolean]
42
+ #
38
43
  def valid_type?
39
44
  %w[ip domain mail hash].include? type
40
45
  end
41
46
 
47
+ #
48
+ # Passive DNS/SSL, reverse whois search
49
+ #
50
+ # @return [Array<String>]
51
+ #
42
52
  def search
43
53
  case type
44
54
  when "domain", "ip"
@@ -52,11 +62,21 @@ module Mihari
52
62
  end
53
63
  end
54
64
 
65
+ #
66
+ # Passive DNS search
67
+ #
68
+ # @return [Array<String>]
69
+ #
55
70
  def passive_dns_search
56
71
  res = api.dns.passive_unique(query)
57
72
  res["results"] || []
58
73
  end
59
74
 
75
+ #
76
+ # Reverse whois search
77
+ #
78
+ # @return [Array<String>]
79
+ #
60
80
  def reverse_whois_search
61
81
  res = api.whois.search(query: query, field: "email")
62
82
  results = res["results"] || []
@@ -65,6 +85,11 @@ module Mihari
65
85
  end.flatten.compact.uniq
66
86
  end
67
87
 
88
+ #
89
+ # Passive SSL search
90
+ #
91
+ # @return [Array<String>]
92
+ #
68
93
  def ssl_search
69
94
  res = api.ssl.history(query)
70
95
  results = res["results"] || []
@@ -35,10 +35,20 @@ module Mihari
35
35
  @api ||= ::Pulsedive::API.new(Mihari.config.pulsedive_api_key)
36
36
  end
37
37
 
38
+ #
39
+ # Check whether a type is valid or not
40
+ #
41
+ # @return [Boolean]
42
+ #
38
43
  def valid_type?
39
44
  %w[ip domain].include? type
40
45
  end
41
46
 
47
+ #
48
+ # Search
49
+ #
50
+ # @return [Array<String>]
51
+ #
42
52
  def search
43
53
  raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
44
54
 
@@ -22,6 +22,8 @@ module Mihari
22
22
  super(**kwargs)
23
23
 
24
24
  @source = id || UUIDTools::UUID.md5_create(UUIDTools::UUID_URL_NAMESPACE, title + description).to_s
25
+
26
+ validate_analyzer_configurations
25
27
  end
26
28
 
27
29
  ANALYZER_TO_CLASS = {
@@ -119,6 +121,22 @@ module Mihari
119
121
 
120
122
  raise ArgumentError, "#{analyzer_name} is not supported"
121
123
  end
124
+
125
+ #
126
+ # Validate configuration of analyzers
127
+ #
128
+ def validate_analyzer_configurations
129
+ queries.each do |params|
130
+ analyzer_name = params[:analyzer]
131
+ klass = get_analyzer_class(analyzer_name)
132
+
133
+ instance = klass.new("dummy")
134
+ unless instance.configured?
135
+ klass_name = klass.to_s.split("::").last
136
+ raise ArgumentError, "#{klass_name} is not configured correctly"
137
+ end
138
+ end
139
+ end
122
140
  end
123
141
  end
124
142
  end