sqreen 1.19.2 → 1.21.0.beta2

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.
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