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