sqreen 1.19.2 → 1.21.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/lib/sqreen/agent_message.rb +20 -0
  4. data/lib/sqreen/aggregated_metric.rb +25 -0
  5. data/lib/sqreen/attack_detected.html +1 -2
  6. data/lib/sqreen/ca.crt +24 -0
  7. data/lib/sqreen/configuration.rb +10 -4
  8. data/lib/sqreen/deliveries/batch.rb +12 -2
  9. data/lib/sqreen/deliveries/simple.rb +4 -0
  10. data/lib/sqreen/ecosystem.rb +96 -0
  11. data/lib/sqreen/ecosystem/dispatch_table.rb +43 -0
  12. data/lib/sqreen/ecosystem/exception_reporting.rb +26 -0
  13. data/lib/sqreen/ecosystem/http/net_http.rb +50 -0
  14. data/lib/sqreen/ecosystem/http/rack_request.rb +39 -0
  15. data/lib/sqreen/ecosystem/loggable.rb +13 -0
  16. data/lib/sqreen/ecosystem/module_api.rb +30 -0
  17. data/lib/sqreen/ecosystem/module_api/event_listener.rb +18 -0
  18. data/lib/sqreen/ecosystem/module_api/instrumentation.rb +23 -0
  19. data/lib/sqreen/ecosystem/module_api/message_producer.rb +51 -0
  20. data/lib/sqreen/ecosystem/module_api/signal_producer.rb +24 -0
  21. data/lib/sqreen/ecosystem/module_api/tracing.rb +45 -0
  22. data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +31 -0
  23. data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +27 -0
  24. data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +16 -0
  25. data/lib/sqreen/ecosystem/module_api/transaction_storage.rb +71 -0
  26. data/lib/sqreen/ecosystem/module_registry.rb +44 -0
  27. data/lib/sqreen/ecosystem/redis/redis_connection.rb +43 -0
  28. data/lib/sqreen/ecosystem/tracing/modules/client.rb +31 -0
  29. data/lib/sqreen/ecosystem/tracing/modules/server.rb +30 -0
  30. data/lib/sqreen/ecosystem/tracing/sampler.rb +160 -0
  31. data/lib/sqreen/ecosystem/tracing/sampling_configuration.rb +150 -0
  32. data/lib/sqreen/ecosystem/tracing/signals/tracing_client.rb +53 -0
  33. data/lib/sqreen/ecosystem/tracing/signals/tracing_server.rb +53 -0
  34. data/lib/sqreen/ecosystem/tracing_broker.rb +101 -0
  35. data/lib/sqreen/ecosystem/tracing_id_setup.rb +34 -0
  36. data/lib/sqreen/ecosystem/transaction_storage.rb +64 -0
  37. data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +13 -0
  38. data/lib/sqreen/ecosystem_integration.rb +81 -0
  39. data/lib/sqreen/ecosystem_integration/around_callbacks.rb +89 -0
  40. data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +38 -0
  41. data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +58 -0
  42. data/lib/sqreen/ecosystem_integration/signal_consumption.rb +35 -0
  43. data/lib/sqreen/endpoint_testing.rb +184 -0
  44. data/lib/sqreen/event.rb +7 -5
  45. data/lib/sqreen/events/attack.rb +23 -18
  46. data/lib/sqreen/events/remote_exception.rb +0 -22
  47. data/lib/sqreen/events/request_record.rb +15 -70
  48. data/lib/sqreen/frameworks/generic.rb +15 -1
  49. data/lib/sqreen/frameworks/request_recorder.rb +13 -2
  50. data/lib/sqreen/graft/call.rb +9 -0
  51. data/lib/sqreen/kit/signals/specialized/aggregated_metric.rb +72 -0
  52. data/lib/sqreen/kit/signals/specialized/attack.rb +57 -0
  53. data/lib/sqreen/kit/signals/specialized/binning_metric.rb +76 -0
  54. data/lib/sqreen/kit/signals/specialized/http_trace.rb +26 -0
  55. data/lib/sqreen/kit/signals/specialized/sdk_track_call.rb +50 -0
  56. data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +57 -0
  57. data/lib/sqreen/legacy/old_event_submission_strategy.rb +227 -0
  58. data/lib/sqreen/legacy/waf_redactions.rb +49 -0
  59. data/lib/sqreen/log/loggable.rb +1 -1
  60. data/lib/sqreen/metrics/base.rb +3 -0
  61. data/lib/sqreen/metrics_store.rb +22 -12
  62. data/lib/sqreen/performance_notifications/binned_metrics.rb +8 -2
  63. data/lib/sqreen/remote_command.rb +3 -0
  64. data/lib/sqreen/rules.rb +4 -2
  65. data/lib/sqreen/rules/rule_cb.rb +2 -0
  66. data/lib/sqreen/rules/waf_cb.rb +13 -10
  67. data/lib/sqreen/runner.rb +94 -13
  68. data/lib/sqreen/sensitive_data_redactor.rb +19 -31
  69. data/lib/sqreen/session.rb +53 -43
  70. data/lib/sqreen/signals/conversions.rb +288 -0
  71. data/lib/sqreen/signals/http_trace_redaction.rb +111 -0
  72. data/lib/sqreen/signals/signals_submission_strategy.rb +78 -0
  73. data/lib/sqreen/version.rb +1 -1
  74. metadata +83 -10
  75. data/lib/sqreen/backport.rb +0 -9
  76. data/lib/sqreen/backport/clock_gettime.rb +0 -74
  77. data/lib/sqreen/backport/original_name.rb +0 -88
@@ -22,8 +22,17 @@ module Sqreen
22
22
  include RequestRecorder
23
23
  attr_accessor :sqreen_configuration
24
24
 
25
+ attr_writer :req_start_cb, :req_end_cb
26
+
25
27
  def initialize
26
28
  clean_request_record
29
+
30
+ # for notifying the ecosystem of request boundaries
31
+ # XXX: this should be refactored. It shouldn't be
32
+ # the framework doing these notifications to the ecosystem
33
+ # Probably the rule callback should do it itself
34
+ @req_start_cb = Proc.new {}
35
+ @req_end_cb = Proc.new {}
27
36
  end
28
37
 
29
38
  # What kind of database is this
@@ -251,8 +260,12 @@ module Sqreen
251
260
  # Nota: cleanup should be performed at end of request (see clean_request)
252
261
  def store_request(object)
253
262
  return unless ensure_rack_loaded
263
+
264
+ rack_req = Rack::Request.new(object)
265
+ @req_start_cb.call(rack_req)
266
+
254
267
  self.remaining_perf_budget = Sqreen.performance_budget
255
- SharedStorage.set(:request, Rack::Request.new(object))
268
+ SharedStorage.set(:request, rack_req)
256
269
  SharedStorage.set(:xss_params, nil)
257
270
  SharedStorage.set(:whitelisted, nil)
258
271
  SharedStorage.set(:request_overtime, nil)
@@ -281,6 +294,7 @@ module Sqreen
281
294
  SharedStorage.set(:xss_params, nil)
282
295
  SharedStorage.set(:whitelisted, nil)
283
296
  SharedStorage.set(:request_overtime, nil)
297
+ @req_end_cb.call
284
298
  end
285
299
 
286
300
  def remaining_perf_budget
@@ -58,12 +58,20 @@ module Sqreen
58
58
  Sqreen.log.debug { "close_request_record called. observed_items: #{observed_items}" }
59
59
 
60
60
  clean_request_record if observed_items.nil?
61
- if only_metric_observation
61
+ if Sqreen.features['use_signals'] || only_metric_observation
62
62
  push_metrics(observations_queue, queue)
63
- return clean_request_record
64
63
  end
64
+
65
+ if only_metric_observation
66
+ clean_request_record
67
+ return
68
+ end
69
+
70
+ # signals require request section to be present
71
+ payload_requests << 'request'
65
72
  payload = payload_creator.payload(payload_requests)
66
73
  payload[:observed] = observed_items
74
+
67
75
  queue.push create_request_record(payload)
68
76
  clean_request_record
69
77
  end
@@ -79,10 +87,13 @@ module Sqreen
79
87
  @redactor ||= SensitiveDataRedactor.from_config
80
88
  end
81
89
 
90
+ # pushes metric observations to the observations queue
91
+ # and clears the list for the request record
82
92
  def push_metrics(observations_queue, event_queue)
83
93
  observed_items[:observations].each do |obs|
84
94
  observations_queue.push obs
85
95
  end
96
+ observed_items[:observations] = []
86
97
  return unless observations_queue.size > MAX_OBS_QUEUE_LENGTH / 2
87
98
  event_queue.push Sqreen::METRICS_EVENT
88
99
  end
@@ -138,6 +138,15 @@ module Sqreen
138
138
  @blips << Timer.read
139
139
  end
140
140
 
141
+ def include_measurements(another_timer)
142
+ @blips += another_timer.instance_variable_get(:@blips)
143
+ end
144
+
145
+ def start_and_end
146
+ raise 'Not exactly two measurements recorded' unless size == 2
147
+ @blips
148
+ end
149
+
141
150
  def size
142
151
  @blips.size
143
152
  end
@@ -0,0 +1,72 @@
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::AggregatedMetric < Sqreen::Kit::Signals::Metric
21
+ add_mandatory_attrs :source, :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/2020-01-01T00:00:00.000Z'.freeze
34
+
35
+ add_mandatory_attrs :capture_interval_s,
36
+ :date_started,
37
+ :date_ended,
38
+ :values,
39
+ :kind
40
+
41
+ # mandatory
42
+ # @return [Integer]
43
+ attr_accessor :capture_interval_s
44
+
45
+ # mandatory
46
+ # @param [Time]
47
+ # @return [String]
48
+ attr_accessor_time :date_started
49
+
50
+ # mandatory
51
+ # @param [Time]
52
+ # @return [String]
53
+ attr_accessor_time :date_ended
54
+
55
+ # mandatory
56
+ # @return [Hash{String=>Object}]
57
+ attr_writer :values
58
+ def values
59
+ return nil if @values.nil?
60
+ @values.map do |k, v|
61
+ {
62
+ key: k.is_a?(Hash) || k.is_a?(Array) ? k : k.to_s,
63
+ value: v,
64
+ }
65
+ end
66
+ end
67
+
68
+ # mandatory
69
+ # @return [String]
70
+ attr_accessor :kind
71
+ end
72
+ 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/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
@@ -0,0 +1,227 @@
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 Sqreen::Kit::Signals::Signal
59
+ logger.warn "Signal event in non-signal mode"
60
+ next
61
+ when Sqreen::Kit::Signals::Trace
62
+ logger.warn "Trace event in non-signal mode"
63
+ next
64
+ when Attack # in practice only found inside req rec
65
+ EventToHash.convert_attack event
66
+ when RemoteException
67
+ EventToHash.convert_exception event
68
+ when RequestRecord
69
+ EventToHash.convert_request_record event
70
+ else
71
+ logger.warn "Unexpected event type: #{event}"
72
+ next
73
+ end
74
+ h['event_type'] = event_kind(event)
75
+ h
76
+ end
77
+ Sqreen.log.debug do
78
+ tally = Hash[events.group_by(&:class).map { |k, v| [k, v.count] }]
79
+ "Doing batch with the following tally of event types: #{tally}"
80
+ end
81
+ post('batch', { batch: batch.compact }, {}, RETRY_MANY)
82
+ end
83
+
84
+ private
85
+
86
+ # see +Sqreen::Session.post+
87
+ def post(*args)
88
+ @post_proc[*args]
89
+ end
90
+
91
+ def event_kind(event)
92
+ case event
93
+ when Sqreen::RemoteException then 'sqreen_exception'
94
+ when Sqreen::Attack then 'attack'
95
+ when Sqreen::RequestRecord then 'request_record'
96
+ end
97
+ end
98
+ end
99
+
100
+ module EventToHash
101
+ class << self
102
+ # @param attack [Sqreen::Attack]
103
+ def convert_attack(attack)
104
+ payload = attack.payload
105
+ res = {}
106
+ rule_p = payload['rule']
107
+ request_p = payload['request']
108
+ res[:rule_name] = rule_p['name'] if rule_p && rule_p['name']
109
+ res[:rulespack_id] = rule_p['rulespack_id'] if rule_p && rule_p['rulespack_id']
110
+ res[:test] = rule_p['test'] if rule_p && rule_p['test']
111
+ res[:infos] = payload['infos'] if payload['infos']
112
+ res[:time] = attack.time
113
+ res[:client_ip] = request_p[:addr] if request_p && request_p[:addr]
114
+ res[:request] = request_p if request_p
115
+ res[:params] = payload['params'] if payload['params']
116
+ res[:context] = payload['context'] if payload['context']
117
+ res[:headers] = payload['headers'] if payload['headers']
118
+ res
119
+ end
120
+
121
+ # @param [Sqreen::RequestRecord] rr
122
+ def convert_request_record(rr)
123
+ res = { :version => '20171208' }
124
+ payload = rr.payload
125
+
126
+ if payload[:observed]
127
+ res[:observed] = payload[:observed].dup
128
+ rulespack = nil
129
+ if rr.observed[:attacks]
130
+ res[:observed][:attacks] = rr.observed[:attacks].map do |att|
131
+ natt = att.dup
132
+ [:attack_type, :block].each { |k| natt.delete(k) } # signals stuff
133
+ rulespack = natt.delete(:rulespack_id) || rulespack
134
+ natt
135
+ end
136
+ end
137
+ if rr.observed[:sqreen_exceptions]
138
+ res[:observed][:sqreen_exceptions] = rr.observed[:sqreen_exceptions].map do |exc|
139
+ nex = exc.dup
140
+ excp = nex.delete(:exception)
141
+ if excp
142
+ nex[:message] = excp.message
143
+ nex[:klass] = excp.class.name
144
+ end
145
+ rulespack = nex.delete(:rulespack_id) || rulespack
146
+ nex
147
+ end
148
+ end
149
+ res[:rulespack_id] = rulespack unless rulespack.nil?
150
+ if rr.observed[:observations]
151
+ res[:observed][:observations] = rr.observed[:observations].map do |cat, key, value, time|
152
+ { :category => cat, :key => key, :value => value, :time => time }
153
+ end
154
+ end
155
+ if rr.observed[:sdk] # rubocop:disable Style/IfUnlessModifier
156
+ res[:observed][:sdk] = rr.processed_sdk_calls
157
+ end
158
+ end
159
+ res[:local] = payload['local'] if payload['local']
160
+ if payload['request']
161
+ res[:request] = payload['request'].dup
162
+ res[:client_ip] = res[:request].delete(:client_ip) if res[:request][:client_ip]
163
+ else
164
+ res[:request] = {}
165
+ end
166
+ if payload['response']
167
+ res[:response] = payload['response'].dup
168
+ else
169
+ res[:response] = {}
170
+ end
171
+
172
+ res[:request][:parameters] = payload['params'] if payload['params']
173
+ res[:request][:headers] = payload['headers'] if payload['headers']
174
+
175
+ res = Sqreen::EncodingSanitizer.sanitize(res)
176
+
177
+ if rr.redactor
178
+ res[:request], redacted = rr.redactor.redact(res[:request])
179
+ redacted = redacted.uniq
180
+ if redacted.any? && res[:observed] && res[:observed][:attacks]
181
+ res[:observed][:attacks] = WafRedactions.redact_attacks!(res[:observed][:attacks], redacted)
182
+ end
183
+ if redacted.any? && res[:observed] && res[:observed][:sqreen_exceptions]
184
+ res[:observed][:sqreen_exceptions] = WafRedactions.redact_exceptions!(res[:observed][:sqreen_exceptions], redacted)
185
+ end
186
+ end
187
+
188
+ res
189
+ end
190
+
191
+ # @param exception_evt [Sqreen::RemoteException]
192
+ def convert_exception(exception_evt)
193
+ payload = exception_evt.payload
194
+ exception = payload['exception']
195
+ ev = {
196
+ :klass => exception.class.name,
197
+ :message => exception.message,
198
+ :params => payload['request_params'],
199
+ :time => payload['time'],
200
+ :infos => {
201
+ :client_ip => payload['client_ip'],
202
+ },
203
+ :request => payload['request_infos'],
204
+ :headers => payload['headers'],
205
+ :rule_name => payload['rule_name'],
206
+ :rulespack_id => payload['rulespack_id'],
207
+ }
208
+
209
+ ev[:infos].merge!(payload['infos']) if payload['infos']
210
+ return ev unless exception.backtrace
211
+ ev[:context] = { :backtrace => exception.backtrace.map(&:to_s) }
212
+ ev
213
+ end
214
+
215
+ # @param [Sqreen::AggregatedMetric] agg_metric
216
+ def convert_agg_metric(agg_metric)
217
+ {
218
+ name: agg_metric.name,
219
+ observation: agg_metric.data,
220
+ start: agg_metric.start,
221
+ finish: agg_metric.finish,
222
+ }
223
+ end
224
+ end
225
+ end
226
+ end
227
+ end