mihari 5.6.1 → 5.6.2

Sign up to get free protection for your applications and to get access to all the features.
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