sqreen 1.18.2-java → 1.18.3-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.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/LICENSE +3 -0
  4. data/lib/sqreen/actions.rb +11 -337
  5. data/lib/sqreen/actions/base.rb +110 -0
  6. data/lib/sqreen/actions/block_ip.rb +32 -0
  7. data/lib/sqreen/actions/block_user.rb +44 -0
  8. data/lib/sqreen/actions/ip_range_indexed_action_class.rb +36 -0
  9. data/lib/sqreen/actions/ip_ranges_index.rb +36 -0
  10. data/lib/sqreen/actions/redirect_ip.rb +40 -0
  11. data/lib/sqreen/actions/redirect_user.rb +45 -0
  12. data/lib/sqreen/actions/repository.rb +24 -0
  13. data/lib/sqreen/actions/unknown_action_type.rb +16 -0
  14. data/lib/sqreen/actions/user_action_class.rb +41 -0
  15. data/lib/sqreen/agent.rb +4 -1
  16. data/lib/sqreen/attack_blocked.rb +17 -0
  17. data/lib/sqreen/binding_accessor.rb +9 -102
  18. data/lib/sqreen/binding_accessor/path_elem.rb +8 -0
  19. data/lib/sqreen/binding_accessor/transforms.rb +107 -0
  20. data/lib/sqreen/capped_queue.rb +2 -0
  21. data/lib/sqreen/{callbacks.rb → cb.rb} +1 -53
  22. data/lib/sqreen/{callback_tree.rb → cb_tree.rb} +2 -2
  23. data/lib/sqreen/condition_evaluator.rb +22 -5
  24. data/lib/sqreen/configuration.rb +5 -0
  25. data/lib/sqreen/default_cb.rb +20 -0
  26. data/lib/sqreen/deferred_logger.rb +63 -0
  27. data/lib/sqreen/deliveries.rb +10 -0
  28. data/lib/sqreen/deliveries/batch.rb +7 -1
  29. data/lib/sqreen/deliveries/simple.rb +5 -0
  30. data/lib/sqreen/dependency/detector.rb +1 -1
  31. data/lib/sqreen/dependency/libsqreen.rb +28 -0
  32. data/lib/sqreen/dependency/rails.rb +4 -0
  33. data/lib/sqreen/dependency/sinatra.rb +47 -14
  34. data/lib/sqreen/error_handling_middleware.rb +30 -0
  35. data/lib/sqreen/event.rb +2 -0
  36. data/lib/sqreen/events/attack.rb +2 -0
  37. data/lib/sqreen/events/request_record.rb +11 -56
  38. data/lib/sqreen/exception.rb +9 -40
  39. data/lib/sqreen/formatter_with_tid.rb +45 -0
  40. data/lib/sqreen/framework_cb.rb +28 -0
  41. data/lib/sqreen/frameworks.rb +7 -0
  42. data/lib/sqreen/frameworks/generic.rb +20 -2
  43. data/lib/sqreen/frameworks/rails.rb +2 -0
  44. data/lib/sqreen/frameworks/request_recorder.rb +3 -0
  45. data/lib/sqreen/frameworks/sinatra.rb +2 -0
  46. data/lib/sqreen/frameworks/sqreen_test.rb +2 -0
  47. data/lib/sqreen/instrumentation.rb +5 -5
  48. data/lib/sqreen/invalid_signature_exception.rb +8 -0
  49. data/lib/{sqreen-alt.rb → sqreen/js.rb} +6 -1
  50. data/lib/sqreen/js/call_context.rb +10 -0
  51. data/lib/sqreen/js/context_pool.rb +60 -0
  52. data/lib/sqreen/js/exec_js_runnable.rb +20 -0
  53. data/lib/sqreen/js/execjs_adapter.rb +6 -47
  54. data/lib/sqreen/js/executable_js.rb +12 -0
  55. data/lib/sqreen/js/js_service.rb +2 -22
  56. data/lib/sqreen/js/js_service_adapter.rb +18 -0
  57. data/lib/sqreen/js/mini_racer_adapter.rb +6 -180
  58. data/lib/sqreen/js/mini_racer_executable_js.rb +142 -0
  59. data/lib/sqreen/js/thread_local_exec_js_runnable.rb +47 -0
  60. data/lib/sqreen/log.rb +8 -188
  61. data/lib/sqreen/logger.rb +83 -0
  62. data/lib/sqreen/metrics_store.rb +3 -11
  63. data/lib/sqreen/metrics_store/already_registered_metric.rb +11 -0
  64. data/lib/sqreen/metrics_store/unknown_metric.rb +11 -0
  65. data/lib/sqreen/metrics_store/unregistered_metric.rb +11 -0
  66. data/lib/sqreen/middleware.rb +0 -34
  67. data/lib/sqreen/mono_time.rb +2 -0
  68. data/lib/sqreen/node.rb +44 -0
  69. data/lib/sqreen/not_implemented_yet.rb +8 -0
  70. data/lib/sqreen/null_logger.rb +24 -0
  71. data/lib/sqreen/payload_creator.rb +2 -19
  72. data/lib/sqreen/payload_creator/header_section.rb +28 -0
  73. data/lib/sqreen/prefix.rb +33 -0
  74. data/lib/sqreen/rails_middleware.rb +14 -0
  75. data/lib/sqreen/remote_command.rb +1 -8
  76. data/lib/sqreen/remote_command/failure_output.rb +11 -0
  77. data/lib/sqreen/rules.rb +32 -2
  78. data/lib/sqreen/{rule_attributes.rb → rules/attrs.rb} +0 -0
  79. data/lib/sqreen/{rules_callbacks/sdk_auth_track.rb → rules/auth_track_cb.rb} +2 -2
  80. data/lib/sqreen/{rules_callbacks/binding_accessor_matcher.rb → rules/binding_accessor_matcher_cb.rb} +4 -8
  81. data/lib/sqreen/{rules_callbacks → rules}/binding_accessor_metrics.rb +1 -1
  82. data/lib/sqreen/{rules_callbacks/blacklist_ips.rb → rules/blacklist_ips_cb.rb} +3 -2
  83. data/lib/sqreen/{rules_callbacks → rules}/count_http_codes.rb +2 -2
  84. data/lib/sqreen/{rules_callbacks/crawler_user_agent_matches.rb → rules/crawler_user_agent_matches_cb.rb} +1 -1
  85. data/lib/sqreen/{rules_callbacks/crawler_user_agent_matches_metrics.rb → rules/crawler_user_agent_matches_metrics_cb.rb} +1 -1
  86. data/lib/sqreen/{rules_callbacks/custom_error.rb → rules/custom_error_cb.rb} +1 -1
  87. data/lib/sqreen/{rules_callbacks/devise_auth_track.rb → rules/devise_auth_track_cb.rb} +2 -2
  88. data/lib/sqreen/{rules_callbacks/devise_signup_track.rb → rules/devise_signup_track_cb.rb} +2 -2
  89. data/lib/sqreen/{rules_callbacks/execjs.rb → rules/execjs_cb.rb} +49 -50
  90. data/lib/sqreen/{rules_callbacks/headers_insert.rb → rules/headers_insert_cb.rb} +1 -1
  91. data/lib/sqreen/{rules_callbacks → rules}/matcher_rule.rb +2 -2
  92. data/lib/sqreen/{rules_callbacks/not_found.rb → rules/not_found_cb.rb} +2 -2
  93. data/lib/sqreen/{rules_callbacks/rails_parameters.rb → rules/rails_parameters_cb.rb} +1 -1
  94. data/lib/sqreen/{rules_callbacks → rules}/record_request_context.rb +1 -1
  95. data/lib/sqreen/{rules_callbacks/regexp_rule.rb → rules/regexp_rule_cb.rb} +1 -1
  96. data/lib/sqreen/{rule_callback.rb → rules/rule_cb.rb} +2 -2
  97. data/lib/sqreen/{rules_callbacks → rules}/run_req_start_actions.rb +4 -2
  98. data/lib/sqreen/{rules_callbacks → rules}/run_user_actions.rb +1 -1
  99. data/lib/sqreen/{rules_callbacks/shell_env.rb → rules/shell_env_cb.rb} +1 -1
  100. data/lib/sqreen/{rules_callbacks/sdk_signup_track.rb → rules/signup_track_cb.rb} +2 -2
  101. data/lib/sqreen/rules/update_request_context.rb +20 -0
  102. data/lib/sqreen/{rules_callbacks/url_matches.rb → rules/url_matches_cb.rb} +1 -1
  103. data/lib/sqreen/{rules_callbacks/user_agent_matches.rb → rules/user_agent_matches_cb.rb} +1 -1
  104. data/lib/sqreen/{rules_callbacks/waf.rb → rules/waf_cb.rb} +10 -14
  105. data/lib/sqreen/{rules_callbacks/reflected_xss.rb → rules/xss_cb.rb} +10 -7
  106. data/lib/sqreen/run_when_called_cb.rb +21 -0
  107. data/lib/sqreen/runtime_infos.rb +2 -9
  108. data/lib/sqreen/sensitive_data_redactor.rb +111 -0
  109. data/lib/sqreen/signature_verifier.rb +20 -0
  110. data/lib/sqreen/sinatra_middleware.rb +14 -0
  111. data/lib/sqreen/{rules_signature.rb → sqreen_signed_verifier.rb} +5 -17
  112. data/lib/sqreen/token_invalid_exception.rb +8 -0
  113. data/lib/sqreen/token_not_found_exception.rb +9 -0
  114. data/lib/sqreen/trie.rb +3 -64
  115. data/lib/sqreen/unauthorized.rb +8 -0
  116. data/lib/sqreen/util.rb +2 -0
  117. data/lib/sqreen/util/capped_array.rb +33 -0
  118. data/lib/sqreen/util/capped_hash.rb +39 -0
  119. data/lib/sqreen/util/capped_string.rb +24 -0
  120. data/lib/sqreen/util/capper.rb +65 -0
  121. data/lib/sqreen/version.rb +1 -1
  122. data/lib/sqreen/waf_error.rb +18 -0
  123. metadata +87 -35
  124. data/lib/sqreen/rules_callbacks.rb +0 -35
  125. data/lib/sqreen/rules_callbacks/inspect_rule.rb +0 -25
@@ -3,8 +3,8 @@
3
3
 
4
4
  require 'cgi'
5
5
 
6
- require 'sqreen/rule_callback'
7
- require 'sqreen/rules_callbacks/regexp_rule'
6
+ require 'sqreen/rules/rule_cb'
7
+ require 'sqreen/rules/regexp_rule_cb'
8
8
 
9
9
  # Sqreen module
10
10
  module Sqreen
@@ -21,6 +21,7 @@ module Sqreen
21
21
  return nil unless framework
22
22
  framework.xss_params(@union_pattern)
23
23
  end
24
+
24
25
  # The remaining code is only to find out if user entry was an attack,
25
26
  # and record it. Since we don't rely on it to respond to user, it would
26
27
  # be better to do it in background.
@@ -36,6 +37,7 @@ module Sqreen
36
37
  true
37
38
  end
38
39
  end
40
+
39
41
  class ReflectedUnsafeXSSCB < XSSCB
40
42
  def pre(_inst, args, _budget = nil, &_block)
41
43
  value = args[0]
@@ -52,13 +54,12 @@ module Sqreen
52
54
  return unless report_dangerous_xss?(saved_value)
53
55
 
54
56
  # potential XSS! let's escape
55
- if block
56
- args[0].replace(CGI.escape_html(value))
57
- end
57
+ args[0].replace(CGI.escape_html(value)) if block
58
58
 
59
59
  advise_action(nil)
60
60
  end
61
61
  end
62
+
62
63
  # look for reflected XSS with erb template engine
63
64
  class ReflectedXSSCB < XSSCB
64
65
  def pre(_inst, args, _budget = nil, &_block)
@@ -84,6 +85,7 @@ module Sqreen
84
85
  advise_action(nil)
85
86
  end
86
87
  end
88
+
87
89
  # look for reflected XSS with haml template engine
88
90
  # hook function arguments of
89
91
  # Haml::Buffer.format_script(result, preserve_script, in_tag, preserve_tag,
@@ -145,7 +147,7 @@ module Sqreen
145
147
  if tag.value[:escape_html] == false &&
146
148
  tag.value[:value].respond_to?(:include?) &&
147
149
  !tag.value[:value].include?('html_escape') &&
148
- tag.value[:parse] == true
150
+ tag.value[:parse] == true
149
151
  tag.value[:value] = "Sqreen.escape_haml((#{tag.value[:value]}))"
150
152
  return { :status => :override, :new_return_value => tag }
151
153
  end
@@ -172,7 +174,8 @@ module Sqreen
172
174
  res << '#{'
173
175
  else
174
176
  # Use eval to get rid of string escapes
175
- content = eval('"' + Haml::Util.balance(scan, '{', '}', 1)[0][0...-1] + '"')
177
+ # TODO: look for eval removal
178
+ content = eval('"' + Haml::Util.balance(scan, '{', '}', 1)[0][0...-1] + '"') # rubocop:disable Security/Eval
176
179
  content = "Haml::Helpers.html_escape((#{content}))" if escape_html
177
180
  res << '#{Sqreen.escape_haml((' + content + '))}'
178
181
  end
@@ -0,0 +1,21 @@
1
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
3
+
4
+ require 'sqreen/cb'
5
+
6
+ module Sqreen
7
+ class RunWhenCalledCB < CB
8
+ def initialize(klass, method, &block)
9
+ super(klass, method)
10
+
11
+ raise 'missing block' unless block_given?
12
+ @block = block
13
+ end
14
+
15
+ def pre(_inst, _args, _budget = nil, &_block)
16
+ # FIXME: implement this removal
17
+ @remove_me = true
18
+ @block.call
19
+ end
20
+ end
21
+ end
@@ -3,6 +3,7 @@
3
3
 
4
4
  require 'sqreen/version'
5
5
  require 'sqreen/frameworks'
6
+ require 'sqreen/dependency/libsqreen'
6
7
 
7
8
  require 'socket'
8
9
  require 'digest/sha1'
@@ -71,15 +72,7 @@ module Sqreen
71
72
  end
72
73
 
73
74
  def libsqreen?
74
- libsqreen_loaded? && !libsqreen_stub?
75
- end
76
-
77
- def libsqreen_loaded?
78
- Kernel.const_defined?('LibSqreen')
79
- end
80
-
81
- def libsqreen_stub?
82
- !::LibSqreen.respond_to?(:version)
75
+ Sqreen::Dependency::LibSqreen.required? && !Sqreen::Dependency::LibSqreen.stub?
83
76
  end
84
77
 
85
78
  def libsqreen_version
@@ -0,0 +1,111 @@
1
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
3
+
4
+ # TODO: Sqreen.config_get
5
+
6
+ require 'json'
7
+ require 'sqreen/log'
8
+
9
+ module Sqreen
10
+ # For redacting sensitive data and avoid having it sent to our servers
11
+ class SensitiveDataRedactor
12
+ DEFAULT_SENSITIVE_KEYS = Set.new(%w[password secret passwd authorization api_key apikey access_token]).freeze
13
+ DEFAULT_REGEX = /\A(?:\d[ -]*?){13,16}\z/
14
+ MASK = '<Redacted by Sqreen>'.freeze
15
+
16
+ def self.from_config
17
+ keys = Sqreen.config_get(:strip_sensitive_keys)
18
+ keys = keys.split(',') if keys && keys.is_a?(String)
19
+
20
+ regex = Sqreen.config_get(:strip_sensitive_regex)
21
+ if regex && regex.is_a?(String)
22
+ begin
23
+ regex = Regexp.compile(regex)
24
+ rescue RegexpError
25
+ Sqreen.log.warn("Invalid regular expression given in strip_sensitive_regex: #{regex}")
26
+ regex = nil
27
+ end
28
+ else
29
+ regex = nil
30
+ end
31
+
32
+ new(keys: keys, regex: regex)
33
+ end
34
+
35
+ def initialize(params = {})
36
+ @regex = params[:regex] || DEFAULT_REGEX
37
+ @keys = (params[:keys] || DEFAULT_SENSITIVE_KEYS).map(&:downcase)
38
+ end
39
+
40
+ def redact(obj)
41
+ result = obj
42
+ redacted = []
43
+
44
+ case obj
45
+ when String
46
+ if obj =~ @regex
47
+ result = MASK
48
+ redacted << obj
49
+ end
50
+ when Array
51
+ result = []
52
+ obj.each do |e|
53
+ e, r = redact(e)
54
+ result << e
55
+ redacted += r
56
+ end
57
+ when Hash
58
+ result = {}
59
+ obj.each do |k, v|
60
+ ck = k.is_a?(String) ? k.downcase : k
61
+ if @keys.include?(ck)
62
+ redacted << v
63
+ v = MASK
64
+ else
65
+ v, r = redact(v)
66
+ redacted += r
67
+ end
68
+ result[k] = v
69
+ end
70
+ end
71
+
72
+ [result, redacted]
73
+ end
74
+
75
+ def redact_attacks!(attacks, values)
76
+ return attacks if values.empty?
77
+
78
+ values = values.map { |v| v.downcase if v.is_a?(String) }
79
+
80
+ attacks.each do |e|
81
+ next(e) unless e[:infos]
82
+ next(e) unless e[:infos][:waf_data]
83
+
84
+ parsed = JSON.parse(e[:infos][:waf_data])
85
+ redacted = parsed.each do |w|
86
+ next unless (filters = w['filter'])
87
+
88
+ filters.each do |f|
89
+ next unless (v = f['resolved_value'])
90
+ next unless values.include?(v.downcase)
91
+
92
+ f['match_status'] = MASK
93
+ f['resolved_value'] = MASK
94
+ end
95
+ end
96
+ e[:infos][:waf_data] = JSON.dump(redacted)
97
+ end
98
+ end
99
+
100
+ def redact_exceptions!(exceptions, values)
101
+ return exceptions if values.empty?
102
+
103
+ exceptions.each do |e|
104
+ next(e) unless e[:infos]
105
+ next(e) unless e[:infos][:waf]
106
+
107
+ e[:infos][:waf].delete(:args)
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,20 @@
1
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
3
+
4
+ require 'openssl'
5
+
6
+ ## Rules signature
7
+ module Sqreen
8
+ # Perform an EC + digest verification of a message.
9
+ class SignatureVerifier
10
+ def initialize(key, digest)
11
+ @pub_key = OpenSSL::PKey.read(key)
12
+ @digest = digest
13
+ end
14
+
15
+ def verify(sig, val)
16
+ hashed_val = @digest.digest(val)
17
+ @pub_key.dsa_verify_asn1(hashed_val, sig)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
3
+
4
+ module Sqreen
5
+ class SinatraMiddleware
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ @app.call(env)
12
+ end
13
+ end
14
+ end
@@ -1,8 +1,6 @@
1
1
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
2
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
3
3
 
4
- require 'sqreen/exception'
5
-
6
4
  require 'set'
7
5
  require 'openssl'
8
6
  require 'base64'
@@ -18,21 +16,11 @@ else
18
16
  end
19
17
  end
20
18
 
19
+ require 'sqreen/exception'
20
+ require 'sqreen/signature_verifier'
21
+
21
22
  ## Rules signature
22
23
  module Sqreen
23
- # Perform an EC + digest verification of a message.
24
- class SignatureVerifier
25
- def initialize(key, digest)
26
- @pub_key = OpenSSL::PKey.read(key)
27
- @digest = digest
28
- end
29
-
30
- def verify(sig, val)
31
- hashed_val = @digest.digest(val)
32
- @pub_key.dsa_verify_asn1(hashed_val, sig)
33
- end
34
- end
35
-
36
24
  # Normalize and verify a rule
37
25
  class SqreenSignedVerifier
38
26
  REQUIRED_SIGNED_KEYS = %w[hookpoint name callbacks conditions].freeze
@@ -40,14 +28,14 @@ module Sqreen
40
28
  SIGNATURE_VALUE_KEY = 'value'.freeze
41
29
  SIGNED_KEYS_KEY = 'keys'.freeze
42
30
  SIGNATURE_VERSION = 'v0_9'.freeze
43
- PUBLIC_KEY = <<-END.gsub(/^ */, '').freeze
31
+ PUBLIC_KEY = <<-KEY.gsub(/^ */, '').freeze
44
32
  -----BEGIN PUBLIC KEY-----
45
33
  MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQA39oWMHR8sxb9LRaM5evZ7mw03iwJ
46
34
  WNHuDeGqgPo1HmvuMfLnAyVLwaMXpGPuvbqhC1U65PG90bTJLpvNokQf0VMA5Tpi
47
35
  m+NXwl7bjqa03vO/HErLbq3zBRysrZnC4OhJOF1jazkAg0psQOea2r5HcMcPHgMK
48
36
  fnWXiKWnZX+uOWPuerE=
49
37
  -----END PUBLIC KEY-----
50
- END
38
+ KEY
51
39
 
52
40
  attr_accessor :pub_key
53
41
  attr_accessor :required_signed_keys
@@ -0,0 +1,8 @@
1
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
3
+
4
+ require 'sqreen/exception'
5
+
6
+ module Sqreen
7
+ class TokenInvalidException < Sqreen::Exception; end
8
+ end
@@ -0,0 +1,9 @@
1
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
3
+
4
+ require 'sqreen/exception'
5
+
6
+ module Sqreen
7
+ # When the token is not found
8
+ class TokenNotFoundException < Sqreen::Exception; end
9
+ end
@@ -2,6 +2,9 @@
2
2
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
3
3
 
4
4
  require 'ipaddr'
5
+ require 'sqreen/node'
6
+
7
+ # TODO: move to Sqreen::IP
5
8
 
6
9
  module Sqreen
7
10
  Trie = Struct.new(:head, :num_active_nodes, :family) do
@@ -211,68 +214,4 @@ module Sqreen
211
214
  xstack
212
215
  end
213
216
  end
214
-
215
- Prefix = Struct.new(:family, :bitlen, :address, :data) do # addr is integer
216
- def initialize(*args)
217
- super
218
- raise ArgumentError, 'no family given' unless family
219
- raise ArgumentError, 'no bitlen given' unless bitlen
220
- raise ArgumentError, 'no address given' unless address
221
- end
222
-
223
- def matches?(addr, family)
224
- raise 'family mismatch' unless family == self.family
225
- shift_amount = (family == Socket::AF_INET ? 32 : 128) - self.bitlen
226
- (addr ^ self.address) >> shift_amount == 0
227
- end
228
- end
229
-
230
- def Prefix.from_str(str, data = nil)
231
- ip_addr = IPAddr.new(str)
232
- if str =~ /\/(\d+)$/
233
- bitlen = $~[1].to_i
234
- else
235
- bitlen = ip_addr.family == Socket::AF_INET6 ? 128 : 32
236
- end
237
- Prefix.new(ip_addr.family, bitlen, ip_addr.to_i, data)
238
- end
239
-
240
- # bit starts at 0 (most significant)
241
- Node = Struct.new(:bit, :prefix, :l, :r, :parent) do
242
- def initialize(*args)
243
- super
244
- raise ArgumentError, 'no bit given' if bit.nil?
245
- end
246
-
247
- def empty?
248
- prefix.nil?
249
- end
250
-
251
- # cover the whole tree
252
- def walk(max_bits, empty_nodes = false)
253
- xstack = Array.new(max_bits + 1)
254
- sidx = 0 # stack index
255
- xhead = self
256
- xcur = xhead
257
- while !xcur.nil?
258
- yield xcur unless xcur.empty? && !empty_nodes
259
-
260
- if xcur.l
261
- if xcur.r
262
- xstack[sidx] = xcur.r
263
- sidx += 1
264
- end
265
- xcur = xcur.l
266
- elsif xcur.r
267
- xcur = xcur.r
268
- elsif sidx.nonzero?
269
- sidx -= 1
270
- xcur = xstack[sidx]
271
- else
272
- xcur = nil
273
- end
274
- end
275
- end
276
- end
277
-
278
217
  end
@@ -0,0 +1,8 @@
1
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
3
+
4
+ require 'sqreen/exception'
5
+
6
+ module Sqreen
7
+ class Unauthorized < Sqreen::Exception; end
8
+ end
@@ -0,0 +1,2 @@
1
+ module Sqreen; end
2
+ module Sqreen::Util; end
@@ -0,0 +1,33 @@
1
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
3
+
4
+ require 'sqreen/util'
5
+
6
+ class Sqreen::Util::CappedArray < Array
7
+ attr_reader :size_cap, :depth_cap
8
+
9
+ def initialize(*args, &block)
10
+ opts = args.last.is_a?(Hash) ? args.pop : {}
11
+ size_cap = opts[:size_cap] || 150
12
+ depth_cap = opts[:depth_cap] || 10
13
+ @size_cap = size_cap
14
+ @depth_cap = depth_cap
15
+
16
+ super(*args, &block)
17
+ end
18
+
19
+ def <<(value)
20
+ keep?(size, value) ? super : self
21
+ end
22
+ alias_method :append, :<<
23
+
24
+ def []=(index, value)
25
+ super if keep?(index, value)
26
+ end
27
+
28
+ private
29
+
30
+ def keep?(index, value)
31
+ index < size_cap && (depth_cap > 0 || !value.is_a?(Hash) && !value.is_a?(Array))
32
+ end
33
+ end