sqreen 1.19.0.beta1 → 1.20.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -2
- data/lib/sqreen/aggregated_metric.rb +25 -0
- data/lib/sqreen/configuration.rb +7 -3
- data/lib/sqreen/deliveries/batch.rb +4 -1
- data/lib/sqreen/deliveries/simple.rb +4 -0
- data/lib/sqreen/event.rb +7 -5
- data/lib/sqreen/events/attack.rb +23 -18
- data/lib/sqreen/events/remote_exception.rb +0 -22
- data/lib/sqreen/events/request_record.rb +15 -70
- data/lib/sqreen/frameworks/request_recorder.rb +13 -2
- data/lib/sqreen/kit/signals/specialized/aggregated_metric.rb +72 -0
- data/lib/sqreen/kit/signals/specialized/attack.rb +57 -0
- data/lib/sqreen/kit/signals/specialized/binning_metric.rb +76 -0
- data/lib/sqreen/kit/signals/specialized/http_trace.rb +26 -0
- data/lib/sqreen/kit/signals/specialized/sdk_track_call.rb +50 -0
- data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +57 -0
- data/lib/sqreen/legacy/old_event_submission_strategy.rb +221 -0
- data/lib/sqreen/legacy/waf_redactions.rb +49 -0
- data/lib/sqreen/metrics/base.rb +3 -0
- data/lib/sqreen/metrics_store.rb +22 -12
- data/lib/sqreen/performance_notifications/binned_metrics.rb +8 -2
- data/lib/sqreen/rules.rb +4 -2
- data/lib/sqreen/rules/not_found_cb.rb +2 -0
- data/lib/sqreen/rules/rule_cb.rb +2 -0
- data/lib/sqreen/rules/waf_cb.rb +39 -16
- data/lib/sqreen/runner.rb +48 -6
- data/lib/sqreen/sensitive_data_redactor.rb +19 -31
- data/lib/sqreen/session.rb +39 -37
- data/lib/sqreen/signals/conversions.rb +283 -0
- data/lib/sqreen/signals/http_trace_redaction.rb +111 -0
- data/lib/sqreen/signals/signals_submission_strategy.rb +78 -0
- data/lib/sqreen/version.rb +1 -1
- data/lib/sqreen/weave/legacy/instrumentation.rb +15 -7
- metadata +55 -14
- data/lib/sqreen/backport.rb +0 -9
- data/lib/sqreen/backport/clock_gettime.rb +0 -74
- data/lib/sqreen/backport/original_name.rb +0 -88
@@ -0,0 +1,49 @@
|
|
1
|
+
# typed: ignore
|
2
|
+
|
3
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
4
|
+
# Please refer to our terms for more information: https://www.sqreen.com/terms.html
|
5
|
+
|
6
|
+
module Sqreen
|
7
|
+
module Legacy
|
8
|
+
module WafRedactions
|
9
|
+
class << self
|
10
|
+
def redact_attacks!(attacks, values)
|
11
|
+
return attacks if values.empty?
|
12
|
+
|
13
|
+
values = values.map { |v| v.downcase if v.is_a?(String) }
|
14
|
+
|
15
|
+
attacks.each do |e|
|
16
|
+
next(e) unless e[:infos]
|
17
|
+
next(e) unless e[:infos][:waf_data]
|
18
|
+
|
19
|
+
parsed = JSON.parse(e[:infos][:waf_data])
|
20
|
+
redacted = parsed.each do |w|
|
21
|
+
next unless (filters = w['filter'])
|
22
|
+
|
23
|
+
filters.each do |f|
|
24
|
+
next unless (v = f['resolved_value'])
|
25
|
+
next unless values.include?(v.downcase)
|
26
|
+
|
27
|
+
f['match_status'] = SensitiveDataRedactor::MASK
|
28
|
+
f['resolved_value'] = SensitiveDataRedactor::MASK
|
29
|
+
end
|
30
|
+
end
|
31
|
+
e[:infos][:waf_data] = JSON.dump(redacted)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# see https://github.com/sqreen/TechDoc/blob/master/content/specs/spec000022-waf-data-sanitization.md#changes-to-the-agents
|
36
|
+
def redact_exceptions!(exceptions, values)
|
37
|
+
return exceptions if values.empty?
|
38
|
+
|
39
|
+
exceptions.each do |e|
|
40
|
+
next(e) unless e[:infos]
|
41
|
+
next(e) unless e[:infos][:waf]
|
42
|
+
|
43
|
+
e[:infos][:waf].delete(:args)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/sqreen/metrics/base.rb
CHANGED
data/lib/sqreen/metrics_store.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
4
4
|
# Please refer to our terms for more information: https://www.sqreen.com/terms.html
|
5
5
|
|
6
|
+
require 'sqreen/aggregated_metric'
|
6
7
|
require 'sqreen/metrics'
|
7
8
|
require 'sqreen/mono_time'
|
8
9
|
require 'sqreen/metrics_store/unknown_metric'
|
@@ -30,8 +31,9 @@ module Sqreen
|
|
30
31
|
|
31
32
|
# Definition contains a name,period and aggregate at least
|
32
33
|
# @param definition [Hash] a metric definition
|
34
|
+
# @param rule [RuleCB] the rule associated with this metric, if any
|
33
35
|
# @param mklass [Object] Override metric object (used in testing)
|
34
|
-
def create_metric(definition, mklass = nil)
|
36
|
+
def create_metric(definition, rule = nil, mklass = nil)
|
35
37
|
name = definition[NAME_KEY]
|
36
38
|
kind = definition[KIND_KEY]
|
37
39
|
klass = valid_metric(kind, name)
|
@@ -43,6 +45,9 @@ module Sqreen
|
|
43
45
|
definition[PERIOD_KEY],
|
44
46
|
nil # Start
|
45
47
|
]
|
48
|
+
metric.name = name
|
49
|
+
metric.rule = rule
|
50
|
+
metric.period = definition[PERIOD_KEY]
|
46
51
|
metric
|
47
52
|
end
|
48
53
|
|
@@ -50,7 +55,7 @@ module Sqreen
|
|
50
55
|
@metrics.key?(name)
|
51
56
|
end
|
52
57
|
|
53
|
-
# @
|
58
|
+
# @param at [Time] when is the store emptied
|
54
59
|
def update(name, at, key, value)
|
55
60
|
metric, period, start = @metrics[name]
|
56
61
|
raise UnregisteredMetric, "Unknown metric #{name}" unless metric
|
@@ -59,7 +64,7 @@ module Sqreen
|
|
59
64
|
end
|
60
65
|
|
61
66
|
# Drains every metrics and returns the store content
|
62
|
-
# @
|
67
|
+
# @param at [Time] when is the store emptied
|
63
68
|
def publish(flush = true, at = Sqreen.time)
|
64
69
|
@metrics.each do |name, (_, period, start)|
|
65
70
|
next_sample(name, at) if flush || !start.nil? && (start + period) < at
|
@@ -75,15 +80,20 @@ module Sqreen
|
|
75
80
|
metric = @metrics[name][0]
|
76
81
|
r = metric.next_sample(at)
|
77
82
|
@metrics[name][2] = at # new start
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
83
|
+
return unless r
|
84
|
+
|
85
|
+
r[NAME_KEY] = name
|
86
|
+
obs = r[Metric::OBSERVATION_KEY]
|
87
|
+
return unless obs && (!obs.respond_to?(:empty?) || !obs.empty?)
|
88
|
+
start_of_mono = Time.now.utc - Sqreen.time
|
89
|
+
|
90
|
+
agg = AggregatedMetric.new
|
91
|
+
agg.metric = metric
|
92
|
+
agg.rule = agg.metric.rule
|
93
|
+
agg.start = start_of_mono + r[Metric::START_KEY]
|
94
|
+
agg.finish = start_of_mono + r[Metric::FINISH_KEY]
|
95
|
+
agg.data = obs
|
96
|
+
@store << agg
|
87
97
|
end
|
88
98
|
|
89
99
|
def valid_metric(kind, name)
|
@@ -122,10 +122,16 @@ module Sqreen
|
|
122
122
|
attr_reader :metrics_store
|
123
123
|
attr_reader :period
|
124
124
|
|
125
|
-
def ensure_metric(metric_name)
|
125
|
+
def ensure_metric(metric_name, rule = nil)
|
126
126
|
return if metrics_store.metric?(metric_name)
|
127
127
|
metrics_store.create_metric(
|
128
|
-
|
128
|
+
{
|
129
|
+
'name' => metric_name,
|
130
|
+
'period' => period,
|
131
|
+
'kind' => 'Binning',
|
132
|
+
'options' => @perf_metric_opts,
|
133
|
+
},
|
134
|
+
rule
|
129
135
|
)
|
130
136
|
end
|
131
137
|
|
data/lib/sqreen/rules.rb
CHANGED
@@ -135,13 +135,15 @@ module Sqreen
|
|
135
135
|
return nil
|
136
136
|
end
|
137
137
|
|
138
|
+
rule_cb = cb_class.new(instr_class, instr_method, hash_rule)
|
139
|
+
|
138
140
|
if metrics_store
|
139
141
|
(hash_rule[Attrs::METRICS] || []).each do |metric|
|
140
|
-
metrics_store.create_metric(metric)
|
142
|
+
metrics_store.create_metric(metric, rule_cb)
|
141
143
|
end
|
142
144
|
end
|
143
145
|
|
144
|
-
|
146
|
+
rule_cb
|
145
147
|
rescue => e
|
146
148
|
rule_name = nil
|
147
149
|
rulespack_id = nil
|
data/lib/sqreen/rules/rule_cb.rb
CHANGED
@@ -61,7 +61,9 @@ module Sqreen
|
|
61
61
|
:infos => infos,
|
62
62
|
:rulespack_id => rulespack_id,
|
63
63
|
:rule_name => rule_name,
|
64
|
+
:attack_type => @rule['attack_type'], # for signal
|
64
65
|
:test => test,
|
66
|
+
:block => @rule['block'], # for signal
|
65
67
|
:time => at,
|
66
68
|
}
|
67
69
|
if payload_tpl.include?('context')
|
data/lib/sqreen/rules/waf_cb.rb
CHANGED
@@ -11,11 +11,15 @@ require 'sqreen/safe_json'
|
|
11
11
|
require 'sqreen/exception'
|
12
12
|
require 'sqreen/util/capper'
|
13
13
|
require 'sqreen/dependency/libsqreen'
|
14
|
+
require 'sqreen/encoding_sanitizer'
|
14
15
|
|
15
16
|
module Sqreen
|
16
17
|
module Rules
|
17
18
|
class WAFCB < RuleCB
|
18
|
-
|
19
|
+
# 2^30 -1 or 2^62 -1
|
20
|
+
MAX_FIXNUM = 1.size == 4 ? 1_073_741_823 : 4_611_686_018_427_387_903
|
21
|
+
# will be converted to a long, so better not to overflow
|
22
|
+
INFINITE_BUDGET_US = MAX_FIXNUM
|
19
23
|
|
20
24
|
def self.libsqreen?
|
21
25
|
Sqreen::Dependency::LibSqreen.required?
|
@@ -25,7 +29,7 @@ module Sqreen
|
|
25
29
|
Sqreen::Dependency.const_exist?('LibSqreen::WAF')
|
26
30
|
end
|
27
31
|
|
28
|
-
attr_reader :binding_accessors, :
|
32
|
+
attr_reader :binding_accessors, :max_run_budget_us, :waf_rule_name
|
29
33
|
|
30
34
|
def initialize(*args)
|
31
35
|
super(*args)
|
@@ -54,8 +58,12 @@ module Sqreen
|
|
54
58
|
@binding_accessors = @data['values'].fetch('binding_accessors', []).each_with_object({}) do |e, h|
|
55
59
|
h[e] = BindingAccessor.new(e)
|
56
60
|
end
|
57
|
-
|
58
|
-
|
61
|
+
|
62
|
+
# 0 for using defaults (PW_RUN_TIMEOUT)
|
63
|
+
@max_run_budget_us = (@data['values'].fetch('budget_in_ms', 0) * 1000).to_i
|
64
|
+
@max_run_budget_us = INFINITE_BUDGET_US if @max_run_budget_us >= INFINITE_BUDGET_US
|
65
|
+
|
66
|
+
Sqreen.log.debug { "Max WAF run budget for #{@waf_rule_name} set to #{@max_run_budget_us} us" }
|
59
67
|
|
60
68
|
ObjectSpace.define_finalizer(self, WAFCB.finalizer(@waf_rule_name.dup))
|
61
69
|
end
|
@@ -68,20 +76,32 @@ module Sqreen
|
|
68
76
|
|
69
77
|
env = [binding, framework, instance, args]
|
70
78
|
|
79
|
+
start = Sqreen.time if budget
|
80
|
+
|
71
81
|
capper = Sqreen::Util::Capper.new(string_size_cap: 4096, size_cap: 150, depth_cap: 10)
|
72
82
|
waf_args = binding_accessors.each_with_object({}) do |(e, b), h|
|
73
83
|
h[e] = capper.call(b.resolve(*env))
|
74
84
|
end
|
75
85
|
waf_args = Sqreen::EncodingSanitizer.sanitize(waf_args)
|
76
|
-
|
77
|
-
|
86
|
+
|
87
|
+
if budget
|
88
|
+
rem_budget_s = budget - (Sqreen.time - start)
|
89
|
+
return advise_action(nil) if rem_budget_s <= 0.0
|
90
|
+
|
91
|
+
waf_gen_budget_us = [(rem_budget_s * 1_000_000).to_i, MAX_FIXNUM].min
|
92
|
+
else # no budget
|
93
|
+
waf_gen_budget_us = INFINITE_BUDGET_US
|
94
|
+
end
|
95
|
+
|
96
|
+
action, data = ::LibSqreen::WAF.run(waf_rule_name, waf_args,
|
97
|
+
waf_gen_budget_us, @max_run_budget_us)
|
78
98
|
|
79
99
|
case action
|
80
100
|
when :monitor
|
81
|
-
record_event({
|
101
|
+
record_event({ waf_data: data })
|
82
102
|
advise_action(nil)
|
83
103
|
when :block
|
84
|
-
record_event({
|
104
|
+
record_event({ waf_data: data })
|
85
105
|
advise_action(:raise)
|
86
106
|
when :good
|
87
107
|
advise_action(nil)
|
@@ -112,20 +132,23 @@ module Sqreen
|
|
112
132
|
end
|
113
133
|
|
114
134
|
def record_exception(exception, infos = {}, at = Time.now.utc)
|
115
|
-
infos.merge!(
|
135
|
+
infos.merge!(waf_infos(exception)) if exception.is_a?(Sqreen::WAFError)
|
116
136
|
super(exception, infos, at)
|
117
137
|
end
|
118
138
|
|
119
139
|
private
|
120
140
|
|
121
|
-
|
141
|
+
# see https://github.com/sqreen/TechDoc/blob/master/content/specs/spec000016-waf-integration.md#error-management
|
142
|
+
def waf_infos(e)
|
122
143
|
{
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
144
|
+
waf: {
|
145
|
+
waf_rule: e.rule_name,
|
146
|
+
error_code: ERROR_CODES[e.error],
|
147
|
+
}.tap do |r|
|
148
|
+
r[:error_data] = e.data if e.data
|
149
|
+
r[:args] = e.args if e.arg
|
150
|
+
end,
|
151
|
+
}
|
129
152
|
end
|
130
153
|
|
131
154
|
ERROR_CODES = {
|
data/lib/sqreen/runner.rb
CHANGED
@@ -23,6 +23,7 @@ require 'sqreen/performance_notifications/binned_metrics'
|
|
23
23
|
require 'sqreen/legacy/instrumentation'
|
24
24
|
require 'sqreen/call_countable'
|
25
25
|
require 'sqreen/weave/legacy/instrumentation'
|
26
|
+
require 'sqreen/kit/configuration'
|
26
27
|
|
27
28
|
module Sqreen
|
28
29
|
@features = {}
|
@@ -37,6 +38,8 @@ module Sqreen
|
|
37
38
|
PERF_METRICS_PERIOD = 60 # 1 min
|
38
39
|
DEFAULT_PERF_LEVEL = 0 # disabled
|
39
40
|
|
41
|
+
DEFAULT_USE_SIGNALS = false
|
42
|
+
|
40
43
|
class << self
|
41
44
|
attr_reader :features
|
42
45
|
def update_features(features)
|
@@ -87,7 +90,9 @@ module Sqreen
|
|
87
90
|
|
88
91
|
attr_accessor :heartbeat_delay
|
89
92
|
attr_accessor :metrics_engine
|
93
|
+
# @return [Sqreen::Deliveries::Simple]
|
90
94
|
attr_reader :deliverer
|
95
|
+
# @return [Sqreen::Session]
|
91
96
|
attr_reader :session
|
92
97
|
attr_reader :instrumenter
|
93
98
|
attr_accessor :running
|
@@ -111,17 +116,26 @@ module Sqreen
|
|
111
116
|
@token = @configuration.get(:token)
|
112
117
|
@app_name = @configuration.get(:app_name)
|
113
118
|
@url = @configuration.get(:url)
|
119
|
+
@proxy_url = @configuration.get(:proxy_url)
|
114
120
|
Sqreen.update_whitelisted_paths([])
|
115
121
|
Sqreen.update_whitelisted_ips({})
|
116
122
|
Sqreen.update_performance_budget(nil)
|
117
123
|
raise(Sqreen::Exception, 'no url found') unless @url
|
118
124
|
raise(Sqreen::TokenNotFoundException, 'no token found') unless @token
|
119
125
|
|
126
|
+
Sqreen::Kit::Configuration.logger = Sqreen.log
|
127
|
+
Sqreen::Kit::Configuration.ingestion_url = @configuration.get(:ingestion_url)
|
128
|
+
Sqreen::Kit::Configuration.proxy_url = @configuration.get(:proxy_url)
|
129
|
+
|
120
130
|
register_exit_cb if set_at_exit
|
121
131
|
|
122
132
|
self.metrics_engine = MetricsStore.new
|
123
133
|
|
124
|
-
|
134
|
+
needs_weave = proc do
|
135
|
+
Gem::Specification.select { |s| s.name == 'scout_apm' && Gem::Requirement.new('>= 2.5.2').satisfied_by?(Gem::Version.new(s.version)) }.any?
|
136
|
+
end
|
137
|
+
|
138
|
+
if @configuration.get(:weave) || needs_weave.call
|
125
139
|
@instrumenter = Sqreen::Weave::Legacy::Instrumentation.new(metrics_engine)
|
126
140
|
else
|
127
141
|
@instrumenter = Sqreen::Legacy::Instrumentation.new(metrics_engine)
|
@@ -138,7 +152,7 @@ module Sqreen
|
|
138
152
|
Sqreen.log.debug do
|
139
153
|
"Override initial features with #{conf_features.inspect}"
|
140
154
|
end
|
141
|
-
wanted_features = conf_features
|
155
|
+
wanted_features = wanted_features.merge(conf_features)
|
142
156
|
rescue
|
143
157
|
Sqreen.log.warn do
|
144
158
|
"NOT using invalid inital features #{conf_initial_features}"
|
@@ -157,7 +171,7 @@ module Sqreen
|
|
157
171
|
end
|
158
172
|
|
159
173
|
def create_session(session_class)
|
160
|
-
@session = session_class.new(@url, @token, @app_name)
|
174
|
+
@session = session_class.new(@url, @token, @app_name, @proxy_url)
|
161
175
|
session.login(@framework)
|
162
176
|
end
|
163
177
|
|
@@ -166,8 +180,18 @@ module Sqreen
|
|
166
180
|
@deliverer = new_deliverer
|
167
181
|
end
|
168
182
|
|
169
|
-
def batch_events(batch_size, max_staleness = nil)
|
183
|
+
def batch_events(batch_size, max_staleness = nil, use_signals = false)
|
170
184
|
size = batch_size.to_i
|
185
|
+
|
186
|
+
if size <= 1 && use_signals
|
187
|
+
Sqreen.log.warn do
|
188
|
+
"Using signals with no delivery batching is unsupported. " \
|
189
|
+
"Using instead batching with batch size = 30, max_staleness = 60"
|
190
|
+
end
|
191
|
+
size = 30
|
192
|
+
max_staleness = 60
|
193
|
+
end
|
194
|
+
|
171
195
|
self.deliverer = if size < 1
|
172
196
|
Deliveries::Simple.new(session)
|
173
197
|
else
|
@@ -297,19 +321,37 @@ module Sqreen
|
|
297
321
|
def do_heartbeat
|
298
322
|
@last_heartbeat_request = Time.now
|
299
323
|
@next_metrics.concat(metrics_engine.publish(false)) if metrics_engine
|
300
|
-
|
324
|
+
metrics_in_hb = use_signals? ? nil : next_metrics
|
325
|
+
|
326
|
+
res = session.heartbeat(next_command_results, metrics_in_hb)
|
301
327
|
next_command_results.clear
|
328
|
+
|
329
|
+
deliver_metrics_as_event if use_signals?
|
302
330
|
next_metrics.clear
|
331
|
+
|
303
332
|
process_commands(res['commands'])
|
304
333
|
end
|
305
334
|
|
335
|
+
def deliver_metrics_as_event
|
336
|
+
# this is disastrous withe simple delivery strategy,
|
337
|
+
# as each aggregated metric would trigger an http request
|
338
|
+
# Sending of metrics is therefore not supported with simple delivery strategy
|
339
|
+
# TODO: Confirm that only batch is used in production
|
340
|
+
next_metrics.each { |x| deliverer.post_event(x) }
|
341
|
+
end
|
342
|
+
|
306
343
|
def features(_context_infos = {})
|
307
344
|
Sqreen.features
|
308
345
|
end
|
309
346
|
|
347
|
+
def use_signals?
|
348
|
+
features.fetch('use_signals', DEFAULT_USE_SIGNALS)
|
349
|
+
end
|
350
|
+
|
310
351
|
def features=(features)
|
311
352
|
Sqreen.update_features(features)
|
312
353
|
session.request_compression = features['request_compression'] if session
|
354
|
+
session.use_signals = use_signals?
|
313
355
|
self.performance_metrics_period = features['performance_metrics_period']
|
314
356
|
|
315
357
|
unless @configuration.get(:weave)
|
@@ -327,7 +369,7 @@ module Sqreen
|
|
327
369
|
hd = features['heartbeat_delay'].to_i
|
328
370
|
self.heartbeat_delay = hd if hd > 0
|
329
371
|
return if features['batch_size'].nil?
|
330
|
-
batch_events(features['batch_size'], features['max_staleness'])
|
372
|
+
batch_events(features['batch_size'], features['max_staleness'], use_signals?)
|
331
373
|
end
|
332
374
|
|
333
375
|
def change_whitelisted_paths(paths, _context_infos = {})
|
@@ -61,7 +61,7 @@ module Sqreen
|
|
61
61
|
obj.each do |k, v|
|
62
62
|
ck = k.is_a?(String) ? k.downcase : k
|
63
63
|
if @keys.include?(ck)
|
64
|
-
redacted
|
64
|
+
redacted += SensitiveDataRedactor.all_strings(v)
|
65
65
|
v = MASK
|
66
66
|
else
|
67
67
|
v, r = redact(v)
|
@@ -74,39 +74,27 @@ module Sqreen
|
|
74
74
|
[result, redacted]
|
75
75
|
end
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
next(e) unless e[:infos]
|
84
|
-
next(e) unless e[:infos][:waf_data]
|
85
|
-
|
86
|
-
parsed = JSON.parse(e[:infos][:waf_data])
|
87
|
-
redacted = parsed.each do |w|
|
88
|
-
next unless (filters = w['filter'])
|
89
|
-
|
90
|
-
filters.each do |f|
|
91
|
-
next unless (v = f['resolved_value'])
|
92
|
-
next unless values.include?(v.downcase)
|
77
|
+
class << self
|
78
|
+
def all_strings(v)
|
79
|
+
accum = []
|
80
|
+
all_strings_impl(v, accum)
|
81
|
+
accum
|
82
|
+
end
|
93
83
|
|
94
|
-
|
95
|
-
|
84
|
+
private
|
85
|
+
|
86
|
+
def all_strings_impl(obj, accum)
|
87
|
+
case obj
|
88
|
+
when String
|
89
|
+
accum << obj
|
90
|
+
when Array
|
91
|
+
obj.each { |el| all_strings_impl(el, accum) }
|
92
|
+
when Hash
|
93
|
+
obj.each do |k, v|
|
94
|
+
all_strings_impl(k, accum)
|
95
|
+
all_strings_impl(v, accum)
|
96
96
|
end
|
97
97
|
end
|
98
|
-
e[:infos][:waf_data] = JSON.dump(redacted)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def redact_exceptions!(exceptions, values)
|
103
|
-
return exceptions if values.empty?
|
104
|
-
|
105
|
-
exceptions.each do |e|
|
106
|
-
next(e) unless e[:infos]
|
107
|
-
next(e) unless e[:infos][:waf]
|
108
|
-
|
109
|
-
e[:infos][:waf].delete(:args)
|
110
98
|
end
|
111
99
|
end
|
112
100
|
end
|