Class: Mihari::Structs::Rule

Inherits:
Object
  • Object
show all
Extended by:
Mixins::Database
Defined in:
lib/mihari/structs/rule.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Mixins::Database

with_db_connection

Constructor Details

#initialize(data, yaml) ⇒ Rule

Returns a new instance of Rule.



23
24
25
26
27
28
29
30
31
# File 'lib/mihari/structs/rule.rb', line 23

def initialize(data, yaml)
  @data = data.deep_symbolize_keys
  @yaml = yaml

  @errors = nil
  @no_method_error = nil

  validate
end

Instance Attribute Details

#dataHash (readonly)

Returns:

  • (Hash)


12
13
14
# File 'lib/mihari/structs/rule.rb', line 12

def data
  @data
end

#errorsArray? (readonly)

Returns:

  • (Array, nil)


18
19
20
# File 'lib/mihari/structs/rule.rb', line 18

def errors
  @errors
end

#idString

Returns:

  • (String)


88
89
90
# File 'lib/mihari/structs/rule.rb', line 88

def id
  @id ||= data[:id] || UUIDTools::UUID.md5_create(UUIDTools::UUID_URL_NAMESPACE, data.to_yaml).to_s
end

#yamlString (readonly)

Returns:

  • (String)


15
16
17
# File 'lib/mihari/structs/rule.rb', line 15

def yaml
  @yaml
end

Class Method Details

.from_model(model) ⇒ Mihari::Structs::Rule

Parameters:

Returns:



157
158
159
160
161
162
163
# File 'lib/mihari/structs/rule.rb', line 157

def from_model(model)
  data = model.data.deep_symbolize_keys
  # set ID if YAML data do not have ID
  data[:id] = model.id unless data.key?(:id)

  Structs::Rule.new(data, model.yaml)
end

.from_path_or_id(path_or_id) ⇒ Mihari::Structs::Rule

Parameters:

  • path_or_id (String)

    Path to YAML file or YAML string or ID of a rule in the database

Returns:



184
185
186
187
188
189
190
191
# File 'lib/mihari/structs/rule.rb', line 184

def from_path_or_id(path_or_id)
  yaml = nil

  yaml = load_yaml_from_file(path_or_id) if File.exist?(path_or_id)
  yaml = load_yaml_from_db(path_or_id) if yaml.nil?

  Structs::Rule.from_yaml yaml
end

.from_yaml(yaml, id: nil) ⇒ Mihari::Structs::Rule

Parameters:

  • yaml (String)
  • id (String, nil) (defaults to: nil)

Returns:



171
172
173
174
175
176
177
# File 'lib/mihari/structs/rule.rb', line 171

def from_yaml(yaml, id: nil)
  data = load_erb_yaml(yaml)
  # set ID if id is given & YAML data do not have ID
  data[:id] = id if !id.nil? && !data.key?(:id)

  Structs::Rule.new(data, yaml)
end

Instance Method Details

#[](key) ⇒ Object



81
82
83
# File 'lib/mihari/structs/rule.rb', line 81

def [](key)
  data[key.to_sym]
end

#descriptionString

Returns:

  • (String)


102
103
104
# File 'lib/mihari/structs/rule.rb', line 102

def description
  @description ||= data[:description]
end

#error_messagesArray<String>

Returns:

  • (Array<String>)


45
46
47
48
49
50
51
52
53
54
# File 'lib/mihari/structs/rule.rb', line 45

def error_messages
  return [] if @errors.nil?

  @errors.messages.filter_map do |message|
    path = message.path.map(&:to_s).join
    "#{path} #{message.text}"
  rescue NoMethodError
    nil
  end
end

#errors?Boolean

Returns:

  • (Boolean)


36
37
38
39
40
# File 'lib/mihari/structs/rule.rb', line 36

def errors?
  return false if @errors.nil?

  !@errors.empty?
end

#titleString

Returns:

  • (String)


95
96
97
# File 'lib/mihari/structs/rule.rb', line 95

def title
  @title ||= data[:title]
end

#to_analyzerMihari::Analyzers::Rule



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/mihari/structs/rule.rb', line 131

def to_analyzer
  analyzer = Mihari::Analyzers::Rule.new(
    title: self[:title],
    description: self[:description],
    tags: self[:tags],
    queries: self[:queries],
    allowed_data_types: self[:allowed_data_types],
    disallowed_data_values: self[:disallowed_data_values],
    emitters: self[:emitters],
    enrichers: self[:enrichers],
    id: id
  )
  analyzer.ignore_old_artifacts = self[:ignore_old_artifacts]
  analyzer.ignore_threshold = self[:ignore_threshold]

  analyzer
end

#to_modelMihari::Rule

Returns:



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/mihari/structs/rule.rb', line 109

def to_model
  rule = Mihari::Rule.find(id)

  rule.title = title
  rule.description = description
  rule.data = data
  rule.yaml = yaml

  rule
rescue ActiveRecord::RecordNotFound
  Mihari::Rule.new(
    id: id,
    title: title,
    description: description,
    data: data,
    yaml: yaml
  )
end

#validateObject



56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/mihari/structs/rule.rb', line 56

def validate
  begin
    contract = Schemas::RuleContract.new
    result = contract.call(data)
  rescue NoMethodError => e
    @no_method_error = e
    return
  end

  @data = result.to_h
  @errors = result.errors
end

#validate!Object



69
70
71
72
73
74
75
76
77
78
79
# File 'lib/mihari/structs/rule.rb', line 69

def validate!
  raise RuleValidationError, "Data should be a hash" unless data.is_a?(Hash)
  raise RuleValidationError, error_messages.join("\n") if errors?
  raise RuleValidationError, "Something wrong with queries, emitters or enrichers." unless @no_method_error.nil?
rescue RuleValidationError => e
  message = "Failed to parse the input as a rule"
  message += ": #{e.message}" unless e.message.empty?
  Mihari.logger.error message

  raise e
end