mihari 5.4.0 → 5.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/frontend/package-lock.json +145 -146
  3. data/frontend/package.json +8 -8
  4. data/frontend/src/swagger.yaml +306 -272
  5. data/lib/mihari/analyzers/binaryedge.rb +4 -4
  6. data/lib/mihari/analyzers/censys.rb +2 -2
  7. data/lib/mihari/analyzers/circl.rb +2 -2
  8. data/lib/mihari/analyzers/greynoise.rb +2 -2
  9. data/lib/mihari/analyzers/hunterhow.rb +5 -5
  10. data/lib/mihari/analyzers/onyphe.rb +4 -4
  11. data/lib/mihari/analyzers/otx.rb +2 -2
  12. data/lib/mihari/analyzers/passivetotal.rb +2 -2
  13. data/lib/mihari/analyzers/pulsedive.rb +2 -2
  14. data/lib/mihari/analyzers/rule.rb +13 -12
  15. data/lib/mihari/analyzers/securitytrails.rb +2 -2
  16. data/lib/mihari/analyzers/shodan.rb +4 -4
  17. data/lib/mihari/analyzers/urlscan.rb +2 -2
  18. data/lib/mihari/analyzers/virustotal.rb +2 -2
  19. data/lib/mihari/analyzers/virustotal_intelligence.rb +2 -2
  20. data/lib/mihari/analyzers/zoomeye.rb +4 -4
  21. data/lib/mihari/cli/alert.rb +11 -0
  22. data/lib/mihari/cli/main.rb +6 -1
  23. data/lib/mihari/commands/alert.rb +42 -0
  24. data/lib/mihari/commands/rule.rb +2 -2
  25. data/lib/mihari/commands/search.rb +20 -59
  26. data/lib/mihari/config.rb +2 -2
  27. data/lib/mihari/emitters/base.rb +1 -1
  28. data/lib/mihari/emitters/database.rb +2 -2
  29. data/lib/mihari/errors.rb +23 -2
  30. data/lib/mihari/http.rb +7 -1
  31. data/lib/mihari/schemas/alert.rb +14 -0
  32. data/lib/mihari/services/alert_proxy.rb +106 -0
  33. data/lib/mihari/services/alert_runner.rb +22 -0
  34. data/lib/mihari/services/{rule.rb → rule_proxy.rb} +10 -6
  35. data/lib/mihari/services/rule_runner.rb +49 -0
  36. data/lib/mihari/version.rb +1 -1
  37. data/lib/mihari/web/endpoints/alerts.rb +22 -0
  38. data/lib/mihari/web/endpoints/rules.rb +8 -8
  39. data/lib/mihari/web/public/assets/{index-61dc587c.js → index-4d7eda9f.js} +1 -1
  40. data/lib/mihari/web/public/index.html +1 -1
  41. data/lib/mihari/web/public/redoc-static.html +29 -27
  42. data/lib/mihari.rb +6 -1
  43. data/mihari.gemspec +2 -3
  44. metadata +14 -23
  45. data/Steepfile +0 -31
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Services
5
+ class AlertProxy
6
+ # @return [Hash]
7
+ attr_reader :data
8
+
9
+ # @return [Array, nil]
10
+ attr_reader :errors
11
+
12
+ #
13
+ # Initialize
14
+ #
15
+ # @param [Hash] data
16
+ #
17
+ def initialize(data)
18
+ @data = data.deep_symbolize_keys
19
+
20
+ @errors = nil
21
+
22
+ validate
23
+ end
24
+
25
+ #
26
+ # @return [Boolean]
27
+ #
28
+ def errors?
29
+ return false if @errors.nil?
30
+
31
+ !@errors.empty?
32
+ end
33
+
34
+ def validate
35
+ contract = Schemas::AlertContract.new
36
+ result = contract.call(data)
37
+
38
+ @data = result.to_h
39
+ @errors = result.errors
40
+ end
41
+
42
+ def validate!
43
+ return unless errors?
44
+
45
+ Mihari.logger.error "Failed to parse the input as an alert:"
46
+ Mihari.logger.error JSON.pretty_generate(errors.to_h)
47
+
48
+ raise AlertValidationError, errors
49
+ end
50
+
51
+ def [](key)
52
+ data key.to_sym
53
+ end
54
+
55
+ #
56
+ # @return [String]
57
+ #
58
+ def rule_id
59
+ @rule_id ||= data[:rule_id]
60
+ end
61
+
62
+ #
63
+ # @return [Array<Mihari::Artifact>]
64
+ #
65
+ def artifacts
66
+ @artifacts ||= data[:artifacts].map do |data|
67
+ artifact = Artifact.new(data: data)
68
+ artifact.rule_id = rule_id
69
+ artifact
70
+ end.uniq(&:data).select(&:valid?)
71
+ end
72
+
73
+ #
74
+ # @return [Mihari::Services::RuleProxy]
75
+ #
76
+ def rule
77
+ @rule ||= Services::RuleProxy.from_model(Mihari::Rule.find(rule_id))
78
+ end
79
+
80
+ class << self
81
+ #
82
+ # Load rule from YAML string
83
+ #
84
+ # @param [String] yaml
85
+ #
86
+ # @return [Mihari::Services::Alert]
87
+ #
88
+ def from_yaml(yaml)
89
+ Services::AlertProxy.new YAML.safe_load(yaml, permitted_classes: [Date, Symbol])
90
+ rescue Psych::SyntaxError => e
91
+ raise YAMLSyntaxError, e.message
92
+ end
93
+
94
+ # @param [String] path
95
+ #
96
+ # @return [Mihari::Services::Alert, nil]
97
+ #
98
+ def from_path(path)
99
+ return nil unless Pathname(path).exist?
100
+
101
+ from_yaml File.read(path)
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Services
5
+ class AlertRunner
6
+ # @return [Mihari::Services::AlertProxy]
7
+ attr_reader :alert
8
+
9
+ def initialize(alert)
10
+ @alert = alert
11
+ end
12
+
13
+ #
14
+ # @return [Mihari::Alert]
15
+ #
16
+ def run
17
+ emitter = Mihari::Emitters::Database.new(artifacts: alert.artifacts, rule: alert.rule)
18
+ emitter.emit
19
+ end
20
+ end
21
+ end
22
+ end
@@ -9,7 +9,11 @@ require "yaml"
9
9
 
10
10
  module Mihari
11
11
  module Services
12
- class Rule
12
+ #
13
+ # proxy (or converter) class for rule
14
+ # proxying rule schema data into analyzer & model
15
+ #
16
+ class RuleProxy
13
17
  include Mixins::FalsePositive
14
18
 
15
19
  # @return [Hash]
@@ -141,7 +145,7 @@ module Mihari
141
145
  #
142
146
  # @return [Mihari::Rule]
143
147
  #
144
- def to_model
148
+ def model
145
149
  rule = Mihari::Rule.find(id)
146
150
 
147
151
  rule.title = title
@@ -161,7 +165,7 @@ module Mihari
161
165
  #
162
166
  # @return [Mihari::Analyzers::Rule]
163
167
  #
164
- def to_analyzer
168
+ def analyzer
165
169
  Mihari::Analyzers::Rule.new self
166
170
  end
167
171
 
@@ -174,7 +178,7 @@ module Mihari
174
178
  # @return [Mihari::Services::Rule]
175
179
  #
176
180
  def from_yaml(yaml)
177
- Services::Rule.new YAML.safe_load(ERB.new(yaml).result, permitted_classes: [Date, Symbol])
181
+ Services::RuleProxy.new YAML.safe_load(ERB.new(yaml).result, permitted_classes: [Date, Symbol])
178
182
  rescue Psych::SyntaxError => e
179
183
  raise YAMLSyntaxError, e.message
180
184
  end
@@ -185,7 +189,7 @@ module Mihari
185
189
  # @return [Mihari::Services::Rule]
186
190
  #
187
191
  def from_model(model)
188
- Services::Rule.new model.data
192
+ Services::RuleProxy.new model.data
189
193
  end
190
194
 
191
195
  #
@@ -211,7 +215,7 @@ module Mihari
211
215
  def from_id(id)
212
216
  return nil unless Mihari::Rule.exists?(id)
213
217
 
214
- Services::Rule.from_model Mihari::Rule.find(id)
218
+ Services::RuleProxy.from_model Mihari::Rule.find(id)
215
219
  end
216
220
 
217
221
  #
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Services
5
+ class RuleRunner
6
+ include Mixins::ErrorNotification
7
+
8
+ # @return [Mihari::Services::RuleProxy]
9
+ attr_reader :rule
10
+
11
+ # @return [Boolean]
12
+ attr_reader :force_overwrite
13
+
14
+ def initialize(rule, force_overwrite:)
15
+ @rule = rule
16
+ @force_overwrite = force_overwrite
17
+ end
18
+
19
+ def force_overwrite?
20
+ force_overwrite
21
+ end
22
+
23
+ #
24
+ # @return [Boolean]
25
+ #
26
+ def diff?
27
+ model = Mihari::Rule.find(rule.id)
28
+ model.data != rule.data.deep_stringify_keys
29
+ rescue ActiveRecord::RecordNotFound
30
+ false
31
+ end
32
+
33
+ def update_or_create
34
+ rule.model.save
35
+ end
36
+
37
+ #
38
+ # @return [Mihari::Alert, nil]
39
+ #
40
+ def run
41
+ analyzer = rule.analyzer
42
+
43
+ with_error_notification do
44
+ analyzer.run
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- VERSION = "5.4.0"
4
+ VERSION = "5.4.2"
5
5
  end
@@ -67,6 +67,28 @@ module Mihari
67
67
  status 204
68
68
  present({ message: "" }, with: Entities::Message)
69
69
  end
70
+
71
+ desc "Create an alert", {
72
+ success: Entities::Alert,
73
+ summary: "Create an alert"
74
+ }
75
+ params do
76
+ requires :ruleId, type: String, documentation: { param_type: "body" }
77
+ requires :artifacts, type: Array, documentation: { type: String, is_array: true, param_type: "body" }
78
+ end
79
+ post "/" do
80
+ proxy = Services::AlertProxy.new(params.to_snake_keys)
81
+ runner = Services::AlertRunner.new(proxy)
82
+
83
+ begin
84
+ alert = runner.run
85
+ rescue ActiveRecord::RecordNotFound
86
+ error!({ message: "Rule:#{params["ruleId"]} is not found" }, 404)
87
+ end
88
+
89
+ status 201
90
+ present alert, with: Entities::Alert
91
+ end
70
92
  end
71
93
  end
72
94
  end
@@ -83,12 +83,12 @@ module Mihari
83
83
  id = params["id"].to_s
84
84
 
85
85
  begin
86
- rule = Mihari::Services::Rule.from_model(Mihari::Rule.find(id))
86
+ rule = Mihari::Services::RuleProxy.from_model(Mihari::Rule.find(id))
87
87
  rescue ActiveRecord::RecordNotFound
88
88
  error!({ message: "ID:#{id} is not found" }, 404)
89
89
  end
90
90
 
91
- analyzer = rule.to_analyzer
91
+ analyzer = rule.analyzer
92
92
  analyzer.run
93
93
 
94
94
  status 201
@@ -106,7 +106,7 @@ module Mihari
106
106
  yaml = params[:yaml]
107
107
 
108
108
  begin
109
- rule = Services::Rule.from_yaml(yaml)
109
+ rule = Services::RuleProxy.from_yaml(yaml)
110
110
  rescue YAMLSyntaxError => e
111
111
  error!({ message: e.message }, 400)
112
112
  end
@@ -129,13 +129,13 @@ module Mihari
129
129
  end
130
130
 
131
131
  begin
132
- rule.to_model.save
132
+ rule.model.save
133
133
  rescue ActiveRecord::RecordNotUnique
134
134
  error!({ message: "ID:#{rule.id} is already registered" }, 400)
135
135
  end
136
136
 
137
137
  status 201
138
- present rule.to_model, with: Entities::Rule
138
+ present rule.model, with: Entities::Rule
139
139
  end
140
140
 
141
141
  desc "Update a rule", {
@@ -157,7 +157,7 @@ module Mihari
157
157
  end
158
158
 
159
159
  begin
160
- rule = Services::Rule.from_yaml(yaml)
160
+ rule = Services::RuleProxy.from_yaml(yaml)
161
161
  rescue YAMLSyntaxError => e
162
162
  error!({ message: e.message }, 400)
163
163
  end
@@ -172,13 +172,13 @@ module Mihari
172
172
  end
173
173
 
174
174
  begin
175
- rule.to_model.save
175
+ rule.model.save
176
176
  rescue ActiveRecord::RecordNotUnique
177
177
  error!({ message: "ID:#{id} is already registered" }, 400)
178
178
  end
179
179
 
180
180
  status 201
181
- present rule.to_model, with: Entities::Rule
181
+ present rule.model, with: Entities::Rule
182
182
  end
183
183
 
184
184
  desc "Delete a rule", {
@@ -938,7 +938,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
938
938
  .ace-tm .ace_indent-guide-active {
939
939
  background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAZSURBVHjaYvj///9/hivKyv8BAAAA//8DACLqBhbvk+/eAAAAAElFTkSuQmCC") right repeat-y;
940
940
  }
941
- `}),ace.define("ace/theme/textmate",["require","exports","module","ace/theme/textmate-css","ace/lib/dom"],function(n,r,A){r.isDark=!1,r.cssClass="ace-tm",r.cssText=n("./textmate-css"),r.$id="ace/theme/textmate";var S=n("../lib/dom");S.importCssString(r.cssText,r.cssClass,!1)}),ace.define("ace/config",["require","exports","module","ace/lib/lang","ace/lib/net","ace/lib/dom","ace/lib/app_config","ace/theme/textmate"],function(n,r,A){"no use strict";var S=n("./lib/lang"),E=n("./lib/net"),T=n("./lib/dom"),c=n("./lib/app_config").AppConfig;A.exports=r=new c;var C={packaged:!1,workerPath:null,modePath:null,themePath:null,basePath:"",suffix:".js",$moduleUrls:{},loadWorkerFromBlob:!0,sharedPopups:!1,useStrictCSP:null};r.get=function(l){if(!C.hasOwnProperty(l))throw new Error("Unknown config key: "+l);return C[l]},r.set=function(l,f){if(C.hasOwnProperty(l))C[l]=f;else if(this.setDefaultValue("",l,f)==!1)throw new Error("Unknown config key: "+l);l=="useStrictCSP"&&T.useStrictCSP(f)},r.all=function(){return S.copyObject(C)},r.$modes={},r.moduleUrl=function(l,f){if(C.$moduleUrls[l])return C.$moduleUrls[l];var R=l.split("/");f=f||R[R.length-2]||"";var x=f=="snippets"?"/":"-",L=R[R.length-1];if(f=="worker"&&x=="-"){var M=new RegExp("^"+f+"[\\-_]|[\\-_]"+f+"$","g");L=L.replace(M,"")}(!L||L==f)&&R.length>1&&(L=R[R.length-2]);var V=C[f+"Path"];return V==null?V=C.basePath:x=="/"&&(f=x=""),V&&V.slice(-1)!="/"&&(V+="/"),V+f+x+L+this.get("suffix")},r.setModuleUrl=function(l,f){return C.$moduleUrls[l]=f};var o=function(l,f){if(l==="ace/theme/textmate"||l==="./theme/textmate")return f(null,n("./theme/textmate"));if(a)return a(l,f);console.error("loader is not configured")},a;r.setLoader=function(l){a=l},r.dynamicModules=Object.create(null),r.$loading={},r.$loaded={},r.loadModule=function(l,f){var R,x;Array.isArray(l)&&(x=l[0],l=l[1]);var L=function(M){if(M&&!r.$loading[l])return f&&f(M);if(r.$loading[l]||(r.$loading[l]=[]),r.$loading[l].push(f),!(r.$loading[l].length>1)){var V=function(){o(l,function(D,F){F&&(r.$loaded[l]=F),r._emit("load.module",{name:l,module:F});var P=r.$loading[l];r.$loading[l]=null,P.forEach(function(X){X&&X(F)})})};if(!r.get("packaged"))return V();E.loadScript(r.moduleUrl(l,x),V),$()}};if(r.dynamicModules[l])r.dynamicModules[l]().then(function(M){M.default?L(M.default):L(M)});else{try{R=this.$require(l)}catch{}L(R||r.$loaded[l])}},r.$require=function(l){if(typeof A.require=="function"){var f="require";return A[f](l)}},r.setModuleLoader=function(l,f){r.dynamicModules[l]=f};var $=function(){!C.basePath&&!C.workerPath&&!C.modePath&&!C.themePath&&!Object.keys(C.$moduleUrls).length&&(console.error("Unable to infer path to ace from script src,","use ace.config.set('basePath', 'path') to enable dynamic loading of modes and themes","or with webpack use ace/webpack-resolver"),$=function(){})};r.version="1.24.0"}),ace.define("ace/loader_build",["require","exports","module","ace/lib/fixoldbrowsers","ace/config"],function(n,r,A){n("./lib/fixoldbrowsers");var S=n("./config");S.setLoader(function(C,o){n([C],function(a){o(null,a)})});var E=function(){return this||typeof window<"u"&&window}();A.exports=function(C){S.init=T,S.$require=n,C.require=n},T(!0);function T(C){if(!(!E||!E.document)){S.set("packaged",C||n.packaged||A.packaged||E.define&&(void 0).packaged);var o={},a="",$=document.currentScript||document._currentScript,l=$&&$.ownerDocument||document;$&&$.src&&(a=$.src.split(/[?#]/)[0].split("/").slice(0,-1).join("/")||"");for(var f=l.getElementsByTagName("script"),R=0;R<f.length;R++){var x=f[R],L=x.src||x.getAttribute("src");if(L){for(var M=x.attributes,V=0,D=M.length;V<D;V++){var F=M[V];F.name.indexOf("data-ace-")===0&&(o[c(F.name.replace(/^data-ace-/,""))]=F.value)}var P=L.match(/^(.*)\/ace([\-.]\w+)?\.js(\?|$)/);P&&(a=P[1])}}a&&(o.base=o.base||a,o.packaged=!0),o.basePath=o.base,o.workerPath=o.workerPath||o.base,o.modePath=o.modePath||o.base,o.themePath=o.themePath||o.base,delete o.base;for(var X in o)typeof o[X]<"u"&&S.set(X,o[X])}}function c(C){return C.replace(/-(.)/g,function(o,a){return a.toUpperCase()})}}),ace.define("ace/range",["require","exports","module"],function(n,r,A){var S=function(T,c){return T.row-c.row||T.column-c.column},E=function(){function T(c,C,o,a){this.start={row:c,column:C},this.end={row:o,column:a}}return T.prototype.isEqual=function(c){return this.start.row===c.start.row&&this.end.row===c.end.row&&this.start.column===c.start.column&&this.end.column===c.end.column},T.prototype.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},T.prototype.contains=function(c,C){return this.compare(c,C)==0},T.prototype.compareRange=function(c){var C,o=c.end,a=c.start;return C=this.compare(o.row,o.column),C==1?(C=this.compare(a.row,a.column),C==1?2:C==0?1:0):C==-1?-2:(C=this.compare(a.row,a.column),C==-1?-1:C==1?42:0)},T.prototype.comparePoint=function(c){return this.compare(c.row,c.column)},T.prototype.containsRange=function(c){return this.comparePoint(c.start)==0&&this.comparePoint(c.end)==0},T.prototype.intersects=function(c){var C=this.compareRange(c);return C==-1||C==0||C==1},T.prototype.isEnd=function(c,C){return this.end.row==c&&this.end.column==C},T.prototype.isStart=function(c,C){return this.start.row==c&&this.start.column==C},T.prototype.setStart=function(c,C){typeof c=="object"?(this.start.column=c.column,this.start.row=c.row):(this.start.row=c,this.start.column=C)},T.prototype.setEnd=function(c,C){typeof c=="object"?(this.end.column=c.column,this.end.row=c.row):(this.end.row=c,this.end.column=C)},T.prototype.inside=function(c,C){return this.compare(c,C)==0?!(this.isEnd(c,C)||this.isStart(c,C)):!1},T.prototype.insideStart=function(c,C){return this.compare(c,C)==0?!this.isEnd(c,C):!1},T.prototype.insideEnd=function(c,C){return this.compare(c,C)==0?!this.isStart(c,C):!1},T.prototype.compare=function(c,C){return!this.isMultiLine()&&c===this.start.row?C<this.start.column?-1:C>this.end.column?1:0:c<this.start.row?-1:c>this.end.row?1:this.start.row===c?C>=this.start.column?0:-1:this.end.row===c?C<=this.end.column?0:1:0},T.prototype.compareStart=function(c,C){return this.start.row==c&&this.start.column==C?-1:this.compare(c,C)},T.prototype.compareEnd=function(c,C){return this.end.row==c&&this.end.column==C?1:this.compare(c,C)},T.prototype.compareInside=function(c,C){return this.end.row==c&&this.end.column==C?1:this.start.row==c&&this.start.column==C?-1:this.compare(c,C)},T.prototype.clipRows=function(c,C){if(this.end.row>C)var o={row:C+1,column:0};else if(this.end.row<c)var o={row:c,column:0};if(this.start.row>C)var a={row:C+1,column:0};else if(this.start.row<c)var a={row:c,column:0};return T.fromPoints(a||this.start,o||this.end)},T.prototype.extend=function(c,C){var o=this.compare(c,C);if(o==0)return this;if(o==-1)var a={row:c,column:C};else var $={row:c,column:C};return T.fromPoints(a||this.start,$||this.end)},T.prototype.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},T.prototype.isMultiLine=function(){return this.start.row!==this.end.row},T.prototype.clone=function(){return T.fromPoints(this.start,this.end)},T.prototype.collapseRows=function(){return this.end.column==0?new T(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new T(this.start.row,0,this.end.row,0)},T.prototype.toScreenRange=function(c){var C=c.documentToScreenPosition(this.start),o=c.documentToScreenPosition(this.end);return new T(C.row,C.column,o.row,o.column)},T.prototype.moveBy=function(c,C){this.start.row+=c,this.start.column+=C,this.end.row+=c,this.end.column+=C},T}();E.fromPoints=function(T,c){return new E(T.row,T.column,c.row,c.column)},E.comparePoints=S,E.comparePoints=function(T,c){return T.row-c.row||T.column-c.column},r.Range=E}),ace.define("ace/lib/keys",["require","exports","module","ace/lib/oop"],function(n,r,A){/*! @license
941
+ `}),ace.define("ace/theme/textmate",["require","exports","module","ace/theme/textmate-css","ace/lib/dom"],function(n,r,A){r.isDark=!1,r.cssClass="ace-tm",r.cssText=n("./textmate-css"),r.$id="ace/theme/textmate";var S=n("../lib/dom");S.importCssString(r.cssText,r.cssClass,!1)}),ace.define("ace/config",["require","exports","module","ace/lib/lang","ace/lib/net","ace/lib/dom","ace/lib/app_config","ace/theme/textmate"],function(n,r,A){"no use strict";var S=n("./lib/lang"),E=n("./lib/net"),T=n("./lib/dom"),c=n("./lib/app_config").AppConfig;A.exports=r=new c;var C={packaged:!1,workerPath:null,modePath:null,themePath:null,basePath:"",suffix:".js",$moduleUrls:{},loadWorkerFromBlob:!0,sharedPopups:!1,useStrictCSP:null};r.get=function(l){if(!C.hasOwnProperty(l))throw new Error("Unknown config key: "+l);return C[l]},r.set=function(l,f){if(C.hasOwnProperty(l))C[l]=f;else if(this.setDefaultValue("",l,f)==!1)throw new Error("Unknown config key: "+l);l=="useStrictCSP"&&T.useStrictCSP(f)},r.all=function(){return S.copyObject(C)},r.$modes={},r.moduleUrl=function(l,f){if(C.$moduleUrls[l])return C.$moduleUrls[l];var R=l.split("/");f=f||R[R.length-2]||"";var x=f=="snippets"?"/":"-",L=R[R.length-1];if(f=="worker"&&x=="-"){var M=new RegExp("^"+f+"[\\-_]|[\\-_]"+f+"$","g");L=L.replace(M,"")}(!L||L==f)&&R.length>1&&(L=R[R.length-2]);var V=C[f+"Path"];return V==null?V=C.basePath:x=="/"&&(f=x=""),V&&V.slice(-1)!="/"&&(V+="/"),V+f+x+L+this.get("suffix")},r.setModuleUrl=function(l,f){return C.$moduleUrls[l]=f};var o=function(l,f){if(l==="ace/theme/textmate"||l==="./theme/textmate")return f(null,n("./theme/textmate"));if(a)return a(l,f);console.error("loader is not configured")},a;r.setLoader=function(l){a=l},r.dynamicModules=Object.create(null),r.$loading={},r.$loaded={},r.loadModule=function(l,f){var R,x;Array.isArray(l)&&(x=l[0],l=l[1]);var L=function(M){if(M&&!r.$loading[l])return f&&f(M);if(r.$loading[l]||(r.$loading[l]=[]),r.$loading[l].push(f),!(r.$loading[l].length>1)){var V=function(){o(l,function(D,F){F&&(r.$loaded[l]=F),r._emit("load.module",{name:l,module:F});var P=r.$loading[l];r.$loading[l]=null,P.forEach(function(X){X&&X(F)})})};if(!r.get("packaged"))return V();E.loadScript(r.moduleUrl(l,x),V),$()}};if(r.dynamicModules[l])r.dynamicModules[l]().then(function(M){M.default?L(M.default):L(M)});else{try{R=this.$require(l)}catch{}L(R||r.$loaded[l])}},r.$require=function(l){if(typeof A.require=="function"){var f="require";return A[f](l)}},r.setModuleLoader=function(l,f){r.dynamicModules[l]=f};var $=function(){!C.basePath&&!C.workerPath&&!C.modePath&&!C.themePath&&!Object.keys(C.$moduleUrls).length&&(console.error("Unable to infer path to ace from script src,","use ace.config.set('basePath', 'path') to enable dynamic loading of modes and themes","or with webpack use ace/webpack-resolver"),$=function(){})};r.version="1.24.1"}),ace.define("ace/loader_build",["require","exports","module","ace/lib/fixoldbrowsers","ace/config"],function(n,r,A){n("./lib/fixoldbrowsers");var S=n("./config");S.setLoader(function(C,o){n([C],function(a){o(null,a)})});var E=function(){return this||typeof window<"u"&&window}();A.exports=function(C){S.init=T,S.$require=n,C.require=n},T(!0);function T(C){if(!(!E||!E.document)){S.set("packaged",C||n.packaged||A.packaged||E.define&&(void 0).packaged);var o={},a="",$=document.currentScript||document._currentScript,l=$&&$.ownerDocument||document;$&&$.src&&(a=$.src.split(/[?#]/)[0].split("/").slice(0,-1).join("/")||"");for(var f=l.getElementsByTagName("script"),R=0;R<f.length;R++){var x=f[R],L=x.src||x.getAttribute("src");if(L){for(var M=x.attributes,V=0,D=M.length;V<D;V++){var F=M[V];F.name.indexOf("data-ace-")===0&&(o[c(F.name.replace(/^data-ace-/,""))]=F.value)}var P=L.match(/^(.*)\/ace([\-.]\w+)?\.js(\?|$)/);P&&(a=P[1])}}a&&(o.base=o.base||a,o.packaged=!0),o.basePath=o.base,o.workerPath=o.workerPath||o.base,o.modePath=o.modePath||o.base,o.themePath=o.themePath||o.base,delete o.base;for(var X in o)typeof o[X]<"u"&&S.set(X,o[X])}}function c(C){return C.replace(/-(.)/g,function(o,a){return a.toUpperCase()})}}),ace.define("ace/range",["require","exports","module"],function(n,r,A){var S=function(T,c){return T.row-c.row||T.column-c.column},E=function(){function T(c,C,o,a){this.start={row:c,column:C},this.end={row:o,column:a}}return T.prototype.isEqual=function(c){return this.start.row===c.start.row&&this.end.row===c.end.row&&this.start.column===c.start.column&&this.end.column===c.end.column},T.prototype.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},T.prototype.contains=function(c,C){return this.compare(c,C)==0},T.prototype.compareRange=function(c){var C,o=c.end,a=c.start;return C=this.compare(o.row,o.column),C==1?(C=this.compare(a.row,a.column),C==1?2:C==0?1:0):C==-1?-2:(C=this.compare(a.row,a.column),C==-1?-1:C==1?42:0)},T.prototype.comparePoint=function(c){return this.compare(c.row,c.column)},T.prototype.containsRange=function(c){return this.comparePoint(c.start)==0&&this.comparePoint(c.end)==0},T.prototype.intersects=function(c){var C=this.compareRange(c);return C==-1||C==0||C==1},T.prototype.isEnd=function(c,C){return this.end.row==c&&this.end.column==C},T.prototype.isStart=function(c,C){return this.start.row==c&&this.start.column==C},T.prototype.setStart=function(c,C){typeof c=="object"?(this.start.column=c.column,this.start.row=c.row):(this.start.row=c,this.start.column=C)},T.prototype.setEnd=function(c,C){typeof c=="object"?(this.end.column=c.column,this.end.row=c.row):(this.end.row=c,this.end.column=C)},T.prototype.inside=function(c,C){return this.compare(c,C)==0?!(this.isEnd(c,C)||this.isStart(c,C)):!1},T.prototype.insideStart=function(c,C){return this.compare(c,C)==0?!this.isEnd(c,C):!1},T.prototype.insideEnd=function(c,C){return this.compare(c,C)==0?!this.isStart(c,C):!1},T.prototype.compare=function(c,C){return!this.isMultiLine()&&c===this.start.row?C<this.start.column?-1:C>this.end.column?1:0:c<this.start.row?-1:c>this.end.row?1:this.start.row===c?C>=this.start.column?0:-1:this.end.row===c?C<=this.end.column?0:1:0},T.prototype.compareStart=function(c,C){return this.start.row==c&&this.start.column==C?-1:this.compare(c,C)},T.prototype.compareEnd=function(c,C){return this.end.row==c&&this.end.column==C?1:this.compare(c,C)},T.prototype.compareInside=function(c,C){return this.end.row==c&&this.end.column==C?1:this.start.row==c&&this.start.column==C?-1:this.compare(c,C)},T.prototype.clipRows=function(c,C){if(this.end.row>C)var o={row:C+1,column:0};else if(this.end.row<c)var o={row:c,column:0};if(this.start.row>C)var a={row:C+1,column:0};else if(this.start.row<c)var a={row:c,column:0};return T.fromPoints(a||this.start,o||this.end)},T.prototype.extend=function(c,C){var o=this.compare(c,C);if(o==0)return this;if(o==-1)var a={row:c,column:C};else var $={row:c,column:C};return T.fromPoints(a||this.start,$||this.end)},T.prototype.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},T.prototype.isMultiLine=function(){return this.start.row!==this.end.row},T.prototype.clone=function(){return T.fromPoints(this.start,this.end)},T.prototype.collapseRows=function(){return this.end.column==0?new T(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new T(this.start.row,0,this.end.row,0)},T.prototype.toScreenRange=function(c){var C=c.documentToScreenPosition(this.start),o=c.documentToScreenPosition(this.end);return new T(C.row,C.column,o.row,o.column)},T.prototype.moveBy=function(c,C){this.start.row+=c,this.start.column+=C,this.end.row+=c,this.end.column+=C},T}();E.fromPoints=function(T,c){return new E(T.row,T.column,c.row,c.column)},E.comparePoints=S,E.comparePoints=function(T,c){return T.row-c.row||T.column-c.column},r.Range=E}),ace.define("ace/lib/keys",["require","exports","module","ace/lib/oop"],function(n,r,A){/*! @license
942
942
  ==========================================================================
943
943
  SproutCore -- JavaScript Application Framework
944
944
  copyright 2006-2009, Sprout Systems Inc., Apple Inc. and contributors.
@@ -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-61dc587c.js"></script>
9
+ <script type="module" crossorigin src="/assets/index-4d7eda9f.js"></script>
10
10
  <link rel="stylesheet" href="/assets/index-33165282.css">
11
11
  </head>
12
12
  <body>