sqreen 1.19.4 → 1.20.4.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -1
  3. data/lib/sqreen/actions/block_user.rb +1 -1
  4. data/lib/sqreen/actions/redirect_ip.rb +1 -1
  5. data/lib/sqreen/actions/redirect_user.rb +1 -1
  6. data/lib/sqreen/agent_message.rb +20 -0
  7. data/lib/sqreen/aggregated_metric.rb +25 -0
  8. data/lib/sqreen/attack_detected.html +1 -2
  9. data/lib/sqreen/ca.crt +24 -0
  10. data/lib/sqreen/configuration.rb +11 -5
  11. data/lib/sqreen/deferred_logger.rb +50 -14
  12. data/lib/sqreen/deliveries/batch.rb +4 -1
  13. data/lib/sqreen/deliveries/simple.rb +4 -0
  14. data/lib/sqreen/deprecation.rb +38 -0
  15. data/lib/sqreen/endpoint_testing.rb +184 -0
  16. data/lib/sqreen/event.rb +7 -5
  17. data/lib/sqreen/events/attack.rb +23 -18
  18. data/lib/sqreen/events/remote_exception.rb +0 -22
  19. data/lib/sqreen/events/request_record.rb +15 -70
  20. data/lib/sqreen/frameworks/generic.rb +9 -0
  21. data/lib/sqreen/frameworks/rails.rb +0 -7
  22. data/lib/sqreen/frameworks/request_recorder.rb +13 -2
  23. data/lib/sqreen/graft/call.rb +76 -18
  24. data/lib/sqreen/graft/callback.rb +1 -1
  25. data/lib/sqreen/graft/hook.rb +187 -85
  26. data/lib/sqreen/graft/hook_point.rb +1 -1
  27. data/lib/sqreen/kit/signals/specialized/aggregated_metric.rb +72 -0
  28. data/lib/sqreen/kit/signals/specialized/attack.rb +57 -0
  29. data/lib/sqreen/kit/signals/specialized/binning_metric.rb +76 -0
  30. data/lib/sqreen/kit/signals/specialized/http_trace.rb +26 -0
  31. data/lib/sqreen/kit/signals/specialized/sdk_track_call.rb +50 -0
  32. data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +57 -0
  33. data/lib/sqreen/legacy/instrumentation.rb +22 -10
  34. data/lib/sqreen/legacy/old_event_submission_strategy.rb +221 -0
  35. data/lib/sqreen/legacy/waf_redactions.rb +49 -0
  36. data/lib/sqreen/log.rb +3 -2
  37. data/lib/sqreen/log/loggable.rb +2 -1
  38. data/lib/sqreen/logger.rb +24 -0
  39. data/lib/sqreen/metrics/base.rb +3 -0
  40. data/lib/sqreen/metrics_store.rb +33 -12
  41. data/lib/sqreen/null_logger.rb +22 -0
  42. data/lib/sqreen/performance_notifications/binned_metrics.rb +8 -2
  43. data/lib/sqreen/remote_command.rb +1 -0
  44. data/lib/sqreen/rules.rb +5 -3
  45. data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
  46. data/lib/sqreen/rules/rule_cb.rb +4 -0
  47. data/lib/sqreen/rules/waf_cb.rb +11 -8
  48. data/lib/sqreen/runner.rb +103 -10
  49. data/lib/sqreen/sensitive_data_redactor.rb +19 -31
  50. data/lib/sqreen/session.rb +51 -43
  51. data/lib/sqreen/signals/conversions.rb +283 -0
  52. data/lib/sqreen/signals/http_trace_redaction.rb +111 -0
  53. data/lib/sqreen/signals/signals_submission_strategy.rb +78 -0
  54. data/lib/sqreen/version.rb +1 -1
  55. data/lib/sqreen/weave/budget.rb +46 -0
  56. data/lib/sqreen/weave/legacy/instrumentation.rb +156 -94
  57. data/lib/sqreen/worker.rb +6 -2
  58. metadata +51 -8
  59. data/lib/sqreen/backport.rb +0 -9
  60. data/lib/sqreen/backport/clock_gettime.rb +0 -74
  61. data/lib/sqreen/backport/original_name.rb +0 -88
@@ -0,0 +1,57 @@
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
+ require 'sqreen/kit/signals/point'
7
+ require 'sqreen/kit/signals/dto_helper'
8
+
9
+ # reference: https://github.com/sqreen/SignalsSchemas/blob/master/schemas/payload/attack/2020-01-01T00_00_00_000Z/schema.cue
10
+
11
+ module Sqreen
12
+ module Kit
13
+ module Signals
14
+ module Specialized
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ class Sqreen::Kit::Signals::Specialized::Attack < Sqreen::Kit::Signals::Point
21
+ add_mandatory_attrs :source, :time, :payload
22
+
23
+ validate_str_attr :signal_name, /\Asq\.agent\.attack\..+\z/
24
+ validate_str_attr :source, /\Asqreen:rule:[a-f0-9]{40}:.+\z/
25
+
26
+ def initialize(values = {})
27
+ self.payload_schema = Payload::SCHEMA_VERSION
28
+ self.time = values[:time] || Time.now
29
+ super
30
+ end
31
+
32
+ def payload=(payload)
33
+ unless payload.is_a?(Payload)
34
+ raise ArgumentError, "Payload should be a #{Payload}"
35
+ end
36
+ super
37
+ end
38
+
39
+ class Payload
40
+ include Sqreen::Kit::Signals::DtoHelper
41
+
42
+ SCHEMA_VERSION = 'attack/2020-01-01T00:00:00.000Z'.freeze
43
+
44
+ add_mandatory_attrs :test, :block, :infos
45
+
46
+ # all are mandatory
47
+
48
+ # @return [Boolean]
49
+ attr_accessor :test
50
+
51
+ # @return [Boolean]
52
+ attr_accessor :block
53
+
54
+ # @return [Hash{String|Symbol=>Object}]
55
+ attr_accessor :infos
56
+ end
57
+ end
@@ -0,0 +1,76 @@
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
+ require 'sqreen/kit/signals/metric'
7
+ require 'sqreen/kit/signals/dto_helper'
8
+
9
+ # reference: https://github.com/sqreen/SignalsSchemas/blob/master/schemas/payload/binning_metric/2020-01-01T00_00_00_000Z/schema.cue
10
+
11
+ module Sqreen
12
+ module Kit
13
+ module Signals
14
+ module Specialized
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ class Sqreen::Kit::Signals::Specialized::BinningMetric < Sqreen::Kit::Signals::Metric
21
+ add_mandatory_attrs :source, :time, :payload
22
+
23
+ validate_str_attr :signal_name, /\Asq\.agent\.metric\..+\z/
24
+
25
+ def initialize(args)
26
+ self.payload_schema = Payload::SCHEMA_VERSION
27
+ super
28
+ end
29
+
30
+ class Payload
31
+ include Sqreen::Kit::Signals::DtoHelper
32
+
33
+ SCHEMA_VERSION = 'metric_binning/2020-01-01T00:00:00.000Z'.freeze
34
+
35
+ add_mandatory_attrs :capture_interval_s,
36
+ :date_started,
37
+ :date_ended,
38
+ :max, :base, :unit, :bins
39
+
40
+ # mandatory
41
+ # @return [Integer]
42
+ attr_accessor :capture_interval_s
43
+
44
+ # mandatory
45
+ # @param [Time]
46
+ # @return [String]
47
+ attr_accessor_time :date_started
48
+
49
+ # mandatory
50
+ # @param [Time]
51
+ # @return [String]
52
+ attr_accessor_time :date_ended
53
+
54
+ # mandatory
55
+ # @return [Float]
56
+ attr_accessor :max
57
+
58
+ # mandatory
59
+ # @return [Float]
60
+ attr_accessor :base
61
+
62
+ # mandatory
63
+ # @return [Float]
64
+ attr_accessor :unit
65
+
66
+ # mandatory
67
+ # @return [Hash{Integer=>Integer}]
68
+ attr_accessor :bins
69
+
70
+ def to_h
71
+ {
72
+ kind: 'binning',
73
+ }.merge(super)
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,26 @@
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
+ require 'sqreen/kit/signals/trace'
7
+ require 'sqreen/kit/signals/context/http_context'
8
+ require 'sqreen/kit/signals/dto_helper'
9
+
10
+ module Sqreen
11
+ module Kit
12
+ module Signals
13
+ module Specialized
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ class Sqreen::Kit::Signals::Specialized::HttpTrace < Sqreen::Kit::Signals::Trace
20
+ add_mandatory_attrs :context
21
+
22
+ def initialize(values = {})
23
+ self.context_schema = ::Sqreen::Kit::Signals::Context::HttpContext::SCHEMA_VERSION
24
+ super
25
+ end
26
+ end
@@ -0,0 +1,50 @@
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
+ require 'sqreen/kit/signals/point'
7
+ require 'sqreen/kit/signals/dto_helper'
8
+
9
+ # reference: https://github.com/sqreen/SignalsSchemas/blob/master/schemas/payload/sdk_call/2020-01-01T00_00_00_000Z/schema.cue
10
+
11
+ module Sqreen
12
+ module Kit
13
+ module Signals
14
+ module Specialized
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ class Sqreen::Kit::Signals::Specialized::SdkTrackCall < Sqreen::Kit::Signals::Point
21
+ add_mandatory_attrs :source, :time, :payload
22
+
23
+ validate_str_attr :signal_name, /\Asq\.sdk\..+\z/
24
+
25
+ def initialize(values = {})
26
+ self.payload_schema = Payload::SCHEMA_VERSION
27
+ self.source = "sqreen:sdk:track"
28
+ self.time = values[:time] || Time.now
29
+ super
30
+ end
31
+
32
+ def payload=(payload)
33
+ unless payload.is_a?(Payload)
34
+ raise ArgumentError, "Payload should be a #{Payload}"
35
+ end
36
+ super
37
+ end
38
+
39
+ class Payload
40
+ include Sqreen::Kit::Signals::DtoHelper
41
+
42
+ SCHEMA_VERSION = 'track_event/2020-01-01T00:00:00.000Z'.freeze
43
+
44
+ # @return [Hash{String|Symbol=>Object}]
45
+ attr_accessor :properties
46
+
47
+ # @return [Hash{String|Symbol=>String}]
48
+ attr_accessor :user_identifiers
49
+ end
50
+ end
@@ -0,0 +1,57 @@
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
+ require 'sqreen/kit/signals/point'
7
+ require 'sqreen/kit/signals/dto_helper'
8
+
9
+ # reference: https://github.com/sqreen/SignalsSchemas/blob/master/schemas/payload/sqreen_exception/2020-01-01T00_00_00_000Z/schema.cue
10
+
11
+ module Sqreen
12
+ module Kit
13
+ module Signals
14
+ module Specialized
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ class Sqreen::Kit::Signals::Specialized::SqreenException < Sqreen::Kit::Signals::Point
21
+ PAYLOAD_SCHEMA_VERSION = 'sqreen_exception/2020-01-01T00:00:00.000Z'.freeze
22
+
23
+ # @return [Hash]
24
+ attr_accessor :infos
25
+
26
+ # @return [Exception]
27
+ attr_accessor :ruby_exception
28
+
29
+ add_mandatory_attrs :source, :time, :ruby_exception
30
+
31
+ validate_str_attr :source, /\A(?:sqreen:rule:[a-f0-9]{40}:.+)|(?:sqreen:agent:.+)\z/
32
+
33
+ def self.attributes_for_to_h_self
34
+ [] # don't include ruby_exception in list of attributes for to_h
35
+ end
36
+
37
+ def initialize(values = {})
38
+ self.payload_schema = PAYLOAD_SCHEMA_VERSION
39
+ self.signal_name = 'sq.agent.exception'
40
+ self.time = values[:time] || Time.now
41
+ super
42
+ end
43
+
44
+ def payload
45
+ return nil unless @ruby_exception
46
+ compact_hash({
47
+ klass: @ruby_exception.class.to_s,
48
+ message: @ruby_exception.message,
49
+ infos: @infos,
50
+ })
51
+ end
52
+
53
+ def location
54
+ return nil unless @ruby_exception
55
+ Sqreen::Kit::Signals::Location.new(exception: @ruby_exception)
56
+ end
57
+ end
@@ -109,7 +109,7 @@ module Legacy
109
109
  break if res.is_a?(Hash) && res[:skip_rem_cbs]
110
110
  rescue StandardError => e
111
111
  Sqreen.log.warn { "we catch an exception: #{e.inspect}" }
112
- Sqreen.log.debug e.backtrace
112
+ Sqreen.log.debug { e.backtrace }
113
113
  if cb.respond_to?(:record_exception)
114
114
  cb.record_exception(e)
115
115
  else
@@ -162,7 +162,7 @@ module Legacy
162
162
  returns << res
163
163
  rescue StandardError => e
164
164
  Sqreen.log.warn { "we catch an exception: #{e.inspect}" }
165
- Sqreen.log.debug e.backtrace
165
+ Sqreen.log.debug { e.backtrace }
166
166
  if cb.respond_to?(:record_exception)
167
167
  cb.record_exception(e)
168
168
  else
@@ -597,16 +597,25 @@ module Legacy
597
597
  method = cb.method
598
598
  key = [klass, method]
599
599
 
600
+ if (call_count = ENV['SQREEN_DEBUG_CALL_COUNT'])
601
+ call_count = JSON.parse(call_count)
602
+ if cb.respond_to?(:rule_name) && call_count.key?(cb.rule_name)
603
+ count = call_count[cb.rule_name]
604
+ Sqreen.log.debug { "override rule:#{cb.rule_name} call_count:#{count.inspect}" }
605
+ cb.instance_eval { @call_count_interval = call_count[cb.rule_name] }
606
+ end
607
+ end
608
+
600
609
  @@record_request_hookpoints << key if cb.is_a?(Sqreen::Rules::RecordRequestContext)
601
610
 
602
611
  already_overriden = @@overriden_methods.include? key
603
612
 
604
613
  if !already_overriden
605
614
  if is_class_method?(klass, method)
606
- Sqreen.log.debug "overriding class method for #{cb}"
615
+ Sqreen.log.debug { "overriding class method for #{cb}" }
607
616
  success = override_class_method(klass, method)
608
617
  elsif is_instance_method?(klass, method)
609
- Sqreen.log.debug "overriding instance method for #{cb}"
618
+ Sqreen.log.debug { "overriding instance method for #{cb}" }
610
619
  success = override_instance_method(klass, method)
611
620
  else
612
621
  # FIXME: Override define_method and other dynamic ways to
@@ -623,7 +632,7 @@ module Legacy
623
632
 
624
633
  @@overriden_methods += [key] if success
625
634
  else
626
- Sqreen.log.debug "#{key} was already overriden"
635
+ Sqreen.log.debug { "#{key} was already overriden" }
627
636
  end
628
637
 
629
638
  if klass != Object && klass != Kernel && !Sqreen.features['instrument_all_instances'] && !defined?(::JRUBY_VERSION)
@@ -638,7 +647,7 @@ module Legacy
638
647
  end
639
648
  end
640
649
 
641
- Sqreen.log.debug "Adding callback #{cb} for #{klass} #{method}"
650
+ Sqreen.log.debug { "Adding callback #{cb} for #{klass} #{method}" }
642
651
  @@registered_callbacks.add(cb)
643
652
  @@unovertimable_hookpoints << key unless cb.overtimeable
644
653
  @@instrumented_pid = Process.pid
@@ -659,7 +668,7 @@ module Legacy
659
668
 
660
669
  already_overriden = @@overriden_methods.include? key
661
670
  unless already_overriden
662
- Sqreen.log.debug "#{key} apparently not overridden"
671
+ Sqreen.log.debug { "#{key} apparently not overridden" }
663
672
  end
664
673
 
665
674
  defined_cbs = @@registered_callbacks.get(klass, method).flatten
@@ -667,17 +676,17 @@ module Legacy
667
676
  nb_removed = 0
668
677
  defined_cbs.each do |found_cb|
669
678
  if found_cb == cb
670
- Sqreen.log.debug "Removing callback #{found_cb}"
679
+ Sqreen.log.debug { "Removing callback #{found_cb}" }
671
680
  @@registered_callbacks.remove(found_cb)
672
681
  nb_removed += 1
673
682
  else
674
- Sqreen.log.debug "Not removing callback #{found_cb} (remains #{defined_cbs.size} cbs)"
683
+ Sqreen.log.debug { "Not removing callback #{found_cb} (remains #{defined_cbs.size} cbs)" }
675
684
  end
676
685
  end
677
686
 
678
687
  return unless nb_removed == defined_cbs.size
679
688
 
680
- Sqreen.log.debug "Removing overriden method #{key}"
689
+ Sqreen.log.debug { "Removing overriden method #{key}" }
681
690
  @@overriden_methods.delete(key)
682
691
 
683
692
  if is_class_method?(klass, method)
@@ -705,6 +714,7 @@ module Legacy
705
714
  remove_callback_no_lock(cb)
706
715
  end
707
716
  Sqreen.instrumentation_ready = false
717
+ Sqreen.log.info('Instrumentation deactivated')
708
718
  end
709
719
  end
710
720
 
@@ -757,6 +767,8 @@ module Legacy
757
767
  ### globally declare instrumentation ready
758
768
  ### from within instance method? not even thread local?
759
769
  Sqreen.instrumentation_ready = true
770
+
771
+ Sqreen.log.info('Instrumentation activated')
760
772
  end
761
773
 
762
774
  def initialize(metrics_engine = nil)
@@ -0,0 +1,221 @@
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
+ require 'sqreen/aggregated_metric'
7
+ require 'sqreen/log/loggable'
8
+ require 'sqreen/legacy/waf_redactions'
9
+
10
+ module Sqreen
11
+ module Legacy
12
+ # see also Sqreen::Signals::SignalsSubmissionStrategy
13
+ # usage in Sqreen:Session
14
+ class OldEventSubmissionStrategy
15
+ include Sqreen::Log::Loggable
16
+
17
+ RETRY_MANY = 301
18
+
19
+ def initialize(post_proc)
20
+ @post_proc = post_proc
21
+ end
22
+
23
+ def post_metrics(metrics)
24
+ return if metrics.nil? || metrics.empty?
25
+ payload = { metrics: metrics.map { |m| EventToHash.convert_agg_metric(m) } }
26
+ post('metrics', payload, {}, RETRY_MANY)
27
+ end
28
+
29
+ # @param attack [Sqreen::Attack]
30
+ def post_attack(attack)
31
+ post('attack', EventToHash.convert_attack(attack), {}, RETRY_MANY)
32
+ end
33
+
34
+ # @param [Sqreen::RequestRecord] request_record
35
+ def post_request_record(request_record)
36
+ rr_hash = EventToHash.convert_request_record(request_record)
37
+ post('request_record', rr_hash, {}, RETRY_MANY)
38
+ end
39
+
40
+ # Post an exception to Sqreen for analysis
41
+ # @param exception [RemoteException] Exception and context to be sent over
42
+ def post_sqreen_exception(exception)
43
+ data = EventToHash.convert_exception(exception)
44
+ post('sqreen_exception', data, {}, 5)
45
+ rescue StandardError => e
46
+ logger.warn(format('Could not post exception (network down? %s) %s',
47
+ e.inspect,
48
+ exception.inspect))
49
+ nil
50
+ end
51
+
52
+ def post_batch(events)
53
+ batch = events.map do |event|
54
+ h = case event
55
+ when AggregatedMetric
56
+ logger.warn "Aggregated metric event in non-signal mode. Signals disabled at runtime?"
57
+ next
58
+ when Attack # in practice only found inside req rec
59
+ EventToHash.convert_attack event
60
+ when RemoteException
61
+ EventToHash.convert_exception event
62
+ when RequestRecord
63
+ EventToHash.convert_request_record event
64
+ else
65
+ logger.warn "Unexpected event type: #{event}"
66
+ next
67
+ end
68
+ h['event_type'] = event_kind(event)
69
+ h
70
+ end
71
+ Sqreen.log.debug do
72
+ tally = Hash[events.group_by(&:class).map { |k, v| [k, v.count] }]
73
+ "Doing batch with the following tally of event types: #{tally}"
74
+ end
75
+ post('batch', { batch: batch }, {}, RETRY_MANY)
76
+ end
77
+
78
+ private
79
+
80
+ # see +Sqreen::Session.post+
81
+ def post(*args)
82
+ @post_proc[*args]
83
+ end
84
+
85
+ def event_kind(event)
86
+ case event
87
+ when Sqreen::RemoteException then 'sqreen_exception'
88
+ when Sqreen::Attack then 'attack'
89
+ when Sqreen::RequestRecord then 'request_record'
90
+ end
91
+ end
92
+ end
93
+
94
+ module EventToHash
95
+ class << self
96
+ # @param attack [Sqreen::Attack]
97
+ def convert_attack(attack)
98
+ payload = attack.payload
99
+ res = {}
100
+ rule_p = payload['rule']
101
+ request_p = payload['request']
102
+ res[:rule_name] = rule_p['name'] if rule_p && rule_p['name']
103
+ res[:rulespack_id] = rule_p['rulespack_id'] if rule_p && rule_p['rulespack_id']
104
+ res[:test] = rule_p['test'] if rule_p && rule_p['test']
105
+ res[:infos] = payload['infos'] if payload['infos']
106
+ res[:time] = attack.time
107
+ res[:client_ip] = request_p[:addr] if request_p && request_p[:addr]
108
+ res[:request] = request_p if request_p
109
+ res[:params] = payload['params'] if payload['params']
110
+ res[:context] = payload['context'] if payload['context']
111
+ res[:headers] = payload['headers'] if payload['headers']
112
+ res
113
+ end
114
+
115
+ # @param [Sqreen::RequestRecord] rr
116
+ def convert_request_record(rr)
117
+ res = { :version => '20171208' }
118
+ payload = rr.payload
119
+
120
+ if payload[:observed]
121
+ res[:observed] = payload[:observed].dup
122
+ rulespack = nil
123
+ if rr.observed[:attacks]
124
+ res[:observed][:attacks] = rr.observed[:attacks].map do |att|
125
+ natt = att.dup
126
+ [:attack_type, :block].each { |k| natt.delete(k) } # signals stuff
127
+ rulespack = natt.delete(:rulespack_id) || rulespack
128
+ natt
129
+ end
130
+ end
131
+ if rr.observed[:sqreen_exceptions]
132
+ res[:observed][:sqreen_exceptions] = rr.observed[:sqreen_exceptions].map do |exc|
133
+ nex = exc.dup
134
+ excp = nex.delete(:exception)
135
+ if excp
136
+ nex[:message] = excp.message
137
+ nex[:klass] = excp.class.name
138
+ end
139
+ rulespack = nex.delete(:rulespack_id) || rulespack
140
+ nex
141
+ end
142
+ end
143
+ res[:rulespack_id] = rulespack unless rulespack.nil?
144
+ if rr.observed[:observations]
145
+ res[:observed][:observations] = rr.observed[:observations].map do |cat, key, value, time|
146
+ { :category => cat, :key => key, :value => value, :time => time }
147
+ end
148
+ end
149
+ if rr.observed[:sdk] # rubocop:disable Style/IfUnlessModifier
150
+ res[:observed][:sdk] = rr.processed_sdk_calls
151
+ end
152
+ end
153
+ res[:local] = payload['local'] if payload['local']
154
+ if payload['request']
155
+ res[:request] = payload['request'].dup
156
+ res[:client_ip] = res[:request].delete(:client_ip) if res[:request][:client_ip]
157
+ else
158
+ res[:request] = {}
159
+ end
160
+ if payload['response']
161
+ res[:response] = payload['response'].dup
162
+ else
163
+ res[:response] = {}
164
+ end
165
+
166
+ res[:request][:parameters] = payload['params'] if payload['params']
167
+ res[:request][:headers] = payload['headers'] if payload['headers']
168
+
169
+ res = Sqreen::EncodingSanitizer.sanitize(res)
170
+
171
+ if rr.redactor
172
+ res[:request], redacted = rr.redactor.redact(res[:request])
173
+ redacted = redacted.uniq
174
+ if redacted.any? && res[:observed] && res[:observed][:attacks]
175
+ res[:observed][:attacks] = WafRedactions.redact_attacks!(res[:observed][:attacks], redacted)
176
+ end
177
+ if redacted.any? && res[:observed] && res[:observed][:sqreen_exceptions]
178
+ res[:observed][:sqreen_exceptions] = WafRedactions.redact_exceptions!(res[:observed][:sqreen_exceptions], redacted)
179
+ end
180
+ end
181
+
182
+ res
183
+ end
184
+
185
+ # @param exception_evt [Sqreen::RemoteException]
186
+ def convert_exception(exception_evt)
187
+ payload = exception_evt.payload
188
+ exception = payload['exception']
189
+ ev = {
190
+ :klass => exception.class.name,
191
+ :message => exception.message,
192
+ :params => payload['request_params'],
193
+ :time => payload['time'],
194
+ :infos => {
195
+ :client_ip => payload['client_ip'],
196
+ },
197
+ :request => payload['request_infos'],
198
+ :headers => payload['headers'],
199
+ :rule_name => payload['rule_name'],
200
+ :rulespack_id => payload['rulespack_id'],
201
+ }
202
+
203
+ ev[:infos].merge!(payload['infos']) if payload['infos']
204
+ return ev unless exception.backtrace
205
+ ev[:context] = { :backtrace => exception.backtrace.map(&:to_s) }
206
+ ev
207
+ end
208
+
209
+ # @param [Sqreen::AggregatedMetric] agg_metric
210
+ def convert_agg_metric(agg_metric)
211
+ {
212
+ name: agg_metric.name,
213
+ observation: agg_metric.data,
214
+ start: agg_metric.start,
215
+ finish: agg_metric.finish,
216
+ }
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end