sqreen 1.6.5 → 1.7.0

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
  SHA1:
3
- metadata.gz: cc4c4bcf86488934c2048d33804dd07398484e09
4
- data.tar.gz: 4d4bb6a78d00ef04d6d824f01f1194a156cb019b
3
+ metadata.gz: dc11a3a48f65cd5aaa1b4e0444b122cf12ae2c21
4
+ data.tar.gz: 85c6e6f370a1bb862f554679063057774f96e7ab
5
5
  SHA512:
6
- metadata.gz: 1ab651db3fb58f44551e4c04885da9bf0c7543a51c479565e8baf23cb7739d83b0b14196ac6958515462b34103542916875da9516cac8517b0f54a74cfa437ee
7
- data.tar.gz: b6886860a4d6a9d118bc675c4ea6b1e70fe6093c9cbda35691f89a9058e845b1270f75b67c9b2bbacd4f4e3a40b013fc5ba733c9cc8d269e5b2806a510c4b699
6
+ metadata.gz: b0d671840b6c605359512b50e23efef360f29d58944031ce0589683c64254a9d7205e91e7ecb6c17797a05e42c09b0d649a36c50de78468280fd4720eefe50b6
7
+ data.tar.gz: 7664d0468f7fd8e0ee71e03b325f02f5b0c76f53379046d2013232592dda05db0f3c9970db1ac046944ada579a42e87175077955485d649fdb207fdbe0e91589
@@ -58,6 +58,8 @@ module Sqreen
58
58
  # - { :status => :reraise }: reraise
59
59
  # - { :status => :override }: eat exception
60
60
  # - { :retry => :retry }: try the block again
61
+ #
62
+ # CB can also declare that they are whitelisted and should not be run at the moment.
61
63
 
62
64
  attr_reader :klass, :method
63
65
 
@@ -72,6 +74,10 @@ module Sqreen
72
74
  raise(Sqreen::Exception, 'No callback provided') unless @has_pre || @has_post || @has_failing
73
75
  end
74
76
 
77
+ def whitelisted?
78
+ false
79
+ end
80
+
75
81
  def pre?
76
82
  @has_pre
77
83
  end
@@ -45,7 +45,6 @@ module Sqreen
45
45
  res = {}
46
46
  rule_p = payload['rule']
47
47
  request_p = payload['request']
48
- whitelisted = request_p.delete('whitelisted') if request_p
49
48
  res[:rule_name] = rule_p['name'] if rule_p && rule_p['name']
50
49
  res[:rulespack_id] = rule_p['rulespack_id'] if rule_p && rule_p['rulespack_id']
51
50
  res[:test] = rule_p['test'] if rule_p && rule_p['test']
@@ -56,7 +55,6 @@ module Sqreen
56
55
  res[:params] = payload['params'] if payload['params']
57
56
  res[:context] = payload['context'] if payload['context']
58
57
  res[:headers] = payload['headers'] if payload['headers']
59
- res[:whitelist_match] = whitelisted if whitelisted
60
58
  res
61
59
  end
62
60
  end
@@ -291,8 +291,52 @@ module Sqreen
291
291
  Dir.getwd
292
292
  end
293
293
 
294
+ WHITELIST_KEY = 'sqreen.whitelisted_request'.freeze
295
+
296
+ # Return the current item that whitelist this request
297
+ # returns nil if request is not whitelisted
298
+ def whitelisted_match
299
+ return nil unless request
300
+ return request.env[WHITELIST_KEY] if request.env.key?(WHITELIST_KEY)
301
+ request.env[WHITELIST_KEY] = whitelisted_ip || whitelisted_path
302
+ end
303
+
304
+ # Returns the current path that whitelist the request
305
+ def whitelisted_path
306
+ path = request_path
307
+ return nil unless path
308
+ find_whitelisted_path(path)
309
+ end
310
+
311
+ # Returns the current path that whitelist the request
312
+ def whitelisted_ip
313
+ ip = client_ip
314
+ return nil unless ip
315
+ find_whitelisted_ip(ip)
316
+ rescue
317
+ nil
318
+ end
319
+
294
320
  protected
295
321
 
322
+ # Is this a whitelisted path?
323
+ # return the path witelisted prefix that match path
324
+ def find_whitelisted_path(rpath)
325
+ (Sqreen.whitelisted_paths || []).find do |path|
326
+ rpath.start_with?(path)
327
+ end
328
+ end
329
+
330
+ # Is this a whitelisted ip?
331
+ # return the ip witelisted range that match ip
332
+ def find_whitelisted_ip(rip)
333
+ ret = (Sqreen.whitelisted_ips || {}).find do |_, ip|
334
+ ip.include?(rip)
335
+ end
336
+ return nil unless ret
337
+ ret.first
338
+ end
339
+
296
340
  def hook_rack_request(klass)
297
341
  @calling_pid = Process.pid
298
342
  klass.class_eval do
@@ -33,6 +33,7 @@ require 'set'
33
33
 
34
34
  module Sqreen
35
35
  class Instrumentation
36
+ WHITELISTED_METRIC='whitelisted'.freeze
36
37
  @@override_semaphore = Mutex.new
37
38
 
38
39
  ## Overriden methods and callbacks globals
@@ -54,6 +55,7 @@ module Sqreen
54
55
  def self.callback_wrapper_pre(klass, method, instance, *args, &block)
55
56
  Instrumentation.guard_call(method, []) do
56
57
  callbacks = @@registered_callbacks.get(klass, method, :pre)
58
+ callbacks.reject!(&:whitelisted?)
57
59
 
58
60
  returns = []
59
61
  callbacks.each do |cb|
@@ -90,6 +92,7 @@ module Sqreen
90
92
  def self.callback_wrapper_post(klass, method, return_val, instance, *args, &block)
91
93
  Instrumentation.guard_call(method, []) do
92
94
  callbacks = @@registered_callbacks.get(klass, method, :post)
95
+ callbacks.reject!(&:whitelisted?)
93
96
 
94
97
  returns = []
95
98
  callbacks.reverse_each do |cb|
@@ -126,6 +129,7 @@ module Sqreen
126
129
  def self.callback_wrapper_failing(exception, klass, method, instance, *args, &block)
127
130
  Instrumentation.guard_call(method, []) do
128
131
  callbacks = @@registered_callbacks.get(klass, method, :failing)
132
+ callbacks.reject!(&:whitelisted?)
129
133
 
130
134
  returns = []
131
135
  callbacks.each do |cb|
@@ -506,11 +510,13 @@ module Sqreen
506
510
 
507
511
  def initialize(metrics_engine = nil)
508
512
  self.metrics_engine = metrics_engine
509
- unless metrics_engine.nil?
510
- metrics_engine.create_metric('name' => CallCountable::COUNT_CALLS,
511
- 'period' => 60,
512
- 'kind' => 'Sum')
513
- end
513
+ return if metrics_engine.nil?
514
+ metrics_engine.create_metric('name' => CallCountable::COUNT_CALLS,
515
+ 'period' => 60,
516
+ 'kind' => 'Sum')
517
+ metrics_engine.create_metric('name' => WHITELISTED_METRIC,
518
+ 'period' => 60,
519
+ 'kind' => 'Sum')
514
520
  end
515
521
  end
516
522
  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
- require "sqreen/log"
3
+ require 'sqreen/log'
4
+ require 'sqreen/events/remote_exception'
4
5
 
5
6
  module Sqreen
6
7
  # Execute and sanitize remote commands
@@ -13,6 +14,7 @@ module Sqreen
13
14
  :features_change => :change_features,
14
15
  :force_logout => :shutdown,
15
16
  :paths_whitelist => :change_whitelisted_paths,
17
+ :ips_whitelist => :change_whitelisted_ips,
16
18
  }.freeze
17
19
 
18
20
  attr_reader :uuid
@@ -27,7 +29,12 @@ module Sqreen
27
29
  failing = validate_command(runner)
28
30
  return failing if failing
29
31
  Sqreen.log.debug format('processing command %s', @name)
30
- output = runner.send(KNOWN_COMMANDS[@name], *@params, context_infos)
32
+ begin
33
+ output = runner.send(KNOWN_COMMANDS[@name], *@params, context_infos)
34
+ rescue => e
35
+ Sqreen::RemoteException.record(e)
36
+ return { :status => false, :reason => "error: #{e.inspect}" }
37
+ end
31
38
  format_output(output)
32
39
  end
33
40
 
@@ -46,39 +46,24 @@ module Sqreen
46
46
  @rule[Attrs::RULESPACK_ID]
47
47
  end
48
48
 
49
+ def whitelisted?
50
+ framework && !framework.whitelisted_match.nil?
51
+ end
52
+
49
53
  # Recommend taking an action (optionnally adding more data/context)
50
54
  #
51
55
  # This will format the requested action and optionnally
52
56
  # override it if it should not be taken (should not block for example)
53
57
  def advise_action(action, additional_data = {})
54
58
  return if action.nil? && additional_data.empty?
55
- if %w(override raise).include?(action.to_s) && framework
56
- prefix = find_whitelisted_path(framework.request_path.to_s)
57
- if prefix
58
- Sqreen.log.debug { "Trying to block on whitelisted path #{prefix}" }
59
- action = nil
60
- end
61
- end
62
59
  additional_data.merge(:status => action)
63
60
  end
64
61
 
65
- # Is this a whitelisted path?
66
- # return the path witelisted prefix that match path
67
- def find_whitelisted_path(rpath)
68
- (Sqreen.whitelisted_paths || []).find do |path|
69
- rpath.start_with?(path)
70
- end
71
- end
72
-
73
62
  # Record an attack event into Sqreen system
74
63
  # @param infos [Hash] Additional information about request
75
64
  def record_event(infos)
76
65
  payload = @payload_generator.payload(framework, @rule)
77
66
  payload['infos'] = infos
78
- if framework && payload['request']
79
- prefix = find_whitelisted_path(framework.request_path.to_s)
80
- payload['request']['whitelisted'] = prefix
81
- end
82
67
  Attack.record(payload)
83
68
  end
84
69
 
@@ -8,6 +8,7 @@ require 'sqreen/rules_callbacks/record_request_context'
8
8
  require 'sqreen/rules_callbacks/rails_parameters'
9
9
 
10
10
  require 'sqreen/rules_callbacks/headers_insert'
11
+ require 'sqreen/rules_callbacks/blacklist_ips'
11
12
 
12
13
  require 'sqreen/rules_callbacks/inspect_rule'
13
14
 
@@ -0,0 +1,44 @@
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 'ipaddr'
5
+
6
+ require 'sqreen/rule_callback'
7
+
8
+ module Sqreen
9
+ module Rules
10
+ # Looks for a blacklisted ip and block
11
+ class BlacklistIPsCB < RuleCB
12
+ def initialize(klass, method, rule_hash)
13
+ super(klass, method, rule_hash)
14
+ @ips = Hash[@data['values'].map { |v| [v, IPAddr.new(v)] }]
15
+ raise ArgumentError.new("no ips given") if @ips.empty?
16
+ end
17
+
18
+ def pre(_inst, *_args, &_block)
19
+ return unless framework
20
+ ip = framework.client_ip
21
+ return unless ip
22
+ found = find_blacklisted_ip(ip)
23
+ return unless found
24
+ Sqreen.log.debug { "Found blacklisted IP #{ip} - found: #{found}" }
25
+ record_observation('blacklisted', found, 1)
26
+ advise_action(:raise)
27
+ end
28
+
29
+ protected
30
+
31
+ # Is this a blacklisted ip?
32
+ # return the ip blacklisted range that match ip
33
+ def find_blacklisted_ip(rip)
34
+ ret = (@ips || {}).find do |_, ip|
35
+ ip.include?(rip)
36
+ end
37
+ return nil unless ret
38
+ ret.first
39
+ rescue
40
+ nil
41
+ end
42
+ end
43
+ end
44
+ end
@@ -3,6 +3,7 @@
3
3
 
4
4
  require 'sqreen/rule_attributes'
5
5
  require 'sqreen/rule_callback'
6
+ require 'sqreen/safe_json'
6
7
 
7
8
  module Sqreen
8
9
  module Rules
@@ -31,7 +32,7 @@ module Sqreen
31
32
  key = @accessors.map do |accessor|
32
33
  accessor.resolve(binding, framework, inst, args, @data, rv)
33
34
  end
34
- record_observation(@metric_category, JSON.dump(key), 1)
35
+ record_observation(@metric_category, SafeJSON.dump(key), 1)
35
36
  advise_action(nil)
36
37
  end
37
38
  end
@@ -73,6 +73,7 @@ module Sqreen
73
73
 
74
74
  def match(str)
75
75
  return if str.nil? || str.empty?
76
+ str = enforce_encoding(str)
76
77
  istr = str.downcase
77
78
 
78
79
  @string.each do |type, cases|
@@ -92,11 +93,35 @@ module Sqreen
92
93
  end
93
94
  end
94
95
 
95
- @regexp_patterns.each do |p|
96
- return p if p.match(str)
96
+ if defined?(Encoding)
97
+ @regexp_patterns.each do |p|
98
+ next unless Encoding.compatible?(p, str)
99
+ return p if p.match(str)
100
+ end
101
+ else
102
+ @regexp_patterns.each do |p|
103
+ warn(Encoding.compatible?(p, str).inspect)
104
+ return p if p.match(str)
105
+ end
97
106
  end
98
107
  nil
99
108
  end
109
+
110
+ private
111
+
112
+ def enforce_encoding(str)
113
+ return str unless str.is_a?(String)
114
+ return str if str.ascii_only?
115
+ encoded8bit = str.encoding.name == 'ASCII-8BIT'
116
+ return str if !encoded8bit && str.valid_encoding?
117
+ str.chars.map do |v|
118
+ if !v.valid_encoding? || (encoded8bit && !v.ascii_only?)
119
+ ''
120
+ else
121
+ v
122
+ end
123
+ end.join
124
+ end
100
125
  end
101
126
 
102
127
  # A configurable matcher rule
@@ -2,13 +2,26 @@
2
2
  # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
3
 
4
4
  require 'sqreen/rule_callback'
5
+ require 'sqreen/instrumentation'
5
6
 
6
7
  module Sqreen
7
8
  module Rules
8
9
  # Save request context for handling further down
9
10
  class RecordRequestContext < RuleCB
11
+ def whitelisted?
12
+ false
13
+ end
14
+
10
15
  def pre(_inst, *args, &_block)
11
16
  framework.store_request(args[0])
17
+ wh = framework.whitelisted_match
18
+ if wh
19
+ unless Sqreen.features.key?('whitelisted_metric') &&
20
+ !Sqreen.features['whitelisted_metric']
21
+ record_observation(Instrumentation::WHITELISTED_METRIC, wh, 1)
22
+ end
23
+ Sqreen.log.debug { "Request was whitelisted because of #{wh}" }
24
+ end
12
25
  advise_action(nil)
13
26
  end
14
27
 
@@ -47,8 +47,7 @@ module Sqreen
47
47
  return unless report_dangerous_xss?(saved_value)
48
48
 
49
49
  # potential XSS! let's escape
50
- if block &&
51
- (!framework || !find_whitelisted_path(framework.request_path.to_s))
50
+ if block
52
51
  args[0].replace(CGI.escape_html(value))
53
52
  end
54
53
 
@@ -150,9 +149,6 @@ module Sqreen
150
149
 
151
150
  return if !found_xss || !block
152
151
  # potential XSS! let's escape
153
- if framework && find_whitelisted_path(framework.request_path.to_s)
154
- return nil
155
- end
156
152
  args[-1] = new_attrs
157
153
  r = inst.send(method, *args)
158
154
  { :status => :skip, :new_return_value => r }
@@ -213,8 +209,7 @@ module Sqreen
213
209
 
214
210
  return unless block
215
211
  # potential XSS! let's escape
216
- if block &&
217
- (!framework || !find_whitelisted_path(framework.request_path.to_s))
212
+ if block
218
213
  args[0] = CGI.escape_html(value)
219
214
  r = inst.send(method, *args)
220
215
  return { :status => :skip, :new_return_value => r }
@@ -1,7 +1,6 @@
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
- require 'sqreen/rules_callbacks'
5
4
  require 'sqreen/exception'
6
5
 
7
6
  require 'set'
data/lib/sqreen/runner.rb CHANGED
@@ -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
 
4
+ require 'ipaddr'
4
5
  require 'timeout'
5
6
  require 'json'
6
7
 
@@ -53,6 +54,11 @@ module Sqreen
53
54
  def update_whitelisted_paths(paths)
54
55
  @whitelisted_paths = paths.freeze
55
56
  end
57
+
58
+ attr_reader :whitelisted_ips
59
+ def update_whitelisted_ips(paths)
60
+ @whitelisted_ips = Hash[paths.map { |v| [v, IPAddr.new(v)] }].freeze
61
+ end
56
62
  end
57
63
 
58
64
  # Main running job class for the agent
@@ -87,6 +93,7 @@ module Sqreen
87
93
  @token = @configuration.get(:token)
88
94
  @url = @configuration.get(:url)
89
95
  Sqreen.update_whitelisted_paths([])
96
+ Sqreen.update_whitelisted_ips({})
90
97
  raise(Sqreen::Exception, 'no url found') unless @url
91
98
  raise(Sqreen::TokenNotFoundException, 'no token found') unless @token
92
99
 
@@ -244,6 +251,12 @@ module Sqreen
244
251
  true
245
252
  end
246
253
 
254
+ def change_whitelisted_ips(ips, _context_infos = {})
255
+ return false unless ips.respond_to?(:each)
256
+ Sqreen.update_whitelisted_ips(ips)
257
+ true
258
+ end
259
+
247
260
  def change_features(new_features, _context_infos = {})
248
261
  old = features
249
262
  self.features = new_features
@@ -0,0 +1,60 @@
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 'json'
5
+
6
+ require 'sqreen/log'
7
+
8
+ module Sqreen
9
+ # Safely dump datastructure in json (more resilient to encoding errors)
10
+ class SafeJSON
11
+ def self.dump(data)
12
+ JSON.generate(data)
13
+ rescue JSON::GeneratorError, Encoding::UndefinedConversionError
14
+ Sqreen.log.debug('Payload could not be encoded enforcing recode')
15
+ JSON.generate(rencode_payload(data))
16
+ end
17
+
18
+ def self.rencode_payload(obj, max_depth = 20)
19
+ max_depth -= 1
20
+ return obj if max_depth < 0
21
+ return rencode_array(obj, max_depth) if obj.is_a?(Array)
22
+ return enforce_encoding(obj) unless obj.is_a?(Hash)
23
+ nobj = {}
24
+ obj.each do |k, v|
25
+ safe_k = rencode_payload(k, max_depth)
26
+ nobj[safe_k] = case v
27
+ when Array
28
+ rencode_array(v, max_depth)
29
+ when Hash
30
+ rencode_payload(v, max_depth)
31
+ when String
32
+ enforce_encoding(v)
33
+ else # for example integers
34
+ v
35
+ end
36
+ end
37
+ nobj
38
+ end
39
+
40
+ def self.rencode_array(array, max_depth)
41
+ array.map! { |e| rencode_payload(e, max_depth - 1) }
42
+ array
43
+ end
44
+
45
+ def self.enforce_encoding(str)
46
+ return str unless str.is_a?(String)
47
+ return str if str.ascii_only?
48
+ encoded8bit = str.encoding.name == 'ASCII-8BIT'
49
+ return str if !encoded8bit && str.valid_encoding?
50
+ r = str.chars.map do |v|
51
+ if !v.valid_encoding? || (encoded8bit && !v.ascii_only?)
52
+ v.bytes.map { |c| "\\x#{c.to_s(16).upcase}" }.join
53
+ else
54
+ v
55
+ end
56
+ end.join
57
+ "SqBytes[#{r}]"
58
+ end
59
+ end
60
+ end
@@ -6,9 +6,9 @@ require 'sqreen/serializer'
6
6
  require 'sqreen/runtime_infos'
7
7
  require 'sqreen/events/remote_exception'
8
8
  require 'sqreen/exception'
9
+ require 'sqreen/safe_json'
9
10
 
10
11
  require 'net/https'
11
- require 'json'
12
12
  require 'uri'
13
13
  require 'openssl'
14
14
  require 'zlib'
@@ -187,7 +187,7 @@ module Sqreen
187
187
  json_data = nil
188
188
  unless data.nil?
189
189
  serialized = Serializer.serialize(data)
190
- json_data = compress(self.class.encode_payload(serialized))
190
+ json_data = compress(SafeJSON.dump(serialized))
191
191
  end
192
192
  @con.post(path, json_data, headers)
193
193
  else
@@ -209,13 +209,6 @@ module Sqreen
209
209
  res
210
210
  end
211
211
 
212
- def self.encode_payload(data)
213
- JSON.generate(data)
214
- rescue JSON::GeneratorError, Encoding::UndefinedConversionError
215
- Sqreen.log.debug('Payload could not be encoded enforcing recode')
216
- JSON.generate(rencode_payload(data))
217
- end
218
-
219
212
  def compress(data)
220
213
  return data unless request_compression
221
214
  out = StringIO.new
@@ -225,47 +218,6 @@ module Sqreen
225
218
  out.string
226
219
  end
227
220
 
228
- def self.rencode_payload(obj, max_depth = 20)
229
- max_depth -= 1
230
- return obj if max_depth < 0
231
- return rencode_array(obj, max_depth) if obj.is_a?(Array)
232
- return enforce_encoding(obj) unless obj.is_a?(Hash)
233
- nobj = {}
234
- obj.each do |k, v|
235
- safe_k = rencode_payload(k, max_depth)
236
- nobj[safe_k] = case v
237
- when Array
238
- rencode_array(v, max_depth)
239
- when Hash
240
- rencode_payload(v, max_depth)
241
- when String
242
- enforce_encoding(v)
243
- else # for example integers
244
- v
245
- end
246
- end
247
- nobj
248
- end
249
-
250
- def self.rencode_array(array, max_depth)
251
- array.map! { |e| rencode_payload(e, max_depth - 1) }
252
- array
253
- end
254
-
255
- def self.enforce_encoding(str)
256
- return str unless str.is_a?(String)
257
- return str if str.ascii_only?
258
- encoded8bit = str.encoding.name == 'ASCII-8BIT'
259
- return str if !encoded8bit && str.valid_encoding?
260
- str.chars.map do |v|
261
- if !v.valid_encoding? || (encoded8bit && !v.ascii_only?)
262
- v.bytes.map { |c| "\\x#{c.to_s(16).upcase}" }.join
263
- else
264
- v
265
- end
266
- end.join
267
- end
268
-
269
221
  def login(framework)
270
222
  headers = { 'x-api-key' => @token }
271
223
 
@@ -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.6.5'.freeze
4
+ VERSION = '1.7.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.6.5
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sqreen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-09 00:00:00.000000000 Z
11
+ date: 2017-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: execjs
@@ -93,6 +93,7 @@ files:
93
93
  - lib/sqreen/rules_callbacks.rb
94
94
  - lib/sqreen/rules_callbacks/binding_accessor_matcher.rb
95
95
  - lib/sqreen/rules_callbacks/binding_accessor_metrics.rb
96
+ - lib/sqreen/rules_callbacks/blacklist_ips.rb
96
97
  - lib/sqreen/rules_callbacks/count_http_codes.rb
97
98
  - lib/sqreen/rules_callbacks/crawler_user_agent_matches.rb
98
99
  - lib/sqreen/rules_callbacks/crawler_user_agent_matches_metrics.rb
@@ -111,6 +112,7 @@ files:
111
112
  - lib/sqreen/rules_signature.rb
112
113
  - lib/sqreen/runner.rb
113
114
  - lib/sqreen/runtime_infos.rb
115
+ - lib/sqreen/safe_json.rb
114
116
  - lib/sqreen/sdk.rb
115
117
  - lib/sqreen/serializer.rb
116
118
  - lib/sqreen/session.rb
@@ -135,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
137
  version: '0'
136
138
  requirements: []
137
139
  rubyforge_project:
138
- rubygems_version: 2.6.11
140
+ rubygems_version: 2.6.12
139
141
  signing_key:
140
142
  specification_version: 4
141
143
  summary: Sqreen Ruby agent