mihari 5.6.1 → 5.6.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/frontend/package-lock.json +173 -176
  3. data/frontend/package.json +9 -9
  4. data/lib/mihari/{base.rb → actor.rb} +16 -2
  5. data/lib/mihari/analyzers/base.rb +5 -10
  6. data/lib/mihari/analyzers/censys.rb +1 -1
  7. data/lib/mihari/analyzers/hunterhow.rb +1 -1
  8. data/lib/mihari/analyzers/passivetotal.rb +1 -1
  9. data/lib/mihari/analyzers/pulsedive.rb +1 -1
  10. data/lib/mihari/analyzers/securitytrails.rb +1 -1
  11. data/lib/mihari/analyzers/urlscan.rb +1 -1
  12. data/lib/mihari/analyzers/virustotal.rb +5 -5
  13. data/lib/mihari/analyzers/zoomeye.rb +3 -3
  14. data/lib/mihari/clients/crtsh.rb +2 -2
  15. data/lib/mihari/clients/passivetotal.rb +4 -4
  16. data/lib/mihari/clients/securitytrails.rb +3 -3
  17. data/lib/mihari/commands/rule.rb +2 -11
  18. data/lib/mihari/commands/search.rb +1 -1
  19. data/lib/mihari/emitters/base.rb +13 -24
  20. data/lib/mihari/emitters/database.rb +7 -9
  21. data/lib/mihari/emitters/misp.rb +14 -38
  22. data/lib/mihari/emitters/slack.rb +14 -11
  23. data/lib/mihari/emitters/the_hive.rb +16 -44
  24. data/lib/mihari/emitters/webhook.rb +31 -21
  25. data/lib/mihari/enrichers/base.rb +1 -6
  26. data/lib/mihari/enrichers/whois.rb +1 -1
  27. data/lib/mihari/models/alert.rb +75 -73
  28. data/lib/mihari/models/artifact.rb +182 -180
  29. data/lib/mihari/models/autonomous_system.rb +22 -20
  30. data/lib/mihari/models/cpe.rb +21 -19
  31. data/lib/mihari/models/dns.rb +24 -22
  32. data/lib/mihari/models/geolocation.rb +22 -20
  33. data/lib/mihari/models/port.rb +21 -19
  34. data/lib/mihari/models/reverse_dns.rb +21 -19
  35. data/lib/mihari/models/rule.rb +67 -65
  36. data/lib/mihari/models/tag.rb +5 -3
  37. data/lib/mihari/models/tagging.rb +5 -3
  38. data/lib/mihari/models/whois.rb +18 -16
  39. data/lib/mihari/rule.rb +352 -0
  40. data/lib/mihari/schemas/analyzer.rb +94 -87
  41. data/lib/mihari/schemas/emitter.rb +9 -5
  42. data/lib/mihari/schemas/enricher.rb +8 -4
  43. data/lib/mihari/schemas/mixins.rb +15 -0
  44. data/lib/mihari/schemas/rule.rb +3 -10
  45. data/lib/mihari/services/alert_builder.rb +1 -1
  46. data/lib/mihari/services/alert_proxy.rb +10 -6
  47. data/lib/mihari/services/alert_runner.rb +4 -4
  48. data/lib/mihari/services/rule_builder.rb +3 -3
  49. data/lib/mihari/services/rule_runner.rb +5 -5
  50. data/lib/mihari/structs/binaryedge.rb +1 -1
  51. data/lib/mihari/structs/censys.rb +6 -6
  52. data/lib/mihari/structs/config.rb +1 -1
  53. data/lib/mihari/structs/greynoise.rb +5 -5
  54. data/lib/mihari/structs/hunterhow.rb +3 -3
  55. data/lib/mihari/structs/onyphe.rb +5 -5
  56. data/lib/mihari/structs/shodan.rb +6 -6
  57. data/lib/mihari/structs/urlscan.rb +3 -3
  58. data/lib/mihari/structs/virustotal_intelligence.rb +3 -3
  59. data/lib/mihari/version.rb +1 -1
  60. data/lib/mihari/web/endpoints/alerts.rb +4 -4
  61. data/lib/mihari/web/endpoints/artifacts.rb +6 -6
  62. data/lib/mihari/web/endpoints/rules.rb +10 -17
  63. data/lib/mihari/web/endpoints/tags.rb +2 -2
  64. data/lib/mihari/web/public/assets/{index-9cc489e6.js → index-28d4c79d.js} +48 -48
  65. data/lib/mihari/web/public/index.html +1 -1
  66. data/lib/mihari.rb +6 -8
  67. data/mihari.gemspec +1 -2
  68. data/requirements.txt +1 -1
  69. metadata +8 -22
  70. data/lib/mihari/analyzers/rule.rb +0 -232
  71. data/lib/mihari/services/rule_proxy.rb +0 -182
@@ -6,7 +6,7 @@
6
6
  <meta name="viewport" content="width=device-width,initial-scale=1.0" />
7
7
  <link rel="icon" href="/favicon.ico" />
8
8
  <title>Mihari</title>
9
- <script type="module" crossorigin src="/assets/index-9cc489e6.js"></script>
9
+ <script type="module" crossorigin src="/assets/index-28d4c79d.js"></script>
10
10
  <link rel="stylesheet" href="/assets/index-56fc2187.css">
11
11
  </head>
12
12
  <body>
data/lib/mihari.rb CHANGED
@@ -35,7 +35,6 @@ require "addressable/uri"
35
35
  require "awrence"
36
36
  require "email_address"
37
37
  require "memist"
38
- require "net/ping"
39
38
  require "parallel"
40
39
  require "plissken"
41
40
  require "public_suffix"
@@ -74,7 +73,7 @@ module Mihari
74
73
  #
75
74
  def emitter_to_class
76
75
  @emitter_to_class ||= emitters.flat_map do |klass|
77
- klass.class_keys.map { |key| [key.downcase, klass] }
76
+ klass.class_keys.map { |key| [key, klass] }
78
77
  end.to_h
79
78
  end
80
79
 
@@ -88,7 +87,7 @@ module Mihari
88
87
  #
89
88
  def analyzer_to_class
90
89
  @analyzer_to_class ||= analyzers.flat_map do |klass|
91
- klass.class_keys.map { |key| [key.downcase, klass] }
90
+ klass.class_keys.map { |key| [key, klass] }
92
91
  end.to_h
93
92
  end
94
93
 
@@ -102,7 +101,7 @@ module Mihari
102
101
  #
103
102
  def enricher_to_class
104
103
  @enricher_to_class ||= enrichers.flat_map do |klass|
105
- klass.class_keys.map { |key| [key.downcase, klass] }
104
+ klass.class_keys.map { |key| [key, klass] }
106
105
  end.to_h
107
106
  end
108
107
 
@@ -131,10 +130,11 @@ module Mihari
131
130
  end
132
131
 
133
132
  # Core classes
134
- require "mihari/base"
133
+ require "mihari/actor"
135
134
  require "mihari/database"
136
135
  require "mihari/http"
137
136
  require "mihari/type_checker"
137
+ require "mihari/rule"
138
138
 
139
139
  # Enrichers
140
140
  require "mihari/enrichers/base"
@@ -210,8 +210,6 @@ require "mihari/analyzers/virustotal_intelligence"
210
210
  require "mihari/analyzers/virustotal"
211
211
  require "mihari/analyzers/zoomeye"
212
212
 
213
- require "mihari/analyzers/rule"
214
-
215
213
  # Types
216
214
  require "mihari/types"
217
215
 
@@ -234,6 +232,7 @@ require "mihari/structs/virustotal_intelligence"
234
232
 
235
233
  # Schemas
236
234
  require "mihari/schemas/macros"
235
+ require "mihari/schemas/mixins"
237
236
 
238
237
  require "mihari/schemas/options"
239
238
 
@@ -243,7 +242,6 @@ require "mihari/schemas/rule"
243
242
 
244
243
  # Services
245
244
  require "mihari/services/rule_builder"
246
- require "mihari/services/rule_proxy"
247
245
  require "mihari/services/rule_runner"
248
246
 
249
247
  require "mihari/services/alert_builder"
data/mihari.gemspec CHANGED
@@ -48,7 +48,7 @@ Gem::Specification.new do |spec|
48
48
  spec.add_development_dependency "rb-fsevent", "~> 0.11"
49
49
  spec.add_development_dependency "rerun", "~> 0.14"
50
50
  spec.add_development_dependency "rspec", "~> 3.12"
51
- spec.add_development_dependency "rubocop-rspec", "~> 2.24"
51
+ spec.add_development_dependency "rubocop-rspec", "~> 2.25"
52
52
  spec.add_development_dependency "simplecov-lcov", "~> 0.8"
53
53
  spec.add_development_dependency "standard", "~> 1.31"
54
54
  spec.add_development_dependency "test-prof", "~> 1.2"
@@ -80,7 +80,6 @@ Gem::Specification.new do |spec|
80
80
  spec.add_dependency "jr-cli", "0.6.0"
81
81
  spec.add_dependency "launchy", "2.5.2"
82
82
  spec.add_dependency "memist", "2.0.2"
83
- spec.add_dependency "net-ping", "2.0.8"
84
83
  spec.add_dependency "normalize_country", "0.3.2"
85
84
  spec.add_dependency "parallel", "1.23.0"
86
85
  spec.add_dependency "plissken", "2.0.1"
data/requirements.txt CHANGED
@@ -1,2 +1,2 @@
1
1
  mkdocs==1.5.3
2
- mkdocs-material==9.4.6
2
+ mkdocs-material==9.4.7
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mihari
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.6.1
4
+ version: 5.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Manabu Niseki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-10-23 00:00:00.000000000 Z
11
+ date: 2023-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -184,14 +184,14 @@ dependencies:
184
184
  requirements:
185
185
  - - "~>"
186
186
  - !ruby/object:Gem::Version
187
- version: '2.24'
187
+ version: '2.25'
188
188
  type: :development
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
192
  - - "~>"
193
193
  - !ruby/object:Gem::Version
194
- version: '2.24'
194
+ version: '2.25'
195
195
  - !ruby/object:Gem::Dependency
196
196
  name: simplecov-lcov
197
197
  requirement: !ruby/object:Gem::Requirement
@@ -570,20 +570,6 @@ dependencies:
570
570
  - - '='
571
571
  - !ruby/object:Gem::Version
572
572
  version: 2.0.2
573
- - !ruby/object:Gem::Dependency
574
- name: net-ping
575
- requirement: !ruby/object:Gem::Requirement
576
- requirements:
577
- - - '='
578
- - !ruby/object:Gem::Version
579
- version: 2.0.8
580
- type: :runtime
581
- prerelease: false
582
- version_requirements: !ruby/object:Gem::Requirement
583
- requirements:
584
- - - '='
585
- - !ruby/object:Gem::Version
586
- version: 2.0.8
587
573
  - !ruby/object:Gem::Dependency
588
574
  name: normalize_country
589
575
  requirement: !ruby/object:Gem::Requirement
@@ -970,6 +956,7 @@ files:
970
956
  - frontend/vitest.config.ts
971
957
  - lefthook.yml
972
958
  - lib/mihari.rb
959
+ - lib/mihari/actor.rb
973
960
  - lib/mihari/analyzers/base.rb
974
961
  - lib/mihari/analyzers/binaryedge.rb
975
962
  - lib/mihari/analyzers/censys.rb
@@ -983,14 +970,12 @@ files:
983
970
  - lib/mihari/analyzers/otx.rb
984
971
  - lib/mihari/analyzers/passivetotal.rb
985
972
  - lib/mihari/analyzers/pulsedive.rb
986
- - lib/mihari/analyzers/rule.rb
987
973
  - lib/mihari/analyzers/securitytrails.rb
988
974
  - lib/mihari/analyzers/shodan.rb
989
975
  - lib/mihari/analyzers/urlscan.rb
990
976
  - lib/mihari/analyzers/virustotal.rb
991
977
  - lib/mihari/analyzers/virustotal_intelligence.rb
992
978
  - lib/mihari/analyzers/zoomeye.rb
993
- - lib/mihari/base.rb
994
979
  - lib/mihari/cli/alert.rb
995
980
  - lib/mihari/cli/base.rb
996
981
  - lib/mihari/cli/database.rb
@@ -1071,18 +1056,19 @@ files:
1071
1056
  - lib/mihari/models/tag.rb
1072
1057
  - lib/mihari/models/tagging.rb
1073
1058
  - lib/mihari/models/whois.rb
1059
+ - lib/mihari/rule.rb
1074
1060
  - lib/mihari/schemas/alert.rb
1075
1061
  - lib/mihari/schemas/analyzer.rb
1076
1062
  - lib/mihari/schemas/emitter.rb
1077
1063
  - lib/mihari/schemas/enricher.rb
1078
1064
  - lib/mihari/schemas/macros.rb
1065
+ - lib/mihari/schemas/mixins.rb
1079
1066
  - lib/mihari/schemas/options.rb
1080
1067
  - lib/mihari/schemas/rule.rb
1081
1068
  - lib/mihari/services/alert_builder.rb
1082
1069
  - lib/mihari/services/alert_proxy.rb
1083
1070
  - lib/mihari/services/alert_runner.rb
1084
1071
  - lib/mihari/services/rule_builder.rb
1085
- - lib/mihari/services/rule_proxy.rb
1086
1072
  - lib/mihari/services/rule_runner.rb
1087
1073
  - lib/mihari/structs/binaryedge.rb
1088
1074
  - lib/mihari/structs/censys.rb
@@ -1110,8 +1096,8 @@ files:
1110
1096
  - lib/mihari/web/endpoints/tags.rb
1111
1097
  - lib/mihari/web/middleware/connection_adapter.rb
1112
1098
  - lib/mihari/web/middleware/error_notification_adapter.rb
1099
+ - lib/mihari/web/public/assets/index-28d4c79d.js
1113
1100
  - lib/mihari/web/public/assets/index-56fc2187.css
1114
- - lib/mihari/web/public/assets/index-9cc489e6.js
1115
1101
  - lib/mihari/web/public/assets/mode-yaml-a21faa53.js
1116
1102
  - lib/mihari/web/public/favicon.ico
1117
1103
  - lib/mihari/web/public/index.html
@@ -1,232 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mihari
4
- module Analyzers
5
- class Rule
6
- include Mixins::FalsePositive
7
-
8
- # @return [Mihari::Services::RuleProxy]
9
- attr_reader :rule
10
-
11
- # @return [Time]
12
- attr_reader :base_time
13
-
14
- #
15
- # @param [Mihari::Services::RuleProxy] rule
16
- #
17
- def initialize(rule)
18
- @rule = rule
19
- @base_time = Time.now.utc
20
-
21
- validate_analyzer_configurations
22
- end
23
-
24
- #
25
- # Returns a list of artifacts matched with queries/analyzers (with the rule ID)
26
- #
27
- # @return [Array<Mihari::Artifact>]
28
- #
29
- def artifacts
30
- analyzers.flat_map do |analyzer|
31
- result = analyzer.result
32
-
33
- raise result.failure if result.failure? && !analyzer.ignore_error?
34
-
35
- artifacts = result.value!
36
- artifacts.map do |artifact|
37
- artifact.rule_id = rule.id
38
- artifact
39
- end
40
- end
41
- end
42
-
43
- #
44
- # Normalize artifacts
45
- # - Reject invalid artifacts (for just in case)
46
- # - Select artifacts with allowed data types
47
- # - Reject artifacts with false positive values
48
- # - Set rule ID
49
- #
50
- # @return [Array<Mihari::Artifact>]
51
- #
52
- def normalized_artifacts
53
- valid_artifacts = artifacts.uniq(&:data).select(&:valid?)
54
- date_type_allowed_artifacts = valid_artifacts.select { |artifact| rule.data_types.include? artifact.data_type }
55
- date_type_allowed_artifacts.reject { |artifact| falsepositive? artifact.data }
56
- end
57
-
58
- #
59
- # Uniquify artifacts (assure rule level uniqueness)
60
- #
61
- # @return [Array<Mihari::Artifact>]
62
- #
63
- def unique_artifacts
64
- normalized_artifacts.select do |artifact|
65
- artifact.unique?(base_time: base_time, artifact_lifetime: rule.artifact_lifetime)
66
- end
67
- end
68
-
69
- #
70
- # Enriched artifacts
71
- #
72
- # @return [Array<Mihari::Artifact>]
73
- #
74
- def enriched_artifacts
75
- @enriched_artifacts ||= Parallel.map(unique_artifacts) do |artifact|
76
- enrichers.each { |enricher| artifact.enrich_by_enricher enricher }
77
- artifact
78
- end
79
- end
80
-
81
- #
82
- # Bulk emit
83
- #
84
- # @return [Array<Mihari::Alert>]
85
- #
86
- def bulk_emit
87
- return [] if enriched_artifacts.empty?
88
-
89
- # NOTE: separate parallel execution and logging
90
- # because the logger does not work along with Parallel
91
- results = Parallel.map(valid_emitters) do |emitter|
92
- emitter.result
93
- end
94
-
95
- results.zip(valid_emitters).map do |result_and_emitter|
96
- result, emitter = result_and_emitter
97
-
98
- Mihari.logger.info "Emission by #{emitter.class} is failed: #{result.failure}" if result.failure?
99
- Mihari.logger.info "Emission by #{emitter.class} is succeeded" if result.success?
100
-
101
- result.value_or nil
102
- end.compact
103
- end
104
-
105
- #
106
- # Set artifacts & run emitters in parallel
107
- #
108
- # @return [Mihari::Alert, nil]
109
- #
110
- def run
111
- alert_or_something = bulk_emit
112
- # returns Mihari::Alert created by the database emitter
113
- alert_or_something.find { |res| res.is_a?(Mihari::Alert) }
114
- end
115
-
116
- private
117
-
118
- #
119
- # Check whether a value is a falsepositive value or not
120
- #
121
- # @return [Boolean]
122
- #
123
- def falsepositive?(value)
124
- return true if rule.falsepositives.include?(value)
125
-
126
- regexps = rule.falsepositives.select { |fp| fp.is_a?(Regexp) }
127
- regexps.any? { |fp| fp.match?(value) }
128
- end
129
-
130
- #
131
- # Get analyzer class
132
- #
133
- # @param [String] key
134
- #
135
- # @return [Class<Mihari::Analyzers::Base>] analyzer class
136
- #
137
- def get_analyzer_class(key)
138
- raise ArgumentError, "#{key} is not supported" unless Mihari.analyzer_to_class.key?(key)
139
-
140
- Mihari.analyzer_to_class[key]
141
- end
142
-
143
- #
144
- # @return [Array<Mihari::Analyzers::Base>]
145
- #
146
- def analyzers
147
- rule.queries.map do |query_params|
148
- analyzer_name = query_params[:analyzer]
149
- klass = get_analyzer_class(analyzer_name)
150
- klass.from_query(query_params)
151
- end
152
- end
153
-
154
- #
155
- # Get emitter class
156
- #
157
- # @param [String] key
158
- #
159
- # @return [Class<Mihari::Emitters::Base>] emitter class
160
- #
161
- def get_emitter_class(key)
162
- raise ArgumentError, "#{key} is not supported" unless Mihari.emitter_to_class.key?(key)
163
-
164
- Mihari.emitter_to_class[key]
165
- end
166
-
167
- #
168
- # @return [Array<Mihari::Emitters::Base>]
169
- #
170
- def emitters
171
- rule.emitters.map(&:deep_dup).map do |params|
172
- name = params[:emitter]
173
- options = params[:options]
174
-
175
- %i[emitter options].each { |key| params.delete key }
176
-
177
- klass = get_emitter_class(name)
178
- klass.new(artifacts: enriched_artifacts, rule: rule, options: options, **params)
179
- end
180
- end
181
-
182
- #
183
- # @return [Array<Mihari::Emitters::Base>]
184
- #
185
- def valid_emitters
186
- @valid_emitters ||= emitters.select(&:valid?)
187
- end
188
-
189
- #
190
- # Get enricher class
191
- #
192
- # @param [String] key
193
- #
194
- # @return [Class<Mihari::Enrichers::Base>] enricher class
195
- #
196
- def get_enricher_class(key)
197
- raise ArgumentError, "#{key} is not supported" unless Mihari.enricher_to_class.key?(key)
198
-
199
- Mihari.enricher_to_class[key]
200
- end
201
-
202
- #
203
- # @return [Array<Mihari::Enrichers::Base>] enrichers
204
- #
205
- def enrichers
206
- @enrichers ||= rule.enrichers.map(&:deep_dup).map do |params|
207
- name = params[:enricher]
208
- options = params[:options]
209
-
210
- %i[enricher options].each { |key| params.delete key }
211
-
212
- klass = get_enricher_class(name)
213
- klass.new(options: options, **params)
214
- end
215
- end
216
-
217
- #
218
- # Validate configuration of analyzers
219
- #
220
- def validate_analyzer_configurations
221
- analyzers.map do |analyzer|
222
- next if analyzer.configured?
223
-
224
- joined = analyzer.configuration_keys.join(", ")
225
- be = (analyzer.configuration_keys.length > 1) ? "are" : "is"
226
- message = "#{analyzer.class.class_key} is not configured correctly. #{joined} #{be} missing."
227
- raise ConfigurationError, message
228
- end
229
- end
230
- end
231
- end
232
- end
@@ -1,182 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "json"
4
-
5
- module Mihari
6
- module Services
7
- #
8
- # proxy (or converter) class for rule
9
- # proxying rule schema data into analyzer & model
10
- #
11
- class RuleProxy
12
- include Mixins::FalsePositive
13
-
14
- # @return [Hash]
15
- attr_reader :data
16
-
17
- # @return [Array, nil]
18
- attr_reader :errors
19
-
20
- #
21
- # Initialize
22
- #
23
- # @param [Hash] data
24
- #
25
- def initialize(data)
26
- @data = data.deep_symbolize_keys
27
- @errors = nil
28
-
29
- validate!
30
- end
31
-
32
- #
33
- # @return [Boolean]
34
- #
35
- def errors?
36
- return false if @errors.nil?
37
-
38
- !@errors.empty?
39
- end
40
-
41
- def validate!
42
- contract = Schemas::RuleContract.new
43
- result = contract.call(data)
44
-
45
- @data = result.to_h
46
- @errors = result.errors
47
-
48
- raise ValidationError.new("Validation failed", errors) if errors?
49
- end
50
-
51
- def [](key)
52
- data key.to_sym
53
- end
54
-
55
- #
56
- # @return [String]
57
- #
58
- def id
59
- @id ||= data[:id]
60
- end
61
-
62
- #
63
- # @return [String]
64
- #
65
- def title
66
- @title ||= data[:title]
67
- end
68
-
69
- #
70
- # @return [String]
71
- #
72
- def description
73
- @description ||= data[:description]
74
- end
75
-
76
- #
77
- # @return [String]
78
- #
79
- def yaml
80
- @yaml ||= data.deep_stringify_keys.to_yaml
81
- end
82
-
83
- #
84
- # @return [Array<Hash>]
85
- #
86
- def queries
87
- @queries ||= data[:queries]
88
- end
89
-
90
- #
91
- # @return [Array<String>]
92
- #
93
- def data_types
94
- @data_types ||= data[:data_types]
95
- end
96
-
97
- #
98
- # @return [Array<String>]
99
- #
100
- def tags
101
- @tags ||= data[:tags]
102
- end
103
-
104
- #
105
- # @return [Array<String, RegExp>]
106
- #
107
- def falsepositives
108
- @falsepositives ||= data[:falsepositives].map { |fp| normalize_falsepositive fp }
109
- end
110
-
111
- #
112
- # @return [Array<Hash>]
113
- #
114
- def emitters
115
- @emitters ||= data[:emitters]
116
- end
117
-
118
- #
119
- # @return [Array<Hash>]
120
- #
121
- def enrichers
122
- @enrichers ||= data[:enrichers]
123
- end
124
-
125
- #
126
- # @return [Integer, nil]
127
- #
128
- def artifact_lifetime
129
- @artifact_lifetime ||= data[:artifact_lifetime] || data[:artifact_ttl]
130
- end
131
-
132
- #
133
- # @return [Mihari::Rule]
134
- #
135
- def model
136
- rule = Mihari::Rule.find(id)
137
-
138
- rule.title = title
139
- rule.description = description
140
- rule.data = data
141
-
142
- rule
143
- rescue ActiveRecord::RecordNotFound
144
- Mihari::Rule.new(
145
- id: id,
146
- title: title,
147
- description: description,
148
- data: data
149
- )
150
- end
151
-
152
- #
153
- # @return [Mihari::Analyzers::Rule]
154
- #
155
- def analyzer
156
- Mihari::Analyzers::Rule.new self
157
- end
158
-
159
- class << self
160
- #
161
- # Load rule from YAML string
162
- #
163
- # @param [String] yaml
164
- #
165
- # @return [Mihari::Services::Rule]
166
- #
167
- def from_yaml(yaml)
168
- new YAML.safe_load(ERB.new(yaml).result, permitted_classes: [Date, Symbol])
169
- end
170
-
171
- #
172
- # @param [Mihari::Rule] model
173
- #
174
- # @return [Mihari::Services::Rule]
175
- #
176
- def from_model(model)
177
- new model.data
178
- end
179
- end
180
- end
181
- end
182
- end