lib/mihari/analyzers/rule.rb in mihari-5.2.2 vs lib/mihari/analyzers/rule.rb in mihari-5.2.3
- old
+ new
@@ -52,16 +52,16 @@
validate_analyzer_configurations
end
#
- # Returns a list of artifacts matched with queries
+ # Returns a list of artifacts matched with queries/analyzers
#
# @return [Array<Mihari::Artifact>]
#
def artifacts
- rule.queries.map { |params| run_query(params.deep_dup) }.flatten
+ analyzers.flat_map(&:normalized_artifacts)
end
#
# Normalize artifacts
# - Reject invalid artifacts (for just in case)
@@ -109,30 +109,19 @@
# Bulk emit
#
# @return [Array<Mihari::Alert>]
#
def bulk_emit
- Parallel.map(valid_emitters) { |emitter| emit emitter }.compact
- end
+ return [] if enriched_artifacts.empty?
- #
- # Emit an alert
- #
- # @param [Mihari::Emitters::Base] emitter
- #
- # @return [Mihari::Alert, nil]
- #
- def emit(emitter)
- return if enriched_artifacts.empty?
-
- alert_or_something = emitter.run(artifacts: enriched_artifacts, rule: rule)
-
- Mihari.logger.info "Emission by #{emitter.class} is succeeded"
-
- alert_or_something
- rescue StandardError => e
- Mihari.logger.info "Emission by #{emitter.class} is failed: #{e}"
+ Parallel.map(valid_emitters) do |emitter|
+ emission = emitter.emit
+ Mihari.logger.info "Emission by #{emitter.class} is succeeded"
+ emission
+ rescue StandardError => e
+ Mihari.logger.info "Emission by #{emitter.class} is failed: #{e}"
+ end.compact
end
#
# Set artifacts & run emitters in parallel
#
@@ -163,31 +152,54 @@
falseposistive.match?(value)
end
end
#
- # @param [Hash] params
+ # Deep copied queries
#
- # @return [Array<Mihari::Artifact>]
+ # @return [Array<Hash>]
#
- def run_query(params)
- analyzer_name = params[:analyzer]
- klass = get_analyzer_class(analyzer_name)
+ def queries
+ rule.queries.map(&:deep_dup)
+ end
- # set interval in the top level
- options = params[:options] || {}
- interval = options[:interval]
- params[:interval] = interval if interval
+ #
+ # Get analyzer class
+ #
+ # @param [String] analyzer_name
+ #
+ # @return [Class<Mihari::Analyzers::Base>] analyzer class
+ #
+ def get_analyzer_class(analyzer_name)
+ analyzer = ANALYZER_TO_CLASS[analyzer_name]
+ return analyzer if analyzer
- # set rule
- params[:rule] = rule
- query = params[:query]
- analyzer = klass.new(query, **params)
+ raise ArgumentError, "#{analyzer_name} is not supported"
+ end
- # Use #normalized_artifacts method to get artifacts as Array<Mihari::Artifact>
- # So Mihari::Artifact object has "source" attribute (e.g. "Shodan")
- analyzer.normalized_artifacts
+ #
+ # @return [Array<Mihari::Analyzers::Base>] <description>
+ #
+ def analyzers
+ @analyzers ||= queries.map do |params|
+ analyzer_name = params[:analyzer]
+ klass = get_analyzer_class(analyzer_name)
+
+ # set interval in the top level
+ options = params[:options] || {}
+ interval = options[:interval]
+ params[:interval] = interval if interval
+
+ # set rule
+ params[:rule] = rule
+ query = params[:query]
+
+ analyzer = klass.new(query, **params)
+ raise ConfigurationError, "#{analyzer.source} is not configured correctly" unless analyzer.configured?
+
+ analyzer
+ end
end
#
# Get emitter class
#
@@ -201,57 +213,36 @@
raise ArgumentError, "#{emitter_name} is not supported"
end
#
- # @param [Hash] params
+ # Deep copied emitters
#
- # @return [Mihari::Emitter:Base]
+ # @return [Array<Mihari::Emitters::Base>]
#
- def validate_emitter(params)
- name = params[:emitter]
- params.delete(:emitter)
+ def emitters
+ rule.emitters.map(&:deep_dup).map do |params|
+ name = params[:emitter]
+ params.delete(:emitter)
- klass = get_emitter_class(name)
- emitter = klass.new(**params)
-
- emitter.valid? ? emitter : nil
+ klass = get_emitter_class(name)
+ klass.new(artifacts: enriched_artifacts, rule: rule, **params)
+ end
end
#
- # @return [Array<Mihari::Emitter::Base>]
+ # @return [Array<Mihari::Emitters::Base>]
#
def valid_emitters
- @valid_emitters ||= rule.emitters.filter_map { |params| validate_emitter(params.deep_dup) }
+ @valid_emitters ||= emitters.select(&:valid?)
end
#
- # Get analyzer class
- #
- # @param [String] analyzer_name
- #
- # @return [Class<Mihari::Analyzers::Base>] analyzer class
- #
- def get_analyzer_class(analyzer_name)
- analyzer = ANALYZER_TO_CLASS[analyzer_name]
- return analyzer if analyzer
-
- raise ArgumentError, "#{analyzer_name} is not supported"
- end
-
- #
# Validate configuration of analyzers
#
def validate_analyzer_configurations
- rule.queries.each do |params|
- analyzer_name = params[:analyzer]
-
- klass = get_analyzer_class(analyzer_name)
- klass_name = klass.to_s.split("::").last
-
- instance = klass.new("dummy")
- raise ConfigurationError, "#{klass_name} is not configured correctly" unless instance.configured?
- end
+ # memoize analyzers & raise ConfigurationError if there is an analyzer which is not configured
+ analyzers
end
end
end
end