sqreen 1.10.5-java → 1.11.0-java

Sign up to get free protection for your applications and to get access to all the features.
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