lib/mihari/analyzers/base.rb in mihari-5.2.1 vs lib/mihari/analyzers/base.rb in mihari-5.2.2
- old
+ new
@@ -3,149 +3,54 @@
module Mihari
module Analyzers
class Base
extend Dry::Initializer
- option :rule, default: proc {}
-
include Mixins::Configurable
include Mixins::Retriable
- # @return [Mihari::Structs::Rule, nil]
- attr_reader :rule
-
- def initialize(*args, **kwargs)
- super(*args, **kwargs)
-
- @base_time = Time.now.utc
+ # @return [Array<String>, Array<Mihari::Artifact>]
+ def artifacts
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
end
#
- # Load/overwrite rule
+ # Normalize artifacts
+ # - Convert data (string) into an artifact
+ # - Reject an invalid artifact
#
- # @param [String] path_or_id
+ # @return [Array<Mihari::Artifact>]
#
- def load_rule(path_or_id)
- @rule = Structs::Rule.from_path_or_id path_or_id
+ def normalized_artifacts
+ retry_on_error do
+ @normalized_artifacts ||= artifacts.compact.sort.map do |artifact|
+ # No need to set data_type manually
+ # It is set automatically in #initialize
+ artifact = artifact.is_a?(Artifact) ? artifact : Artifact.new(data: artifact)
+ artifact
+ end.select(&:valid?).uniq(&:data).map do |artifact|
+ # set source
+ artifact.source = source
+ artifact
+ end
+ end
end
- # @return [Array<String>, Array<Mihari::Artifact>]
- def artifacts
- raise NotImplementedError, "You must implement #{self.class}##{__method__}"
- end
-
# @return [String]
def source
self.class.to_s.split("::").last.to_s
end
# @return [String]
def class_name
self.class.to_s.split("::").last
end
- #
- # Set artifacts & run emitters in parallel
- #
- # @return [Mihari::Alert, nil]
- #
- def run
- raise ConfigurationError, "#{class_name} is not configured correctly" unless configured?
-
- alert_or_something = bulk_emit
- # returns Mihari::Alert created by the database emitter
- alert_or_something.find { |res| res.is_a?(Mihari::Alert) }
- end
-
- #
- # Bulk emit
- #
- # @return [Array<Mihari::Alert>]
- #
- def bulk_emit
- Parallel.map(valid_emitters) { |emitter| emit emitter }.compact
- end
-
- #
- # 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 succedded"
-
- alert_or_something
- rescue StandardError => e
- Mihari.logger.info "Emission by #{emitter.class} is failed: #{e}"
- end
-
class << self
def inherited(child)
super
Mihari.analyzers << child
end
- end
-
- #
- # Normalize artifacts
- # - Convert data (string) into an artifact
- # - Set rule ID
- # - Reject an invalid artifact
- # - Uniquefy artifacts by data
- #
- # @return [Array<Mihari::Artifact>]
- #
- def normalized_artifacts
- @normalized_artifacts ||= artifacts.compact.sort.map do |artifact|
- # No need to set data_type manually
- # It is set automatically in #initialize
- artifact = artifact.is_a?(Artifact) ? artifact : Artifact.new(data: artifact, source: source)
- artifact.rule_id = rule&.id
- artifact
- end.select(&:valid?).uniq(&:data)
- end
-
- private
-
- #
- # Uniquefy artifacts (assure rule level uniqueness)
- #
- # @return [Array<Mihari::Artifact>]
- #
- def unique_artifacts
- @unique_artifacts ||= normalized_artifacts.select do |artifact|
- artifact.unique?(base_time: @base_time, artifact_lifetime: rule&.artifact_lifetime)
- end
- end
-
- #
- # Enriched artifacts
- #
- # @return [Array<Mihari::Artifact>]
- #
- def enriched_artifacts
- @enriched_artifacts ||= Parallel.map(unique_artifacts) do |artifact|
- artifact.enrich_all
- artifact
- end
- end
-
- #
- # Select valid emitters
- #
- # @return [Array<Mihari::Emitters::Base>]
- #
- def valid_emitters
- @valid_emitters ||= Mihari.emitters.filter_map do |klass|
- emitter = klass.new
- emitter.valid? ? emitter : nil
- end.compact
end
end
end
end