sqreen 1.12.0 → 1.13.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 867b430d86c473c22fcad2e5531c5ee70078ffa45201e8e4e906127e854eaf84
4
- data.tar.gz: e8ba868e3b21824963da46dde7abbf171f17cb83732af65599fb84eaa4181245
3
+ metadata.gz: fb4ef79ad2d573f02250c303800c9d4c8b64a3f1e0318fbf2f7e198508826b7b
4
+ data.tar.gz: 991f85b77cb27f9387fb027e74538aded1a7f0e4dd0c1a78a8a89041154d790a
5
5
  SHA512:
6
- metadata.gz: 98d5d2879397613f82ead509e0dc352ab7c139c8e045f0e64d4f2f8938b3c992264e4053e6b1d001af7f2131593bf319d45882235388b417d48c9cf88a337093
7
- data.tar.gz: c0ee0912af909dd7fa94db71a5480215dc36e4e2c3cd6471dae61b0ee888763c63e10fa385027957d0d7c17e34c47aa96968225be3a4ebe8f04fbe044b2ad0ab
6
+ metadata.gz: a575ae38cbccc9381e8dea3fedc7c7ac24ce0a7174b0ba799f264cfbd8bf0a346c4c60fc6518172f6bff09d692193d469cb31fe4513781f67468d52c7db14419
7
+ data.tar.gz: 8dffc28661b0e8fd608cae0917326519abf7c6d8f4b36d96ffead33e6df3059f0de05187a03d425d21068e36a04f8b6f0b42c9375bce9a9a7515c1fe6f847ff4
@@ -6,6 +6,7 @@ require 'sqreen/log'
6
6
  require 'sqreen/exception'
7
7
  require 'sqreen/sdk'
8
8
  require 'sqreen/frameworks'
9
+ require 'singleton'
9
10
 
10
11
  module Sqreen
11
12
  # Implements actions (behavior taken in response to agent signals)
@@ -58,25 +59,39 @@ module Sqreen
58
59
  return nil
59
60
  end
60
61
 
61
- subclass.new(id, duration, hash['parameters'] || {})
62
+ opts = {
63
+ :duration => duration,
64
+ :send_response => hash['send_response'],
65
+ }
66
+
67
+ subclass.new(id, opts, hash['parameters'] || {})
62
68
  end
63
69
 
70
+ # Base class for actions
64
71
  class Base
65
- attr_reader :id, :expiry
72
+ attr_reader :id, :expiry, :send_response
66
73
 
67
- def initialize(id, duration)
74
+ def initialize(id, opts)
68
75
  @id = id
76
+ duration = opts[:duration]
69
77
  @expiry = Time.new + duration unless duration.nil?
78
+ @send_response = if opts[:send_response].nil?
79
+ true
80
+ else
81
+ !!opts[:send_response]
82
+ end
70
83
  end
71
84
 
72
85
  # See Sqreen::CB for return values
73
86
  def run(*args)
74
87
  return if expiry && Time.new > expiry
75
88
  ret = do_run *args
76
- unless ret.nil?
89
+ unless ret.nil? || !@send_response
77
90
  Sqreen.internal_track(event_name,
78
- 'properties' => event_properties(*args).
79
- merge('action_id' => id))
91
+ 'properties' => {
92
+ 'output' => event_properties(*args),
93
+ 'action_id' => id,
94
+ })
80
95
  end
81
96
  ret
82
97
  end
@@ -155,8 +170,8 @@ module Sqreen
155
170
  include IpRanges
156
171
  self.type_name = 'block_ip'
157
172
 
158
- def initialize(id, duration, params = {})
159
- super(id, duration)
173
+ def initialize(id, opts, params = {})
174
+ super(id, opts)
160
175
  parse_ip_ranges params
161
176
  end
162
177
 
@@ -179,8 +194,8 @@ module Sqreen
179
194
 
180
195
  attr_reader :redirect_url
181
196
 
182
- def initialize(id, duration, params = {})
183
- super(id, duration)
197
+ def initialize(id, opts, params = {})
198
+ super(id, opts)
184
199
  @redirect_url = params['url']
185
200
  raise "no url provided for action #{id}" unless @redirect_url
186
201
  parse_ip_ranges params
@@ -199,5 +214,48 @@ module Sqreen
199
214
  { 'ip_address' => client_ip, 'url' => @redirect_url }
200
215
  end
201
216
  end
217
+
218
+ # Blocks a user at the point Sqreen::identify()
219
+ # or Sqreen::auth_track() are called
220
+ class BlockUser < Base
221
+ self.type_name = 'block_user'
222
+
223
+ def initialize(id, opts, params = {})
224
+ super(id, opts)
225
+ @users = params['users']
226
+ raise ::Sqreen::Exception, 'nil "users" param for block_user action' if @users.nil?
227
+ raise ::Sqreen::Exception, '"users" param must be an array' unless @users.is_a? Array
228
+ end
229
+
230
+ def do_run(identity_params)
231
+ return unless @users.include? stringify_keys(identity_params)
232
+ Sqreen.log.info(
233
+ "Will raise due to user being blocked by action #{id}. " \
234
+ "Blocked user identity: #{identity_params}"
235
+ )
236
+
237
+ e = Sqreen::AttackBlocked.new(
238
+ "Blocked user with identity #{identity_params} " \
239
+ 'due to automatic security response. No action is required'
240
+ )
241
+
242
+ {
243
+ :status => :raise,
244
+ :exception => e,
245
+ }
246
+ end
247
+
248
+ def event_properties(identity_params)
249
+ { 'user' => identity_params }
250
+ end
251
+
252
+ private
253
+
254
+ def stringify_keys(hash)
255
+ Hash[
256
+ hash.map { |k, v| [k.to_s, v] }
257
+ ]
258
+ end
259
+ end
202
260
  end
203
261
  end
@@ -49,6 +49,8 @@ module Sqreen
49
49
  :default => false, :convert => :to_bool },
50
50
  { :env => :SQREEN_INITIAL_FEATURES, :name => :initial_features,
51
51
  :default => nil },
52
+ { :env => :SQREEN_IP_HEADER, :name => :ip_header,
53
+ :default => nil },
52
54
 
53
55
  ].freeze
54
56
 
@@ -42,9 +42,7 @@ module Sqreen
42
42
  end
43
43
  end
44
44
  if observed[:sdk]
45
- res[:observed][:sdk] = observed[:sdk].map do |meth, time, *args|
46
- { :name => meth, :time => time, :args => args }
47
- end
45
+ res[:observed][:sdk] = processed_sdk_calls
48
46
  end
49
47
  end
50
48
  res[:local] = payload['local'] if payload['local']
@@ -58,5 +56,44 @@ module Sqreen
58
56
  res[:request][:headers] = payload['headers'] if payload['headers']
59
57
  res
60
58
  end
59
+
60
+ private
61
+
62
+ def processed_sdk_calls
63
+ auth_keys = last_identify_id
64
+
65
+ observed[:sdk].map do |meth, time, *args|
66
+ {
67
+ :name => meth,
68
+ :time => time,
69
+ :args => inject_identifiers(args, meth, auth_keys),
70
+ }
71
+ end
72
+ end
73
+
74
+ def inject_identifiers(args, meth, auth_keys)
75
+ return args unless meth == :track && auth_keys
76
+
77
+ track_opts = args[1] || {}
78
+ if track_opts[:user_identifiers].nil?
79
+ args[1] = track_opts.dup
80
+ args[1][:user_identifiers] = auth_keys
81
+ elsif track_opts[:user_identifiers] != auth_keys
82
+ Sqreen.log.warn 'Sqreen.identify and Sqreen.track have been called ' \
83
+ 'with different user_identifiers values'
84
+ end
85
+
86
+ args
87
+ end
88
+
89
+ def last_identify_id
90
+ return nil unless observed[:sdk]
91
+
92
+ observed[:sdk].reverse_each do |meth, _time, *args|
93
+ next unless meth == :identify
94
+ return args.first if args.respond_to? :first
95
+ end
96
+ nil
97
+ end
61
98
  end
62
99
  end
@@ -44,16 +44,30 @@ module Sqreen
44
44
  ENV['RACK_ENV'] == 'development'
45
45
  end
46
46
 
47
- PREFFERED_IP_HEADERS = %w(HTTP_X_FORWARDED_FOR HTTP_X_REAL_IP
47
+ PREFERRED_IP_HEADERS = %w[HTTP_X_FORWARDED_FOR HTTP_X_REAL_IP
48
48
  HTTP_CLIENT_IP HTTP_X_FORWARDED
49
49
  HTTP_X_CLUSTER_CLIENT_IP HTTP_FORWARDED_FOR
50
- HTTP_FORWARDED HTTP_VIA).freeze
50
+ HTTP_FORWARDED HTTP_VIA].freeze
51
+
52
+ def preferred_ip_headers
53
+ @preferred_ip_headers ||=
54
+ begin
55
+ header_name = Sqreen.config_get(:ip_header)
56
+ if header_name
57
+ env_var = 'HTTP_' + header_name.tr('-', '_').upcase
58
+ [env_var] + (PREFERRED_IP_HEADERS - [env_var])
59
+ else
60
+ PREFERRED_IP_HEADERS
61
+ end
62
+ end
63
+ end
64
+ private :preferred_ip_headers
51
65
 
52
66
  def ip_headers
53
67
  req = request
54
68
  return [] unless req
55
69
  ips = []
56
- (PREFFERED_IP_HEADERS + ['REMOTE_ADDR']).each do |header|
70
+ (preferred_ip_headers + ['REMOTE_ADDR']).each do |header|
57
71
  v = req.env[header]
58
72
  ips << [header, v] unless v.nil?
59
73
  end
@@ -79,7 +93,7 @@ module Sqreen
79
93
  return nil unless req
80
94
  # Look for an external address being forwarded
81
95
  split_ips = []
82
- PREFFERED_IP_HEADERS.each do |header_name|
96
+ preferred_ip_headers.each do |header_name|
83
97
  forwarded = req.env[header_name]
84
98
  ips = split_ip_addresses(forwarded)
85
99
  lip = ips.find { |ip| (ip !~ TRUSTED_PROXIES) && valid_ip?(ip) }
@@ -11,6 +11,7 @@ require 'sqreen/rules_signature'
11
11
  require 'sqreen/shared_storage'
12
12
  require 'sqreen/rules_callbacks/record_request_context'
13
13
  require 'sqreen/rules_callbacks/run_req_start_actions'
14
+ require 'sqreen/rules_callbacks/run_block_user_actions'
14
15
  require 'set'
15
16
 
16
17
  # How to override a class method:
@@ -245,6 +246,10 @@ module Sqreen
245
246
  def self.define_callback_method(meth, original_meth, klass_name)
246
247
  @sqreen_multi_instr ||= nil
247
248
  proc do |*args, &block|
249
+ record_req_hp = @@record_request_hookpoints.include?([klass_name, meth]) &&
250
+ Sqreen::PerformanceNotifications.listen_for?
251
+ Sqreen::PerformanceNotifications::BinnedMetrics.start_request if record_req_hp
252
+
248
253
  budget = nil
249
254
  skip_call = Thread.current[:sqreen_in_use]
250
255
  begin
@@ -370,6 +375,7 @@ module Sqreen
370
375
  next unless ret.is_a? Hash
371
376
  case ret[:status]
372
377
  when :raise, 'raise'
378
+ raise ret[:exception] if ret.key?(:exception)
373
379
  raise Sqreen::AttackBlocked, "Sqreen blocked a security threat (type: #{ret[:rule_name]}). No action is required."
374
380
  when :override, 'override'
375
381
  result = ret[:new_return_value]
@@ -379,10 +385,11 @@ module Sqreen
379
385
  end
380
386
  result
381
387
  ensure
382
- if @@record_request_hookpoints.include?([klass_name, meth]) && Sqreen::PerformanceNotifications.listen_for?
388
+ if record_req_hp
383
389
  Sqreen::PerformanceNotifications.instrument('Callbacks/hooks_reporting/pre') do
384
390
  Sqreen::PerformanceNotifications::LogPerformance.next_request
385
391
  Sqreen::PerformanceNotifications::NewRelic.next_request
392
+ Sqreen::PerformanceNotifications::BinnedMetrics.finish_request
386
393
  end
387
394
  end
388
395
  Thread.current[:sqreen_in_use] = false
@@ -439,6 +446,8 @@ module Sqreen
439
446
  end
440
447
  alias_method meth, saved_meth_name
441
448
  send(method_kind, meth)
449
+
450
+ remove_method saved_meth_name
442
451
  end
443
452
  end
444
453
 
@@ -450,6 +459,15 @@ module Sqreen
450
459
  saved_meth_name = get_saved_method_name(meth)
451
460
  new_method = "#{meth}_modified".to_sym
452
461
 
462
+ # do not include ancestors o/wise we might get a saved method from a
463
+ # superclass which is never called because the original name
464
+ # (instrumented) method of the superclass has been overridden
465
+ private_meths = klass_name.private_instance_methods(false)
466
+ if private_meths.include?(saved_meth_name)
467
+ Sqreen.log.debug { "#{saved_meth_name} found #{klass_name}##{meth} already instrumented" }
468
+ return saved_meth_name
469
+ end
470
+
453
471
  p = Instrumentation.define_callback_method(meth, saved_meth_name,
454
472
  klass_name)
455
473
  method_kind = nil
@@ -664,7 +682,9 @@ module Sqreen
664
682
  # @return [Array<Sqreen::CB>]
665
683
  def hardcoded_callbacks(framework)
666
684
  [
667
- Sqreen::Rules::RunReqStartActions.new(framework)
685
+ Sqreen::Rules::RunReqStartActions.new(framework),
686
+ Sqreen::Rules::RunBlockUserActions.new(Sqreen, :identify, 0),
687
+ Sqreen::Rules::RunBlockUserActions.new(Sqreen, :auth_track, 1),
668
688
  ]
669
689
  end
670
690
 
@@ -4,3 +4,4 @@
4
4
  require 'sqreen/metrics/collect'
5
5
  require 'sqreen/metrics/average'
6
6
  require 'sqreen/metrics/sum'
7
+ require 'sqreen/metrics/binning'
@@ -0,0 +1,74 @@
1
+ # Copyright (c) 2018 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
+
4
+ require 'sqreen/metrics/base'
5
+
6
+ module Sqreen
7
+ module Metric
8
+ # Takes numbers as samples and bins them (effectively, rounds them).
9
+ class Binning < Base
10
+ # upper bound of i-th bin is factor * base^(i-1)
11
+ def initialize(base, factor)
12
+ super()
13
+ @base = base
14
+ @factor = factor
15
+ log_base = Math.log(base)
16
+ log_factor = Math.log(factor)
17
+ @inv_log_base = 1 / log_base
18
+ @add_parcel = - log_factor / log_base
19
+ new_sample(Time.now.utc)
20
+ end
21
+
22
+ def update(_at, _key, x)
23
+ h = @sample[OBSERVATION_KEY]
24
+ bin = bin_no(x)
25
+ h[bin] += 1
26
+ end
27
+
28
+ def next_sample(time)
29
+ return nil if @sample[OBSERVATION_KEY].empty?
30
+ super(time)
31
+ end
32
+
33
+ protected
34
+
35
+ # these two are called by next_sample
36
+
37
+ def finalize_sample(time)
38
+ @sample[FINISH_KEY] = time
39
+ h = @sample[OBSERVATION_KEY]
40
+ @sample[OBSERVATION_KEY] = { 'u' => @factor, 'b' => @base, 'v' => h }
41
+ end
42
+
43
+ def new_sample(time)
44
+ @sample = {
45
+ OBSERVATION_KEY => Hash.new { |hash, key| hash[key] = 0 },
46
+ START_KEY => time,
47
+ }
48
+ end
49
+
50
+ private
51
+
52
+ def bin_no(x)
53
+ res = 2 + (@inv_log_base * Math.log(x) + @add_parcel).floor
54
+ res < 1 ? 1 : res
55
+ end
56
+ end
57
+
58
+ # overrides the constructor
59
+ class ParameterizedBinning < Binning
60
+ def initialize
61
+ raise 'Not configured' unless self.class.base && self.class.factor
62
+ super(self.class.base, self.class.factor)
63
+ end
64
+
65
+ class << self
66
+ attr_reader :base, :factor
67
+ def parameters(opts)
68
+ @base = opts[:base]
69
+ @factor = opts[:factor]
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -33,7 +33,7 @@ module Sqreen
33
33
 
34
34
  # Definition contains a name,period and aggregate at least
35
35
  # @param definition [Hash] a metric definition
36
- # @param klass [Object] Override metric class (used in testing)
36
+ # @param mklass [Object] Override metric object (used in testing)
37
37
  def create_metric(definition, mklass = nil)
38
38
  name = definition[NAME_KEY]
39
39
  kind = definition[KIND_KEY]
@@ -47,6 +47,10 @@ module Sqreen
47
47
  metric
48
48
  end
49
49
 
50
+ def metric?(name)
51
+ @metrics.key?(name)
52
+ end
53
+
50
54
  def update(name, at, key, value)
51
55
  at = at.utc
52
56
  metric, period, start = @metrics[name]
@@ -71,7 +75,7 @@ module Sqreen
71
75
  def next_sample(name, at)
72
76
  metric = @metrics[name][0]
73
77
  r = metric.next_sample(at)
74
- @metrics[name][2] = at
78
+ @metrics[name][2] = at # start
75
79
  if r
76
80
  r[NAME_KEY] = name
77
81
  obs = r[Metric::OBSERVATION_KEY]
@@ -0,0 +1,119 @@
1
+ # Copyright (c) 2018 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
+
4
+ require 'sqreen/performance_notifications'
5
+
6
+ module Sqreen
7
+ #
8
+ module PerformanceNotifications
9
+ # Logs callback performance
10
+ class BinnedMetrics
11
+ EVENT_REQ = 'req'.freeze # request total time
12
+ EVENT_TOTAL_TIME = 'sq'.freeze # sqreen total overhead callback time
13
+
14
+ EVT_NAME_REGEXP = %r{\ACallbacks/([^/]+)/([^/]+)\z}
15
+
16
+ # @param metrics_store [Sqreen::MetricsStore]
17
+ def initialize(metrics_store, period)
18
+ @metrics_store = metrics_store
19
+ @period = period
20
+ @subid = nil
21
+ end
22
+
23
+ def enable
24
+ return unless @subid.nil?
25
+
26
+ metrics_store.create_metric(
27
+ 'name' => EVENT_REQ, 'period' => period, 'kind' => 'ParameterizedBinning'
28
+ )
29
+ metrics_store.create_metric(
30
+ 'name' => EVENT_TOTAL_TIME, 'period' => period, 'kind' => 'ParameterizedBinning'
31
+ )
32
+
33
+ @subid = Sqreen::PerformanceNotifications.subscribe(&method(:log))
34
+ end
35
+
36
+ def disable
37
+ return if @subid.nil?
38
+ Sqreen::PerformanceNotifications.unsubscribe(@subid)
39
+ @subid = nil
40
+ end
41
+
42
+ def log(event, start, finish, _meta)
43
+ return unless event =~ EVT_NAME_REGEXP
44
+ rule, cb = Regexp.last_match.captures
45
+
46
+ metric_name = "sq.#{rule}.#{cb}"
47
+ ensure_metric(metric_name)
48
+
49
+ finish_time = SQREEN_MONO_TIME ? Time.now.utc : finish
50
+ time_millis = (finish - start) * 1000
51
+ SharedStorage[:sqreen_request_time] += time_millis
52
+ metrics_store.update(metric_name, finish_time, nil, time_millis)
53
+ end
54
+
55
+ def start_request
56
+ SharedStorage[:request_start_time] = PerformanceNotifications.time
57
+ SharedStorage[:sqreen_request_time] = 0.0
58
+ end
59
+
60
+ def finish_request
61
+ start_time = SharedStorage[:request_start_time]
62
+ finish_time = PerformanceNotifications.time
63
+ duration_millis = (finish_time - start_time) * 1000
64
+
65
+ finish_time_obj = SQREEN_MONO_TIME ? Time.now.utc : finish_time
66
+ # format of evt is [cat, key, value, timestamp]
67
+ Sqreen.observations_queue.push(
68
+ [EVENT_REQ, nil, duration_millis, finish_time_obj]
69
+ )
70
+ Sqreen.observations_queue.push(
71
+ [EVENT_TOTAL_TIME, nil,
72
+ SharedStorage[:sqreen_request_time], finish_time_obj]
73
+ )
74
+ end
75
+
76
+ private
77
+
78
+ # @return [Sqreen::MetricsStore]
79
+ attr_reader :metrics_store
80
+ attr_reader :period
81
+
82
+ def ensure_metric(metric_name)
83
+ return if metrics_store.metric?(metric_name)
84
+ metrics_store.create_metric(
85
+ 'name' => metric_name, 'period' => period, 'kind' => 'ParameterizedBinning'
86
+ )
87
+ end
88
+
89
+ @instance = nil
90
+ class << self
91
+ # @return [Sqreen::PerformanceNotifications::BinnedMetrics]
92
+ attr_reader :instance
93
+ def enable(metrics_store, period = 60, base = 2.0, factor = 0.1)
94
+ disable
95
+ Sqreen::Metric::ParameterizedBinning.parameters(
96
+ :base => base, :factor => factor
97
+ )
98
+ @instance = new(metrics_store, period).tap(&:enable)
99
+ end
100
+
101
+ def disable
102
+ return unless instance
103
+ instance.disable
104
+ @instance = nil
105
+ end
106
+
107
+ def start_request
108
+ return unless instance
109
+ instance.start_request
110
+ end
111
+
112
+ def finish_request
113
+ return unless instance
114
+ instance.finish_request
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,34 @@
1
+ # Copyright (c) 2018 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
+
4
+ require 'sqreen/rule_callback'
5
+ require 'sqreen/actions'
6
+
7
+ module Sqreen
8
+ module Rules
9
+ # Runs the block_user actions (for hooking Sqreen.{identify,auth_user})
10
+ class RunBlockUserActions < CB
11
+ def initialize(klass, method, auth_keys_idx)
12
+ super(klass, method)
13
+ @auth_keys_idx = auth_keys_idx
14
+ end
15
+
16
+ def post(_retval, _inst, args, _budget = nil)
17
+ actions = actions_repo[Sqreen::Actions::BlockUser]
18
+
19
+ actions.each do |action|
20
+ res = action.run args[@auth_keys_idx]
21
+ return res unless res.nil?
22
+ end
23
+ nil
24
+ end
25
+
26
+ private
27
+
28
+ # @return [Sqreen::Actions::Repository]
29
+ def actions_repo
30
+ Sqreen::Actions::Repository.instance
31
+ end
32
+ end
33
+ end
34
+ end
data/lib/sqreen/runner.rb CHANGED
@@ -17,6 +17,7 @@ require 'sqreen/metrics_store'
17
17
  require 'sqreen/deliveries/simple'
18
18
  require 'sqreen/deliveries/batch'
19
19
  require 'sqreen/performance_notifications/metrics'
20
+ require 'sqreen/performance_notifications/binned_metrics'
20
21
  require 'sqreen/instrumentation'
21
22
  require 'sqreen/call_countable'
22
23
 
@@ -30,6 +31,11 @@ module Sqreen
30
31
 
31
32
  METRICS_EVENT = 'metrics'.freeze
32
33
 
34
+ PERF_METRICS_PERIOD = 60 # 1 min
35
+ DEFAULT_PERF_LEVEL = 0 # disabled
36
+ DEFAULT_PERF_UNIT = 0.1 # ms
37
+ DEFAULT_PERF_BASE = 2.0
38
+
33
39
  class << self
34
40
  attr_reader :features
35
41
  def update_features(features)
@@ -204,6 +210,20 @@ module Sqreen
204
210
  end
205
211
  end
206
212
 
213
+ def config_binned_metrics(level, base, factor)
214
+ level = level.to_i
215
+ if level <= 0
216
+ Sqreen.log.debug('Disabling binned metrics')
217
+ PerformanceNotifications::BinnedMetrics.disable
218
+ else
219
+ Sqreen.log.warn("Unknown value for perf_level: #{level}. Treating as 1") unless level == 1
220
+ PerformanceNotifications::BinnedMetrics.enable(
221
+ metrics_engine, PERF_METRICS_PERIOD, base.to_f, factor.to_f
222
+ )
223
+ end
224
+ end
225
+
226
+
207
227
  def setup_instrumentation(context_infos = {})
208
228
  Sqreen.log.info 'setup instrumentation'
209
229
  rulespack_id, rules = load_rules(context_infos)
@@ -282,6 +302,9 @@ module Sqreen
282
302
  Sqreen.update_features(features)
283
303
  session.request_compression = features['request_compression'] if session
284
304
  self.performance_metrics_period = features['performance_metrics_period']
305
+ config_binned_metrics(features['perf_level'] || DEFAULT_PERF_LEVEL,
306
+ features['perf_base'] || DEFAULT_PERF_BASE,
307
+ features['perf_unit'] || DEFAULT_PERF_UNIT)
285
308
  self.call_counts_metrics_period = features['call_counts_metrics_period']
286
309
  hd = features['heartbeat_delay'].to_i
287
310
  self.heartbeat_delay = hd if hd > 0
data/lib/sqreen/sdk.rb CHANGED
@@ -36,13 +36,13 @@ module Sqreen
36
36
  # For internal usage. Users are to call track() instead.
37
37
  def internal_track(event_name, options = {})
38
38
  properties = options[:properties]
39
- authentication_keys = options[:user_identifiers]
39
+ user_identifiers = options[:user_identifiers]
40
40
  timestamp = options[:timestamp] || Time.now.utc
41
41
  # Not in SDK v0
42
42
  # request = options[:request]
43
43
 
44
44
  args = {}
45
- args[:authentication_keys] = authentication_keys if authentication_keys
45
+ args[:user_identifiers] = user_identifiers if user_identifiers
46
46
  args[:properties] = properties if properties
47
47
 
48
48
  Sqreen.framework.observe(
@@ -33,3 +33,8 @@ end
33
33
 
34
34
  # Change SharedStorage.get if ruby is actually newer
35
35
  require 'sqreen/shared_storage23' if RUBY_VERSION >= '2.3.0'
36
+
37
+ class << Sqreen::SharedStorage
38
+ alias [] get
39
+ alias []= set
40
+ end
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
2
  # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
3
  module Sqreen
4
- VERSION = '1.12.0'.freeze
4
+ VERSION = '1.13.0'.freeze
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sqreen
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.0
4
+ version: 1.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sqreen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-31 00:00:00.000000000 Z
11
+ date: 2018-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: execjs
@@ -81,12 +81,14 @@ files:
81
81
  - lib/sqreen/metrics.rb
82
82
  - lib/sqreen/metrics/average.rb
83
83
  - lib/sqreen/metrics/base.rb
84
+ - lib/sqreen/metrics/binning.rb
84
85
  - lib/sqreen/metrics/collect.rb
85
86
  - lib/sqreen/metrics/sum.rb
86
87
  - lib/sqreen/metrics_store.rb
87
88
  - lib/sqreen/middleware.rb
88
89
  - lib/sqreen/payload_creator.rb
89
90
  - lib/sqreen/performance_notifications.rb
91
+ - lib/sqreen/performance_notifications/binned_metrics.rb
90
92
  - lib/sqreen/performance_notifications/log.rb
91
93
  - lib/sqreen/performance_notifications/log_performance.rb
92
94
  - lib/sqreen/performance_notifications/metrics.rb
@@ -111,6 +113,7 @@ files:
111
113
  - lib/sqreen/rules_callbacks/record_request_context.rb
112
114
  - lib/sqreen/rules_callbacks/reflected_xss.rb
113
115
  - lib/sqreen/rules_callbacks/regexp_rule.rb
116
+ - lib/sqreen/rules_callbacks/run_block_user_actions.rb
114
117
  - lib/sqreen/rules_callbacks/run_req_start_actions.rb
115
118
  - lib/sqreen/rules_callbacks/shell_env.rb
116
119
  - lib/sqreen/rules_callbacks/url_matches.rb