sqreen 1.10.5-java → 1.11.0-java

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: 58abc14c547cc578aaf136de7ab1ec4171b64e1e3502177ac3c5d2490180ba22
4
- data.tar.gz: 42ef798d12119ceaa07ed590c4c9196a6ea28b2c6daf5f122949ece0cca9d7c5
3
+ metadata.gz: 53669623f0ae28ec6d69e5811956073c925f977a0beceda24756f4c2dc0b1bf5
4
+ data.tar.gz: dd62e44b9461fc8fac1bd11a511d1c4023fc152ced31afdaf17934ed82824e85
5
5
  SHA512:
6
- metadata.gz: b6acfc147fa7349d8c5535b77438402efaa674e9f1841fb58e59395100b82c469d62a0bac456b64e8dce3320378ec57113c6acbeee6b0c96a32af0bf1bb0c848
7
- data.tar.gz: c24b36e4be8bfdc3f727d8810ed79b5a9e403fab122fdf3c240442e7dbdf392ce9b4e6aeb098003019947fbd8213bb93ad81b457cd6f33a29bbb44edf6f5faa4
6
+ metadata.gz: 23dd698494d6913be0cf911d034ae7c51fa2969959f3758eed165958d390e6b80860f1c20d40298a3b1acf42456c0ca276dc65b0ab161cae917cf18ede700fb7
7
+ data.tar.gz: c9567b90cdeb4cf836cf8f20a0781e584d3cf3dddf09b83434ad70b91d3f17122660dfac4766cf818b08c77f22fcf6fbc13d84bfc2668e2257d26fcc2ad77e42
@@ -48,7 +48,7 @@ module Sqreen
48
48
  cbs = k[method]
49
49
  unless cbs
50
50
  Sqreen.log.debug { format('Error: no cbs registered for method %s.%s', klass, method) }
51
- Sqreen.log.debug { log(inspect) }
51
+ Sqreen.log.debug { inspect }
52
52
  return []
53
53
  end
54
54
 
@@ -3,6 +3,7 @@
3
3
 
4
4
  require 'set'
5
5
  require 'sqreen/shared_storage'
6
+ require 'sqreen/log'
6
7
 
7
8
  module Sqreen
8
9
 
@@ -67,6 +68,15 @@ module Sqreen
67
68
  def to_s
68
69
  format('#<%s: %s.%s>', self.class, @klass, @method)
69
70
  end
71
+
72
+ def overtime!
73
+ Sqreen.log.debug { "#{self} is overtime!" }
74
+ false
75
+ end
76
+
77
+ def framework
78
+ nil
79
+ end
70
80
  end
71
81
  # target_method, position, callback, callback class
72
82
 
@@ -11,8 +11,8 @@ module Sqreen
11
11
  def self.config_init(framework = nil)
12
12
  @config = Configuration.new(framework)
13
13
  @config.load!
14
- if @config && config_get(:report_perf_newrelic)
15
- Sqreen::PerformanceNotifications::NewRelic.enable
14
+ if @config && config_get(:report_perf_newrelic) > 0
15
+ Sqreen::PerformanceNotifications::NewRelic.enable(config_get(:report_perf_newrelic))
16
16
  end
17
17
  @config
18
18
  end
@@ -44,6 +44,8 @@ module Sqreen
44
44
  { :env => :SQREEN_BLOCK_ALL_RULES, :name => :block_all_rules,
45
45
  :default => nil },
46
46
  { :env => :SQREEN_REPORT_PERF_NR, :name => :report_perf_newrelic,
47
+ :default => 0, :convert => :to_int },
48
+ { :env => :SQREEN_REPORT_PERF, :name => :report_perf,
47
49
  :default => false, :convert => :to_bool },
48
50
  { :env => :SQREEN_INITIAL_FEATURES, :name => :initial_features,
49
51
  :default => nil },
@@ -53,7 +55,13 @@ module Sqreen
53
55
  CONFIG_FILE_NAME = 'sqreen.yml'.freeze
54
56
 
55
57
  def self.to_bool(value)
56
- %w[1 true].include?(value.to_s.downcase.strip)
58
+ %w[1 true].include?(value.to_s.downcase.strip)
59
+ end
60
+
61
+ def self.to_int(value)
62
+ str = value.to_s.downcase.strip
63
+ str = 1 if str == 'true'
64
+ str.to_i
57
65
  end
58
66
 
59
67
  # Class to access configurations variables
@@ -164,5 +172,9 @@ module Sqreen
164
172
  def to_bool(value)
165
173
  Sqreen::to_bool(value)
166
174
  end
175
+
176
+ def to_int(value)
177
+ Sqreen::to_int(value)
178
+ end
167
179
  end
168
180
  end
@@ -1,6 +1,7 @@
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
  require 'ipaddr'
4
+ require 'set'
4
5
 
5
6
  require 'sqreen/events/remote_exception'
6
7
  require 'sqreen/callbacks'
@@ -199,8 +200,8 @@ module Sqreen
199
200
  end
200
201
 
201
202
  # Does the parameters value include this value
202
- def params_include?(value)
203
- params = request_params
203
+ def params_include?(value, params = nil)
204
+ params = request_params if params.nil?
204
205
  return false if params.nil?
205
206
  each_value_for_hash(params) do |param|
206
207
  return true if param == value
@@ -209,8 +210,8 @@ module Sqreen
209
210
  end
210
211
 
211
212
  # Does the parameters key/value include this value
212
- def full_params_include?(value)
213
- params = request_params
213
+ def full_params_include?(value, params = nil)
214
+ params = request_params if params.nil?
214
215
  return false if params.nil?
215
216
  each_key_value_for_hash(params) do |param|
216
217
  return true if param == value
@@ -218,12 +219,22 @@ module Sqreen
218
219
  false
219
220
  end
220
221
 
222
+ def mark_request_overtime!
223
+ over = SharedStorage.get(:request_overtime)
224
+ return false if over
225
+ SharedStorage.set(:request_overtime, true)
226
+ true
227
+ end
228
+
221
229
  # Fetch and store the current request object
222
230
  # Nota: cleanup should be performed at end of request (see clean_request)
223
231
  def store_request(object)
224
232
  return unless ensure_rack_loaded
233
+ self.remaining_perf_budget = Sqreen.performance_budget
225
234
  SharedStorage.set(:request, Rack::Request.new(object))
226
235
  SharedStorage.inc(:stored_requests)
236
+ SharedStorage.set(:xss_params, nil)
237
+ SharedStorage.set(:request_overtime, nil)
227
238
  end
228
239
 
229
240
  # Get the currently stored request
@@ -236,7 +247,18 @@ module Sqreen
236
247
  return unless SharedStorage.dec(:stored_requests) <= 0
237
248
  payload_creator = Sqreen::PayloadCreator.new(self)
238
249
  close_request_record(Sqreen.queue, Sqreen.observations_queue, payload_creator)
250
+ self.remaining_perf_budget = nil
239
251
  SharedStorage.set(:request, nil)
252
+ SharedStorage.set(:xss_params, nil)
253
+ SharedStorage.set(:request_overtime, nil)
254
+ end
255
+
256
+ def remaining_perf_budget
257
+ SharedStorage.get(:performance_budget)
258
+ end
259
+
260
+ def remaining_perf_budget=(value)
261
+ SharedStorage.set(:performance_budget, value)
240
262
  end
241
263
 
242
264
  def request_params
@@ -347,6 +369,23 @@ module Sqreen
347
369
  request.env['REMOTE_ADDR']
348
370
  end
349
371
 
372
+ def xss_params(regexp = nil)
373
+ p = SharedStorage.get(:xss_params)
374
+ return p unless p.nil?
375
+ p = request_params
376
+ parm = Set.new
377
+ each_key_value_for_hash(p) do |value|
378
+ next unless value.is_a?(String)
379
+ next if value.size < 5
380
+ next if regexp && !regexp.match(value)
381
+ parm << value
382
+ end
383
+ p = parm.to_a
384
+ Sqreen.log.debug { "Filtered XSS params: #{p.inspect}" }
385
+ SharedStorage.set(:xss_params, p)
386
+ p
387
+ end
388
+
350
389
  protected
351
390
 
352
391
  # Is this a whitelisted path?
@@ -3,6 +3,8 @@
3
3
  require 'set'
4
4
  require 'sqreen/shared_storage'
5
5
  require 'sqreen/events/request_record'
6
+ require 'sqreen/performance_notifications/log_performance'
7
+ require 'sqreen/performance_notifications/newrelic'
6
8
 
7
9
  module Sqreen
8
10
  # Store event/observations that happened in this request
@@ -45,6 +47,8 @@ module Sqreen
45
47
  end
46
48
 
47
49
  def close_request_record(queue, observations_queue, payload_creator)
50
+ Sqreen::PerformanceNotifications::LogPerformance.next_request
51
+ Sqreen::PerformanceNotifications::NewRelic.next_request
48
52
  clean_request_record if observed_items.nil?
49
53
  if only_metric_observation
50
54
  push_metrics(observations_queue, queue)
@@ -34,6 +34,7 @@ require 'set'
34
34
  module Sqreen
35
35
  class Instrumentation
36
36
  WHITELISTED_METRIC='whitelisted'.freeze
37
+ OVERTIME_METRIC='request_overtime'.freeze
37
38
  @@override_semaphore = Mutex.new
38
39
 
39
40
  ## Overriden methods and callbacks globals
@@ -64,38 +65,52 @@ module Sqreen
64
65
  callbacks = callbacks.reject(&:whitelisted?)
65
66
  end
66
67
 
68
+ cb_with_framework = callbacks.find(&:framework)
69
+ budget = nil
70
+ budget = cb_with_framework.framework.remaining_perf_budget if cb_with_framework
67
71
  returns = []
68
72
  callbacks.each do |cb|
69
73
  # If record_request is part of callbacks we should filter after it ran
70
74
  next if cb.whitelisted?
71
75
  rule = cb.rule_name if cb.respond_to?(:rule_name)
76
+ if !budget.nil? && budget <= 0
77
+ next if cb.overtime!
78
+ end
72
79
  Sqreen.log.debug { "running pre cb #{cb}" }
73
- Sqreen::PerformanceNotifications.instrument("Callbacks/#{rule || cb.class.name}/pre") do
74
- begin
75
- res = cb.send(:pre, instance, *args, &block)
76
- if !res.nil? && cb.respond_to?(:block) && (!cb.block && !Sqreen.config_get(:block_all_rules))
77
- Sqreen.log.debug do
78
- "#{cb} cannot block, overriding return value"
79
- end
80
- res = nil
81
- elsif res.is_a?(Hash)
82
- res[:rule_name] = rule
83
- end
84
- returns << res
85
- rescue => e
86
- Sqreen.log.warn "we catch an exception: #{e.inspect}"
87
- Sqreen.log.debug e.backtrace
88
- if cb.respond_to?(:record_exception)
89
- cb.record_exception(e)
90
- else
91
- Sqreen::RemoteException.record(e)
80
+ begin
81
+ start = Sqreen::PerformanceNotifications.time
82
+ res = cb.send(:pre, instance, *args, &block)
83
+ stop = Sqreen::PerformanceNotifications.time
84
+ # The first few pre callbacks could not have a request & hence a budget just yet so we try harder to find it
85
+ budget = cb_with_framework.framework.remaining_perf_budget if budget.nil? && !Sqreen.performance_budget.nil? && cb.framework
86
+ budget -= (stop - start) unless budget.nil?
87
+ if !res.nil? && cb.respond_to?(:block) && (!cb.block && !Sqreen.config_get(:block_all_rules))
88
+ Sqreen.log.debug do
89
+ "#{cb} cannot block, overriding return value"
92
90
  end
93
- next
91
+ res = nil
92
+ elsif res.is_a?(Hash)
93
+ res[:rule_name] = rule
94
+ end
95
+ returns << res
96
+ rescue StandardError => e
97
+ Sqreen.log.warn "we catch an exception: #{e.inspect}"
98
+ Sqreen.log.debug e.backtrace
99
+ if cb.respond_to?(:record_exception)
100
+ cb.record_exception(e)
101
+ else
102
+ Sqreen::RemoteException.record(e)
94
103
  end
104
+ next
95
105
  end
106
+ Sqreen::PerformanceNotifications.notify("Callbacks/#{rule || cb.class.name}/pre", start, stop)
96
107
  end
108
+ cb_with_framework.framework.remaining_perf_budget=budget if cb_with_framework && !budget.nil?
97
109
  returns
98
110
  end
111
+ rescue StandardError => e
112
+ Sqreen.log.warn "we catched an exception between cbs: #{e.inspect}"
113
+ Sqreen::RemoteException.record(e)
99
114
  end
100
115
 
101
116
  def self.callback_wrapper_post(klass, method, return_val, instance, *args, &block)
@@ -105,36 +120,48 @@ module Sqreen
105
120
  callbacks = callbacks.reject(&:whitelisted?)
106
121
  end
107
122
 
123
+ cb_with_framework = callbacks.find(&:framework)
124
+ budget = nil
125
+ budget = cb_with_framework.framework.remaining_perf_budget if cb_with_framework
108
126
  returns = []
109
127
  callbacks.reverse_each do |cb|
110
128
  rule = cb.rule_name if cb.respond_to?(:rule_name)
129
+ if !budget.nil? && budget <= 0
130
+ next if cb.overtime!
131
+ end
111
132
  Sqreen.log.debug { "running post cb #{cb}" }
112
- Sqreen::PerformanceNotifications.instrument("Callbacks/#{rule || cb.class.name}/post") do
113
- begin
114
- res = cb.send(:post, return_val, instance, *args, &block)
115
- if !res.nil? && cb.respond_to?(:block) && (!cb.block && !Sqreen.config_get(:block_all_rules))
116
- Sqreen.log.debug do
117
- "#{cb} cannot block, overriding return value"
118
- end
119
- res = nil
120
- elsif res.is_a?(Hash)
121
- res[:rule_name] = rule
122
- end
123
- returns << res
124
- rescue => e
125
- Sqreen.log.warn "we catch an exception: #{e.inspect}"
126
- Sqreen.log.debug e.backtrace
127
- if cb.respond_to?(:record_exception)
128
- cb.record_exception(e)
129
- else
130
- Sqreen::RemoteException.record(e)
133
+ begin
134
+ start = Sqreen::PerformanceNotifications.time
135
+ res = cb.send(:post, return_val, instance, *args, &block)
136
+ stop = Sqreen::PerformanceNotifications.time
137
+ budget -= (stop - start) unless budget.nil?
138
+ if !res.nil? && cb.respond_to?(:block) && (!cb.block && !Sqreen.config_get(:block_all_rules))
139
+ Sqreen.log.debug do
140
+ "#{cb} cannot block, overriding return value"
131
141
  end
132
- next
142
+ res = nil
143
+ elsif res.is_a?(Hash)
144
+ res[:rule_name] = rule
145
+ end
146
+ returns << res
147
+ rescue => e
148
+ Sqreen.log.warn "we catch an exception: #{e.inspect}"
149
+ Sqreen.log.debug e.backtrace
150
+ if cb.respond_to?(:record_exception)
151
+ cb.record_exception(e)
152
+ else
153
+ Sqreen::RemoteException.record(e)
133
154
  end
155
+ next
134
156
  end
157
+ Sqreen::PerformanceNotifications.notify("Callbacks/#{rule || cb.class.name}/post", start, stop)
135
158
  end
159
+ cb_with_framework.framework.remaining_perf_budget=budget if cb_with_framework && !budget.nil? && !cb_with_framework.framework.remaining_perf_budget.nil?
136
160
  returns
137
161
  end
162
+ rescue StandardError => e
163
+ Sqreen.log.warn "we catched an exception between cbs: #{e.inspect}"
164
+ Sqreen::RemoteException.record(e)
138
165
  end
139
166
 
140
167
  def self.callback_wrapper_failing(exception, klass, method, instance, *args, &block)
@@ -144,36 +171,48 @@ module Sqreen
144
171
  callbacks = callbacks.reject(&:whitelisted?)
145
172
  end
146
173
 
174
+ cb_with_framework = callbacks.find(&:framework)
175
+ budget = nil
176
+ budget = cb_with_framework.framework.remaining_perf_budget if cb_with_framework
147
177
  returns = []
148
178
  callbacks.each do |cb|
149
179
  rule = cb.rule_name if cb.respond_to?(:rule_name)
180
+ if !budget.nil? && budget <= 0
181
+ next if cb.overtime!
182
+ end
150
183
  Sqreen.log.debug { "running failing cb #{cb}" }
151
- Sqreen::PerformanceNotifications.instrument("Callbacks/#{rule || cb.class.name}/failing") do
152
- begin
153
- res = cb.send(:failing, exception, instance, *args, &block)
154
- if !res.nil? && cb.respond_to?(:block) && (!cb.block && !Sqreen.config_get(:block_all_rules))
155
- Sqreen.log.debug do
156
- "#{cb} cannot block, overriding return value"
157
- end
158
- res = nil
159
- elsif res.is_a?(Hash)
160
- res[:rule_name] = rule
184
+ begin
185
+ start = Sqreen::PerformanceNotifications.time
186
+ res = cb.send(:failing, exception, instance, *args, &block)
187
+ stop = Sqreen::PerformanceNotifications.time
188
+ budget -= (stop - start) unless budget.nil?
189
+ if !res.nil? && cb.respond_to?(:block) && (!cb.block && !Sqreen.config_get(:block_all_rules))
190
+ Sqreen.log.debug do
191
+ "#{cb} cannot block, overriding return value"
161
192
  end
162
- returns << res
163
- rescue => e
164
- Sqreen.log.warn "we catch an exception: #{e.inspect}"
165
- Sqreen.log.debug e.backtrace
166
- if cb.respond_to?(:record_exception)
167
- cb.record_exception(e)
168
- else
169
- Sqreen::RemoteException.record(e)
170
- end
171
- next
193
+ res = nil
194
+ elsif res.is_a?(Hash)
195
+ res[:rule_name] = rule
172
196
  end
197
+ returns << res
198
+ rescue => e
199
+ Sqreen.log.warn "we catch an exception: #{e.inspect}"
200
+ Sqreen.log.debug e.backtrace
201
+ if cb.respond_to?(:record_exception)
202
+ cb.record_exception(e)
203
+ else
204
+ Sqreen::RemoteException.record(e)
205
+ end
206
+ next
173
207
  end
208
+ Sqreen::PerformanceNotifications.notify("Callbacks/#{rule || cb.class.name}/failing", start, stop)
174
209
  end
210
+ cb_with_framework.framework.remaining_perf_budget=budget if cb_with_framework && !budget.nil? && !cb_with_framework.framework.remaining_perf_budget.nil?
175
211
  returns
176
212
  end
213
+ rescue StandardError => e
214
+ Sqreen.log.warn "we catched an exception between cbs: #{e.inspect}"
215
+ Sqreen::RemoteException.record(e)
177
216
  end
178
217
 
179
218
  def self.guard_multi_call(instance, method, original_method, args, block)
@@ -594,6 +633,9 @@ module Sqreen
594
633
  metrics_engine.create_metric('name' => WHITELISTED_METRIC,
595
634
  'period' => 60,
596
635
  'kind' => 'Sum')
636
+ metrics_engine.create_metric('name' => OVERTIME_METRIC,
637
+ 'period' => 60,
638
+ 'kind' => 'Sum')
597
639
  end
598
640
  end
599
641
  end
@@ -4,6 +4,7 @@
4
4
  require 'logger'
5
5
 
6
6
  require 'sqreen/performance_notifications/log'
7
+ require 'sqreen/performance_notifications/log_performance'
7
8
  require 'sqreen/configuration'
8
9
 
9
10
  module Sqreen
@@ -105,6 +106,8 @@ module Sqreen
105
106
  log_level = ::Logger.const_get(level)
106
107
  @logger.level = log_level
107
108
  Sqreen::PerformanceNotifications::Log.enable if level == 'DEBUG'
109
+ return if level != 'DEBUG' && !Sqreen.config_get(:report_perf)
110
+ Sqreen::PerformanceNotifications::LogPerformance.enable
108
111
  end
109
112
 
110
113
  def create_error_logger
@@ -1,6 +1,13 @@
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
 
4
+ begin
5
+ Process.clock_gettime Process::CLOCK_MONOTONIC
6
+ SQREEN_MONO_TIME = Process::CLOCK_MONOTONIC
7
+ rescue StandardError
8
+ SQREEN_MONO_TIME = nil
9
+ end
10
+
4
11
  module Sqreen
5
12
  # This module enable us to keep track of sqreen resource usage
6
13
  #
@@ -27,6 +34,16 @@ module Sqreen
27
34
  id
28
35
  end
29
36
 
37
+ if SQREEN_MONO_TIME
38
+ def time
39
+ Process.clock_gettime(SQREEN_MONO_TIME)
40
+ end
41
+ else
42
+ def time
43
+ Time.now
44
+ end
45
+ end
46
+
30
47
  # Is there a subscriber for this key
31
48
  def listen_for?(key)
32
49
  return true unless @subscriptions_all.empty?
@@ -40,6 +57,13 @@ module Sqreen
40
57
  _instrument(key, meta, &block)
41
58
  end
42
59
 
60
+ def notify(key, start, stop, meta = {})
61
+ return unless listen_for?(key)
62
+ notifiers_for(key).each do |callable|
63
+ callable.call(key, start, stop, meta)
64
+ end
65
+ end
66
+
43
67
  # Unsubscrube for a given subscription
44
68
  def unsubscribe(subscription)
45
69
  return unless @subscriptions_all.delete(subscription).nil?
@@ -72,13 +96,21 @@ module Sqreen
72
96
  @subscriptions_all.values + str + reg
73
97
  end
74
98
 
75
- def _instrument(key, meta)
76
- start = Time.now
77
- yield
78
- ensure
79
- stop = Time.now
80
- notifiers_for(key).each do |callable|
81
- callable.call(key, start, stop, meta)
99
+ if SQREEN_MONO_TIME
100
+ def _instrument(key, meta)
101
+ start = Process.clock_gettime(SQREEN_MONO_TIME)
102
+ yield
103
+ ensure
104
+ stop = Process.clock_gettime(SQREEN_MONO_TIME)
105
+ notify(key, start, stop, meta)
106
+ end
107
+ else
108
+ def _instrument(key, meta)
109
+ start = Time.now
110
+ yield
111
+ ensure
112
+ stop = Time.now
113
+ notify(key, start, stop, meta)
82
114
  end
83
115
  end
84
116
  end
@@ -0,0 +1,70 @@
1
+ # Copyright (c) 2015 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
+ module PerformanceNotifications
8
+ # Log performances on the console
9
+ class LogPerformance < Log
10
+ @subid = nil
11
+ @facility = nil
12
+ class << self
13
+ def timings
14
+ v = SharedStorage.get(:log_performance_timings)
15
+ if v.nil?
16
+ v = []
17
+ self.timings = v
18
+ end
19
+ v
20
+ end
21
+
22
+ def timings=(value)
23
+ SharedStorage.set(:log_performance_timings, value)
24
+ end
25
+
26
+ def log(event, start, finish, _meta)
27
+ timings << [event, start, finish]
28
+ end
29
+
30
+ def enabled?
31
+ !@subid.nil?
32
+ end
33
+
34
+ def next_request
35
+ return unless enabled?
36
+ (@facility || Sqreen.log).warn do
37
+ output = timings.map do |evt, start, finish|
38
+ [evt.split('/')[1], (finish - start) * 1000]
39
+ end
40
+ self.timings = []
41
+ total = output.map(&:last).inject(0, &:+)
42
+ rules = output.inject({}) do |acc, (e, t)|
43
+ tt, cc = (acc[e] || [0, 0])
44
+ acc[e] = [tt + t, cc + 1]
45
+ acc
46
+ end
47
+ format(
48
+ "Sqreen request overhead:\n" +
49
+ ("%s: %.2fms (%d calls)\n" * rules.size) +
50
+ 'Total: %.2fms', *rules.to_a.sort_by { |e| e[1] }.flatten, total
51
+ )
52
+ end
53
+ end
54
+
55
+ def enable(facility = nil)
56
+ return unless @subid.nil?
57
+ @facility = facility
58
+ @subid = Sqreen::PerformanceNotifications.subscribe(nil,
59
+ &method(:log))
60
+ end
61
+
62
+ def disable
63
+ return if @subid.nil?
64
+ Sqreen::PerformanceNotifications.unsubscribe(@subid)
65
+ @subid = nil
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -12,7 +12,7 @@ module Sqreen
12
12
  class << self
13
13
  EVENT_CAT = 'sqreen_time'.freeze
14
14
  def log(event, start, finish, _meta)
15
- evt = [EVENT_CAT, event, (finish - start) * 1000, finish]
15
+ evt = [EVENT_CAT, event, (finish - start) * 1000, SQREEN_MONO_TIME ? Time.now.utc : finish]
16
16
  Sqreen.observations_queue.push(evt)
17
17
  end
18
18
 
@@ -8,18 +8,73 @@ module Sqreen
8
8
  # Log performances on the console
9
9
  class NewRelic
10
10
  @subid = nil
11
-
12
- @nr_name_regexp = %r{/([^/]+)$}
11
+ @level = 0
13
12
 
14
13
  class << self
14
+ def timings
15
+ v = SharedStorage.get(:log_performance_nr_timings)
16
+ if v.nil?
17
+ v = []
18
+ self.timings = v
19
+ end
20
+ v
21
+ end
22
+
23
+ def timings=(value)
24
+ SharedStorage.set(:log_performance_nr_timings, value)
25
+ end
26
+
15
27
  def log(event, start, finish, _meta)
16
- event_name = "Custom/Sqreen#{event.sub(@nr_name_regexp, '_\1')}"
17
- ::NewRelic::Agent.record_metric(event_name, finish - start)
28
+ timings << [event, start, finish]
29
+ end
30
+
31
+ def enabled?
32
+ !@subid.nil?
33
+ end
34
+
35
+ def report(hash)
36
+ if ::NewRelic::Agent.respond_to?(:add_custom_attributes)
37
+ return ::NewRelic::Agent.add_custom_attributes(hash)
38
+ end
39
+ ::NewRelic::Agent.add_custom_parameters(:user_id => @user.id)
40
+ end
41
+
42
+ def next_request
43
+ return unless enabled?
44
+ if @level == 1
45
+ overhead = timings.map do |_evt, start, finish|
46
+ (finish - start) * 1000
47
+ end.inject(0, &:+)
48
+ report('sqreen_time' => overhead)
49
+ else
50
+ output = timings.map do |evt, start, finish|
51
+ [evt.split('/')[1], (finish - start) * 1000]
52
+ end
53
+ total = 0
54
+ count = 0
55
+ rules = output.inject({}) do |acc, (e, t)|
56
+ tt, cc = (acc[e] || [0, 0])
57
+ acc[e] = [tt + t, cc + 1]
58
+ total += t
59
+ count += 1
60
+ acc
61
+ end
62
+ attrs = rules.inject('sqreen_time' => total, 'sqreen_count' => count) do |acc, (rule, values)|
63
+ acc["sqreen_#{rule}_time"] = values[0]
64
+ acc["sqreen_#{rule}_count"] = values[1]
65
+ acc
66
+ end
67
+ report(attrs)
68
+ end
69
+ self.timings = []
18
70
  end
19
71
 
20
- def enable
72
+ def enable(level = 0)
21
73
  return unless @subid.nil?
22
74
  return unless defined?(::NewRelic::Agent)
75
+ return unless ::NewRelic::Agent.respond_to?(:add_custom_attributes) || ::NewRelic::Agent.respond_to?(:add_custom_parameters)
76
+ return unless level > 0
77
+ @level = level
23
78
  Sqreen.log.debug('Enabling New Relic reporting')
24
79
  @subid = Sqreen::PerformanceNotifications.subscribe(nil,
25
80
  &method(:log))
@@ -29,6 +84,7 @@ module Sqreen
29
84
  return if @subid.nil?
30
85
  Sqreen::PerformanceNotifications.unsubscribe(@subid)
31
86
  @subid = nil
87
+ @level = 0
32
88
  end
33
89
  end
34
90
  end
@@ -16,6 +16,7 @@ module Sqreen
16
16
  :paths_whitelist => :change_whitelisted_paths,
17
17
  :ips_whitelist => :change_whitelisted_ips,
18
18
  :get_bundle => :upload_bundle,
19
+ :performance_budget => :change_performance_budget,
19
20
  }.freeze
20
21
 
21
22
  attr_reader :uuid
@@ -103,6 +103,17 @@ module Sqreen
103
103
  }
104
104
  framework.observe(:sqreen_exceptions, payload)
105
105
  end
106
+
107
+ def overtime!
108
+ Sqreen.log.debug { "rulecb #{self} is overtime!" }
109
+ return true if framework.nil? || !framework.mark_request_overtime!
110
+ record_observation(
111
+ 'request_overtime',
112
+ rule_name,
113
+ 1
114
+ )
115
+ true
116
+ end
106
117
  end
107
118
  end
108
119
  end
@@ -15,6 +15,10 @@ module Sqreen
15
15
  record_observation(METRIC_CATEGORY, rv[0], 1)
16
16
  advise_action(nil)
17
17
  end
18
+
19
+ def overtime!
20
+ false
21
+ end
18
22
  end
19
23
 
20
24
  # Count 1 for each things located by the binding accessor
@@ -59,6 +59,10 @@ module Sqreen
59
59
  }
60
60
  [@status_code, headers, page]
61
61
  end
62
+
63
+ def overtime!
64
+ false
65
+ end
62
66
  end
63
67
  end
64
68
  end
@@ -12,6 +12,10 @@ module Sqreen
12
12
  false
13
13
  end
14
14
 
15
+ def overtime!
16
+ false
17
+ end
18
+
15
19
  def pre(_inst, *args, &_block)
16
20
  framework.store_request(args[0])
17
21
  wh = framework.whitelisted_match
@@ -12,6 +12,15 @@ module Sqreen
12
12
  module Rules
13
13
  # XSSCB abstract common behaviour of tpls
14
14
  class XSSCB < RegexpRuleCB
15
+ def initialize(*args)
16
+ super(*args)
17
+ @union_pattern = Regexp.union(*@patterns)
18
+ end
19
+
20
+ def xss_params
21
+ return nil unless framework
22
+ framework.xss_params(@union_pattern)
23
+ end
15
24
  # The remaining code is only to find out if user entry was an attack,
16
25
  # and record it. Since we don't rely on it to respond to user, it would
17
26
  # be better to do it in background.
@@ -35,7 +44,7 @@ module Sqreen
35
44
 
36
45
  # Sqreen::log.debug value
37
46
 
38
- return unless framework.params_include?(value)
47
+ return unless xss_params.any? { |p| p == value }
39
48
 
40
49
  Sqreen.log.debug { format('Found unescaped user param: %s', value) }
41
50
 
@@ -62,7 +71,7 @@ module Sqreen
62
71
 
63
72
  # Sqreen::log.debug value
64
73
 
65
- return unless framework.params_include?(value)
74
+ return unless xss_params.any? { |p| p == value }
66
75
 
67
76
  Sqreen.log.debug { format('Found unescaped user param: %s', value) }
68
77
 
@@ -70,9 +79,7 @@ module Sqreen
70
79
  return unless report_dangerous_xss?(saved_value)
71
80
 
72
81
  # potential XSS! let's escape
73
- if block
74
- args[0].replace(CGI.escape_html(value))
75
- end
82
+ args[0].replace(CGI.escape_html(value)) if block
76
83
 
77
84
  advise_action(nil)
78
85
  end
@@ -85,16 +92,13 @@ module Sqreen
85
92
  class ReflectedXSSHamlCB < XSSCB
86
93
  def post(ret, _inst, *_args, &_block)
87
94
  value = ret
88
- return if value.nil?
89
-
90
- # Sqreen::log.debug value
95
+ return unless value.is_a?(String)
91
96
 
92
- return unless framework.full_params_include?(value)
97
+ # 99% of the time we return here
98
+ return unless xss_params.any? { |p| p == value }
93
99
 
94
100
  Sqreen.log.debug { format('Found unescaped user param: %s', value) }
95
101
 
96
- return unless value.is_a?(String)
97
-
98
102
  return unless report_dangerous_xss?(value)
99
103
 
100
104
  return unless block
@@ -117,6 +121,10 @@ module Sqreen
117
121
  end
118
122
  nil
119
123
  end
124
+
125
+ def overtime!
126
+ false
127
+ end
120
128
  end
121
129
 
122
130
  # Hook into haml4 tag parser
@@ -132,6 +140,10 @@ module Sqreen
132
140
  end
133
141
  nil
134
142
  end
143
+
144
+ def overtime!
145
+ false
146
+ end
135
147
  end
136
148
 
137
149
  class Haml4UtilInterpolationHookCB < RuleCB
@@ -147,13 +159,18 @@ module Sqreen
147
159
  if escapes.odd?
148
160
  res << '#{'
149
161
  else
162
+ # Use eval to get rid of string escapes
150
163
  content = eval('"' + Haml::Util.balance(scan, '{', '}', 1)[0][0...-1] + '"')
151
164
  content = "Haml::Helpers.html_escape((#{content}))" if escape_html
152
- res << '#{Sqreen.escape_haml((' + content + '))}' # Use eval to get rid of string escapes
165
+ res << '#{Sqreen.escape_haml((' + content + '))}'
153
166
  end
154
167
  end
155
168
  { :status => :skip, :new_return_value => res + rest }
156
169
  end
170
+
171
+ def overtime!
172
+ false
173
+ end
157
174
  end
158
175
 
159
176
  # Hook build attributes
@@ -161,8 +178,9 @@ module Sqreen
161
178
  def pre(inst, *args, &_block)
162
179
  return unless Haml::VERSION < '5'
163
180
  attrs = args[-1]
181
+ params = xss_params
164
182
  new_attrs, found_xss = Haml4CompilerBuildAttributeCB.clean_hash_key(attrs) do |key|
165
- if !key.nil? && key.is_a?(String) && framework.full_params_include?(key) && report_dangerous_xss?(key)
183
+ if !key.nil? && key.is_a?(String) && params.any? { |p| p == key } && report_dangerous_xss?(key)
166
184
  Sqreen.log.debug { format('Found unescaped user param: %s', key) }
167
185
  [CGI.escape_html(key), true]
168
186
  else
@@ -199,6 +217,10 @@ module Sqreen
199
217
  end
200
218
  [new_h, has_xss]
201
219
  end
220
+
221
+ def overtime!
222
+ false
223
+ end
202
224
  end
203
225
 
204
226
  class Haml5EscapableHookCB < RuleCB
@@ -206,6 +228,10 @@ module Sqreen
206
228
  args[0] = "Sqreen.escape_haml((#{args[0]}))"
207
229
  { :status => :modify_args, :args => args }
208
230
  end
231
+
232
+ def overtime!
233
+ false
234
+ end
209
235
  end
210
236
 
211
237
  # Hook into temple template rendering
@@ -214,6 +240,10 @@ module Sqreen
214
240
  ret[1] = "Sqreen.escape_temple((#{ret[1]}))"
215
241
  { :status => :override, :new_return_value => ret }
216
242
  end
243
+
244
+ def overtime!
245
+ false
246
+ end
217
247
  end
218
248
 
219
249
  # Hook into temple template rendering
@@ -222,7 +252,7 @@ module Sqreen
222
252
  value = args[0]
223
253
  return if value.nil?
224
254
 
225
- return unless framework.full_params_include?(value)
255
+ return unless xss_params.any? { |p| p == value }
226
256
 
227
257
  Sqreen.log.debug { format('Found unescaped user param: %s', value) }
228
258
 
@@ -59,6 +59,12 @@ module Sqreen
59
59
  def update_whitelisted_ips(paths)
60
60
  @whitelisted_ips = Hash[paths.map { |v| [v, IPAddr.new(v)] }].freeze
61
61
  end
62
+
63
+ attr_reader :performance_budget
64
+ def update_performance_budget(value)
65
+ return @performance_budget = nil if value.nil?
66
+ @performance_budget = value.to_f / 1000
67
+ end
62
68
  end
63
69
 
64
70
  # Main running job class for the agent
@@ -94,6 +100,7 @@ module Sqreen
94
100
  @url = @configuration.get(:url)
95
101
  Sqreen.update_whitelisted_paths([])
96
102
  Sqreen.update_whitelisted_ips({})
103
+ Sqreen.update_performance_budget(nil)
97
104
  raise(Sqreen::Exception, 'no url found') unless @url
98
105
  raise(Sqreen::TokenNotFoundException, 'no token found') unless @token
99
106
 
@@ -251,6 +258,13 @@ module Sqreen
251
258
  true
252
259
  end
253
260
 
261
+ def change_performance_budget(budget, _context_infos = {})
262
+ return false unless budget.nil? || budget.to_f > 0
263
+ prev = Sqreen.performance_budget
264
+ Sqreen.update_performance_budget(budget)
265
+ { :was => prev }
266
+ end
267
+
254
268
  def upload_bundle(_context_infos = {})
255
269
  t = Time.now
256
270
  session.post_bundle(RuntimeInfos.dependencies_signature, RuntimeInfos.dependencies)
@@ -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.10.5'.freeze
4
+ VERSION = '1.11.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.10.5
4
+ version: 1.11.0
5
5
  platform: java
6
6
  authors:
7
7
  - Sqreen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-22 00:00:00.000000000 Z
11
+ date: 2018-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: execjs
@@ -86,6 +86,7 @@ files:
86
86
  - lib/sqreen/payload_creator.rb
87
87
  - lib/sqreen/performance_notifications.rb
88
88
  - lib/sqreen/performance_notifications/log.rb
89
+ - lib/sqreen/performance_notifications/log_performance.rb
89
90
  - lib/sqreen/performance_notifications/metrics.rb
90
91
  - lib/sqreen/performance_notifications/newrelic.rb
91
92
  - lib/sqreen/remote_command.rb