sqreen 1.13.4 → 1.14.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sqreen/js/execjs_adapter.rb +25 -0
- data/lib/sqreen/js/js_service.rb +133 -0
- data/lib/sqreen/js/mini_racer_adapter.rb +118 -0
- data/lib/sqreen/rules.rb +11 -0
- data/lib/sqreen/rules_callbacks/execjs.rb +144 -204
- data/lib/sqreen/rules_callbacks/execjs_old.rb +315 -0
- data/lib/sqreen/rules_callbacks/reflected_xss.rb +5 -1
- data/lib/sqreen/version.rb +1 -1
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: be5e0fc0157660b4143e23279952f83b846a5c85b922b6bcdb6740f88ec1a6b1
|
4
|
+
data.tar.gz: 3b07af02a64839b8028d783831c42f7a46af9faeaed32d535ad7092ca1e667ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a5cae395aa6f18212e296675641be3f8e55237b808346deed258496b8eb6597323146702cd2e34531c6154e8faee6d974610e3a054069ef815b915f97c32950
|
7
|
+
data.tar.gz: cf0e72d2bf2e976bed8e29dd3f3c9f1c718efdc55490745e550e5163ea16f33e7bccee3e9169944bd669d1d6a4ab679ecf705ca22febfbb0ebd07a21702ffc9b
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'execjs'
|
2
|
+
|
3
|
+
module Sqreen
|
4
|
+
module Js
|
5
|
+
class ExecjsAdapter < JsServiceAdapter
|
6
|
+
def preprocess(_rule_name, code)
|
7
|
+
ExecJsRunnable.new(ExecJS.compile(code))
|
8
|
+
end
|
9
|
+
|
10
|
+
def variant_name
|
11
|
+
ExecJS.runtime.name + ' (ExecJS)'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class ExecJsRunnable < ExecutableJs
|
16
|
+
def initialize(compiled)
|
17
|
+
@compiled = compiled
|
18
|
+
end
|
19
|
+
|
20
|
+
def run_js_cb(cbname, _budget, arguments)
|
21
|
+
@compiled.call(cbname, *arguments)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'sqreen/exception'
|
2
|
+
|
3
|
+
module Sqreen
|
4
|
+
module Js
|
5
|
+
# start public interface
|
6
|
+
|
7
|
+
class JsService
|
8
|
+
include Singleton
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
detect_adapter
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [Sqreen::Js::ExecutableJs]
|
15
|
+
def prepare(rule_name, code)
|
16
|
+
raise 'Not online' unless online?
|
17
|
+
@adapter.preprocess(rule_name, code)
|
18
|
+
end
|
19
|
+
|
20
|
+
def online?
|
21
|
+
@online
|
22
|
+
end
|
23
|
+
|
24
|
+
def variant
|
25
|
+
@adapter.variant_name
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def detect_adapter
|
31
|
+
if Sqreen.features['isolated_mini_racer'] || ENV['SQREEN_FORCE_SQ_MINI_RACER']
|
32
|
+
@online = try_sq_mini_racer
|
33
|
+
else
|
34
|
+
@online = try_mini_racer || try_rhino || try_therubyracer
|
35
|
+
end
|
36
|
+
|
37
|
+
Sqreen.log.info "JS engine online: #{variant}" if @online
|
38
|
+
end
|
39
|
+
|
40
|
+
def try_mini_racer
|
41
|
+
gem = Gem.loaded_specs['mini_racer']
|
42
|
+
unless gem
|
43
|
+
Sqreen.log.info "mini_racer gem not detected"
|
44
|
+
return false
|
45
|
+
end
|
46
|
+
unless gem.version >= Gem::Version.create('0.1.15') &&
|
47
|
+
gem.version < Gem::Version.create('2.0')
|
48
|
+
Sqreen.log.warn 'mini_racer won\'t be used because its version is' \
|
49
|
+
"#{gem.version}; not >= 0.1.15, < 2.0"
|
50
|
+
return false
|
51
|
+
end
|
52
|
+
|
53
|
+
require 'mini_racer'
|
54
|
+
require 'sqreen/js/mini_racer_adapter'
|
55
|
+
@adapter = MiniRacerAdapter.new
|
56
|
+
rescue LoadError => e
|
57
|
+
Sqreen.log.warn "Failed loading mini_racer: #{e}"
|
58
|
+
false
|
59
|
+
end
|
60
|
+
|
61
|
+
def try_sq_mini_racer
|
62
|
+
gem = Gem.loaded_specs['sq_mini_racer']
|
63
|
+
unless gem
|
64
|
+
Sqreen.log.info "sq_mini_racer gem not detected"
|
65
|
+
return false
|
66
|
+
end
|
67
|
+
|
68
|
+
require 'sqreen/mini_racer'
|
69
|
+
require 'sqreen/js/mini_racer_adapter'
|
70
|
+
@adapter = MiniRacerAdapter.new(true)
|
71
|
+
rescue LoadError => e
|
72
|
+
Sqreen.log.warn "Failed loading sq_mini_racer: #{e}"
|
73
|
+
false
|
74
|
+
end
|
75
|
+
|
76
|
+
def try_rhino
|
77
|
+
gem = Gem.loaded_specs['therubyrhino']
|
78
|
+
unless gem
|
79
|
+
Sqreen.log.info "therubyrhino gem not detected"
|
80
|
+
return false
|
81
|
+
end
|
82
|
+
|
83
|
+
require 'rhino'
|
84
|
+
require 'sqreen/js/execjs_adapter'
|
85
|
+
@adapter = ExecjsAdapter.new
|
86
|
+
rescue LoadError => e
|
87
|
+
Sqreen.log.warn "Failed loading rhino: #{e}"
|
88
|
+
false
|
89
|
+
end
|
90
|
+
|
91
|
+
def try_therubyracer
|
92
|
+
gem = Gem.loaded_specs['therubyracer']
|
93
|
+
unless gem
|
94
|
+
Sqreen.log.info "therubyracer gem not detected"
|
95
|
+
return false
|
96
|
+
end
|
97
|
+
unless gem.version >= Gem::Version.create('0.12.1')
|
98
|
+
Sqreen.log.warn 'therubyracer won\'t be used because its version is ' \
|
99
|
+
"#{gem.version}; not >= 0.12.1"
|
100
|
+
return false
|
101
|
+
end
|
102
|
+
|
103
|
+
require 'therubyracer'
|
104
|
+
require 'sqreen/js/execjs_adapter'
|
105
|
+
@adapter = ExecjsAdapter.new
|
106
|
+
rescue LoadError => e
|
107
|
+
Sqreen.log.warn "Failed loading therubyracer: #{e}"
|
108
|
+
false
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
CallContext = Struct.new(:inst, :args, :rv)
|
114
|
+
|
115
|
+
class ExecutableJs
|
116
|
+
def run_js_cb(_cb_name, _budget, _arguments)
|
117
|
+
raise Sqreen::NotImplementedYet
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# end public interface
|
122
|
+
|
123
|
+
class JsServiceAdapter
|
124
|
+
def preprocess(code)
|
125
|
+
raise Sqreen::NotImplementedYet
|
126
|
+
end
|
127
|
+
|
128
|
+
def variant_name
|
129
|
+
'unspecified'
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'weakref'
|
2
|
+
|
3
|
+
module Sqreen
|
4
|
+
module Js
|
5
|
+
GC_MINI_RACER = 10_000
|
6
|
+
|
7
|
+
class MiniRacerAdapter < JsServiceAdapter
|
8
|
+
def initialize(vendored = false)
|
9
|
+
@vendored = vendored
|
10
|
+
end
|
11
|
+
|
12
|
+
def preprocess(_rule_name, code)
|
13
|
+
MiniRacerExecutableJs.new(code, @vendored)
|
14
|
+
end
|
15
|
+
|
16
|
+
def variant_name
|
17
|
+
@vendored ? 'sq_mini_racer' : 'mini_racer'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Auxiliary classes
|
22
|
+
|
23
|
+
class MiniRacerExecutableJs < ExecutableJs
|
24
|
+
@@ctx_defined = false
|
25
|
+
|
26
|
+
def initialize(source, vendored)
|
27
|
+
@module = vendored ? Sqreen::MiniRacer : MiniRacer
|
28
|
+
@source = source
|
29
|
+
@recycle_runtime_every = GC_MINI_RACER
|
30
|
+
@snapshot = @module::Snapshot.new(source)
|
31
|
+
@runtimes = []
|
32
|
+
@tl_key = "SQREEN_MINI_RACER_CONTEXT_#{object_id}".freeze
|
33
|
+
unless @@ctx_defined
|
34
|
+
self.class.define_sqreen_context(@module)
|
35
|
+
@@ctx_defined = true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def run_js_cb(cb_name, budget, arguments)
|
40
|
+
mini_racer_context = Thread.current[@tl_key]
|
41
|
+
dead_runtime = !mini_racer_context ||
|
42
|
+
!mini_racer_context[:r] || !mini_racer_context[:r].weakref_alive?
|
43
|
+
if !dead_runtime && mini_racer_context[:c] >= @recycle_runtime_every
|
44
|
+
dispose_runtime(mini_racer_context[:r])
|
45
|
+
dead_runtime = true
|
46
|
+
end
|
47
|
+
if dead_runtime
|
48
|
+
new_runtime = SqreenContext.new(:snapshot => @snapshot)
|
49
|
+
push_runtime new_runtime
|
50
|
+
mini_racer_context = {
|
51
|
+
:c => 0,
|
52
|
+
:r => WeakCtx.new(new_runtime),
|
53
|
+
}
|
54
|
+
Thread.current[@tl_key] = mini_racer_context
|
55
|
+
end
|
56
|
+
|
57
|
+
mini_racer_context[:c] += 1
|
58
|
+
begin
|
59
|
+
mini_racer_context[:r].eval_unsafe(
|
60
|
+
"#{cb_name}.apply(this, #{::JSON.generate(arguments)})", nil, budget)
|
61
|
+
rescue @module::ScriptTerminatedError
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def push_runtime(runtime)
|
69
|
+
@runtimes.delete_if do |th, runt, _thid|
|
70
|
+
del = th.nil? || !th.weakref_alive? || !th.alive?
|
71
|
+
runt.dispose if del
|
72
|
+
del
|
73
|
+
end
|
74
|
+
@runtimes.push [WeakRef.new(Thread.current), runtime, Thread.current.object_id]
|
75
|
+
end
|
76
|
+
|
77
|
+
def dispose_runtime(runtime)
|
78
|
+
@runtimes.delete_if { |_th, _runt, thid| thid == Thread.current.object_id }
|
79
|
+
runtime.dispose
|
80
|
+
end
|
81
|
+
|
82
|
+
class << self
|
83
|
+
def define_sqreen_context(modoole)
|
84
|
+
# Context specialized for Sqreen usage
|
85
|
+
Sqreen::Js.const_set 'SqreenContext', Class.new(modoole.const_get('Context'))
|
86
|
+
SqreenContext.class_eval do
|
87
|
+
def eval_unsafe(str, filename = nil, timeoutv = nil)
|
88
|
+
# Beware, timeout could be kept in the context
|
89
|
+
# if perf cap is removed after having been activated
|
90
|
+
# As it's unused by execjscb we are not cleaning it
|
91
|
+
return super(str, filename) if timeoutv.nil?
|
92
|
+
return if timeoutv <= 0.0
|
93
|
+
timeoutv *= 1000 # Timeout are currently expressed in seconds
|
94
|
+
@timeout = timeoutv
|
95
|
+
@eval_thread = Thread.current
|
96
|
+
timeout do
|
97
|
+
super(str, filename)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
# Weak ref to a context
|
107
|
+
# enables us to skip a method missing call
|
108
|
+
class WeakCtx < WeakRef
|
109
|
+
def initialize(*args)
|
110
|
+
super(*args)
|
111
|
+
end
|
112
|
+
|
113
|
+
def eval_unsafe(str, filename, timeoutv)
|
114
|
+
__getobj__.eval_unsafe(str, filename, timeoutv)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/sqreen/rules.rb
CHANGED
@@ -75,6 +75,17 @@ module Sqreen
|
|
75
75
|
|
76
76
|
cb_class = nil
|
77
77
|
js = hash_rule[Attrs::CALLBACKS]
|
78
|
+
|
79
|
+
if js && !Sqreen::Js::JsService.instance.online?
|
80
|
+
unless @@issue_nojs_warn
|
81
|
+
@@issue_nojs_warn = true
|
82
|
+
Sqreen.log.warn('No JavaScript engine is available. ' \
|
83
|
+
'JavaScript callbacks will be ignored')
|
84
|
+
end
|
85
|
+
Sqreen.log.info("Ignoring JS callback #{rule_name}")
|
86
|
+
return nil
|
87
|
+
end
|
88
|
+
|
78
89
|
cb_class = ExecJSCB if js
|
79
90
|
|
80
91
|
if cbname && Rules.const_defined?(cbname)
|
@@ -1,22 +1,8 @@
|
|
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
|
-
if defined?(::JRUBY_VERSION)
|
5
|
-
require 'rhino'
|
6
|
-
SQREEN_MINI_RACER = false
|
7
|
-
else
|
8
|
-
begin
|
9
|
-
require 'mini_racer'
|
10
|
-
SQREEN_MINI_RACER = true
|
11
|
-
GC_MINI_RACER = 10_000
|
12
|
-
rescue LoadError
|
13
|
-
require 'therubyracer'
|
14
|
-
SQREEN_MINI_RACER = false
|
15
|
-
end
|
16
|
-
end
|
17
4
|
|
18
|
-
require '
|
19
|
-
require 'execjs'
|
5
|
+
require 'sqreen/js/js_service'
|
20
6
|
|
21
7
|
require 'sqreen/rule_attributes'
|
22
8
|
require 'sqreen/rule_callback'
|
@@ -25,64 +11,30 @@ require 'sqreen/binding_accessor'
|
|
25
11
|
require 'sqreen/events/remote_exception'
|
26
12
|
|
27
13
|
module Sqreen
|
28
|
-
if SQREEN_MINI_RACER
|
29
|
-
# Context specialized for Sqreen usage
|
30
|
-
class SqreenContext < MiniRacer::Context
|
31
|
-
def eval_unsafe(str, filename = nil, timeoutv = nil)
|
32
|
-
# Beware, timeout could be kept in the context
|
33
|
-
# if perf cap is removed after having been activated
|
34
|
-
# As it's unused by execjscb we are not cleaning it
|
35
|
-
return super(str, filename) if timeoutv.nil?
|
36
|
-
return if timeoutv <= 0.0
|
37
|
-
timeoutv *= 1000 # Timeout are currently expressed in seconds
|
38
|
-
@timeout = timeoutv
|
39
|
-
@eval_thread = Thread.current
|
40
|
-
timeout do
|
41
|
-
super(str, filename)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
# Weak ref to a context
|
47
|
-
# enables us to skip a method missing call
|
48
|
-
class WeakCtx < WeakRef
|
49
|
-
def initialize(*args)
|
50
|
-
super(*args)
|
51
|
-
end
|
52
|
-
|
53
|
-
def eval_unsafe(str, filename, timeoutv)
|
54
|
-
__getobj__.eval_unsafe(str, filename, timeoutv)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
14
|
module Rules
|
59
15
|
# Exec js callbacks
|
60
16
|
class ExecJSCB < RuleCB
|
61
|
-
|
62
|
-
|
63
|
-
|
17
|
+
|
18
|
+
class << self
|
19
|
+
# @return [Sqreen::Js::JsService]
|
20
|
+
def js_service
|
21
|
+
Sqreen::Js::JsService.instance
|
22
|
+
end
|
23
|
+
end
|
64
24
|
|
65
25
|
def initialize(klass, method, rule_hash)
|
66
26
|
super(klass, method, rule_hash)
|
67
27
|
callbacks = @rule[Attrs::CALLBACKS]
|
68
28
|
@conditions = @rule.fetch(Attrs::CONDITIONS, {})
|
69
29
|
|
70
|
-
if callbacks['pre'].nil? &&
|
71
|
-
callbacks['post'].nil? &&
|
72
|
-
callbacks['failing'].nil?
|
73
|
-
raise(Sqreen::Exception, 'no JS CB provided')
|
74
|
-
end
|
75
|
-
|
76
30
|
build_runnable(callbacks)
|
77
|
-
|
78
|
-
unless
|
79
|
-
|
80
|
-
return
|
31
|
+
|
32
|
+
unless pre? || post? || failing?
|
33
|
+
raise Sqreen::Exception, 'no JS CB provided'
|
81
34
|
end
|
82
|
-
|
83
|
-
@
|
84
|
-
@
|
85
|
-
@key = "SQREEN_MINI_RACER_CONTEXT_#{object_id}".freeze
|
35
|
+
|
36
|
+
@executable = ExecJSCB.js_service.prepare(rule_name, @source)
|
37
|
+
@argument_filter = ArgumentFilter.new(rule_hash)
|
86
38
|
end
|
87
39
|
|
88
40
|
def pre?
|
@@ -100,63 +52,22 @@ module Sqreen
|
|
100
52
|
def pre(inst, args, budget = nil, &_block)
|
101
53
|
return unless pre?
|
102
54
|
|
103
|
-
call_callback('pre', inst,
|
55
|
+
call_callback('pre', budget, inst, @cb_bas['pre'], args)
|
104
56
|
end
|
105
57
|
|
106
58
|
def post(rv, inst, args, budget = nil, &_block)
|
107
59
|
return unless post?
|
108
60
|
|
109
|
-
call_callback('post', inst,
|
61
|
+
call_callback('post', budget, inst, @cb_bas['post'], args, rv)
|
110
62
|
end
|
111
63
|
|
112
64
|
def failing(rv, inst, args, budget = nil, &_block)
|
113
65
|
return unless failing?
|
114
66
|
|
115
|
-
call_callback('failing', inst,
|
116
|
-
end
|
117
|
-
|
118
|
-
def self.hash_val_included(needed, haystack, min_length = 8, max_depth = 20)
|
119
|
-
new_obj = {}
|
120
|
-
insert = []
|
121
|
-
to_do = haystack.map { |k, v| [new_obj, k, v, 0] }
|
122
|
-
until to_do.empty?
|
123
|
-
where, key, value, deepness = to_do.pop
|
124
|
-
safe_key = key.is_a?(Integer) ? key : key.to_s
|
125
|
-
if value.is_a?(Hash) && deepness < max_depth
|
126
|
-
val = {}
|
127
|
-
insert << [where, safe_key, val]
|
128
|
-
to_do += value.map { |k, v| [val, k, v, deepness + 1] }
|
129
|
-
elsif value.is_a?(Array) && deepness < max_depth
|
130
|
-
val = []
|
131
|
-
insert << [where, safe_key, val]
|
132
|
-
i = -1
|
133
|
-
to_do += value.map { |v| [val, i += 1, v, deepness + 1] }
|
134
|
-
elsif deepness >= max_depth # if we are after max_depth don't try to filter
|
135
|
-
insert << [where, safe_key, value]
|
136
|
-
else
|
137
|
-
v = value.to_s
|
138
|
-
if v.size >= min_length && ConditionEvaluator.str_include?(needed.to_s, v)
|
139
|
-
case where
|
140
|
-
when Array
|
141
|
-
where << value
|
142
|
-
else
|
143
|
-
where[safe_key] = value
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
insert.reverse.each do |wh, ikey, ival|
|
149
|
-
case wh
|
150
|
-
when Array
|
151
|
-
wh << ival unless ival.respond_to?(:empty?) && ival.empty?
|
152
|
-
else
|
153
|
-
wh[ikey] = ival unless ival.respond_to?(:empty?) && ival.empty?
|
154
|
-
end
|
155
|
-
end
|
156
|
-
new_obj
|
67
|
+
call_callback('failing', budget, inst, @cb_bas['failing'], args, rv)
|
157
68
|
end
|
158
69
|
|
159
|
-
|
70
|
+
private
|
160
71
|
|
161
72
|
def record_and_continue?(ret)
|
162
73
|
case ret
|
@@ -165,10 +76,10 @@ module Sqreen
|
|
165
76
|
when Hash
|
166
77
|
ret.keys.each do |k|
|
167
78
|
ret[(begin
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
79
|
+
k.to_sym
|
80
|
+
rescue StandardError
|
81
|
+
k
|
82
|
+
end)] = ret[k] end
|
172
83
|
record_event(ret[:record]) unless ret[:record].nil?
|
173
84
|
unless ret['observations'].nil?
|
174
85
|
ret['observations'].each do |obs|
|
@@ -182,134 +93,163 @@ module Sqreen
|
|
182
93
|
end
|
183
94
|
end
|
184
95
|
|
185
|
-
def
|
186
|
-
|
187
|
-
|
188
|
-
runt.dispose if del
|
189
|
-
del
|
96
|
+
def call_callback(cb_name, budget, inst, cb_ba_args, args, rv = nil)
|
97
|
+
arguments = cb_ba_args.map do |ba|
|
98
|
+
ba.resolve(binding, framework, inst, args, @data, rv)
|
190
99
|
end
|
191
|
-
@
|
192
|
-
end
|
100
|
+
arguments = @argument_filter.filter(cb_name, arguments)
|
193
101
|
|
194
|
-
|
195
|
-
@runtimes.delete_if { |_th, _runt, thid| thid == Thread.current.object_id }
|
196
|
-
runtime.dispose
|
197
|
-
end
|
102
|
+
ret = @executable.run_js_cb(cb_name, budget, arguments)
|
198
103
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
mini_racer_context = Thread.current[@key]
|
203
|
-
dead_runtime = !mini_racer_context || !mini_racer_context[:r] || !mini_racer_context[:r].weakref_alive?
|
204
|
-
if !dead_runtime && mini_racer_context[:c] >= @recycle_runtime_every
|
205
|
-
dispose_runtime(mini_racer_context[:r])
|
206
|
-
dead_runtime = true
|
207
|
-
end
|
208
|
-
if dead_runtime
|
209
|
-
new_runtime = SqreenContext.new(:snapshot => @snapshot)
|
210
|
-
push_runtime new_runtime
|
211
|
-
mini_racer_context = {
|
212
|
-
:c => 0,
|
213
|
-
:r => WeakCtx.new(new_runtime),
|
214
|
-
}
|
215
|
-
Thread.current[@key] = mini_racer_context
|
216
|
-
end
|
217
|
-
end
|
218
|
-
ret = nil
|
219
|
-
args_override = nil
|
220
|
-
arguments = nil
|
221
|
-
while true
|
222
|
-
arguments = (args_override || @argument_requirements[name]).map do |accessor|
|
223
|
-
accessor.resolve(binding, framework, inst, args, @data, rv)
|
224
|
-
end
|
225
|
-
arguments = restrict(name, arguments) if @conditions.key?(name)
|
226
|
-
Sqreen.log.debug { [name, arguments].inspect }
|
227
|
-
if SQREEN_MINI_RACER
|
228
|
-
mini_racer_context[:c] += 1
|
229
|
-
begin
|
230
|
-
ret = mini_racer_context[:r].eval_unsafe("#{name}.apply(this, #{::JSON.generate(arguments)})", nil, budget)
|
231
|
-
rescue MiniRacer::ScriptTerminatedError
|
232
|
-
ret = nil
|
233
|
-
end
|
234
|
-
else
|
235
|
-
ret = @compiled.call(name, *arguments)
|
236
|
-
end
|
237
|
-
unless record_and_continue?(ret)
|
238
|
-
return nil if ret.nil?
|
239
|
-
return advise_action(ret[:status], ret)
|
240
|
-
end
|
241
|
-
name = ret[:call]
|
242
|
-
rv = ret[:data]
|
243
|
-
args_override = ret[:args]
|
244
|
-
args_override = build_accessor(args_override) if args_override
|
104
|
+
unless record_and_continue?(ret)
|
105
|
+
return nil if ret.nil?
|
106
|
+
return advise_action(ret[:status], ret)
|
245
107
|
end
|
108
|
+
|
109
|
+
name = ret[:call]
|
110
|
+
rv = ret[:data]
|
111
|
+
new_ba_args = if ret[:args]
|
112
|
+
self.class.build_accessors(ret[:args])
|
113
|
+
else
|
114
|
+
@cb_bas[name] || []
|
115
|
+
end
|
116
|
+
|
117
|
+
# XXX: budgets was not subtracted from
|
118
|
+
call_callback(name, budget, inst, new_ba_args, args, rv)
|
119
|
+
|
246
120
|
rescue StandardError => e
|
247
|
-
Sqreen.log.warn { "
|
121
|
+
Sqreen.log.warn { "Caught JS callback exception: #{e.inspect}" }
|
248
122
|
Sqreen.log.debug e.backtrace
|
249
|
-
record_exception(e, :cb =>
|
123
|
+
record_exception(e, :cb => cb_name, :args => arguments)
|
250
124
|
nil
|
251
125
|
end
|
252
126
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
127
|
+
|
128
|
+
def self.build_accessors(reqs)
|
129
|
+
reqs.map do |req|
|
130
|
+
BindingAccessor.new(req, true)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def build_runnable(callbacks)
|
135
|
+
@cb_bas = {}
|
136
|
+
@source = ''
|
137
|
+
@js_pre = !callbacks['pre'].nil?
|
138
|
+
@js_post = !callbacks['post'].nil?
|
139
|
+
@js_failing = !callbacks['failing'].nil?
|
140
|
+
callbacks.each do |name, args_or_func|
|
141
|
+
@source << "this['#{name.tr("'", "\\'")}'] = "
|
142
|
+
if args_or_func.is_a?(Array)
|
143
|
+
args_or_func = args_or_func.dup
|
144
|
+
@source << args_or_func.pop
|
145
|
+
@cb_bas[name] = self.class.build_accessors(args_or_func)
|
258
146
|
else
|
259
|
-
|
260
|
-
|
261
|
-
end
|
147
|
+
@source << args_or_func
|
148
|
+
@cb_bas[name] = []
|
262
149
|
end
|
150
|
+
@source << ";\n"
|
263
151
|
end
|
264
152
|
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class ArgumentFilter
|
156
|
+
MAX_DEPTH = 2
|
157
|
+
|
158
|
+
def initialize(rule)
|
159
|
+
@conditions = rule.fetch(Attrs::CONDITIONS, {})
|
160
|
+
build_arg_requirements rule
|
161
|
+
end
|
265
162
|
|
266
|
-
def
|
163
|
+
def filter(cbname, arguments)
|
267
164
|
condition = @conditions[cbname]
|
268
|
-
return arguments if condition.nil? || @
|
165
|
+
return arguments if condition.nil? || @ba_expressions[cbname].nil?
|
269
166
|
|
270
167
|
each_hash_val_include(condition) do |needle, haystack, min_length|
|
271
168
|
# We could actually run the binding accessor expression here.
|
272
|
-
needed_idx = @
|
169
|
+
needed_idx = @ba_expressions[cbname].index(needle)
|
273
170
|
next unless needed_idx
|
274
171
|
|
275
|
-
haystack_idx = @
|
172
|
+
haystack_idx = @ba_expressions[cbname].index(haystack)
|
276
173
|
next unless haystack_idx
|
277
174
|
|
278
|
-
arguments[haystack_idx] =
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
175
|
+
arguments[haystack_idx] = ArgumentFilter.hash_val_included(
|
176
|
+
arguments[needed_idx],
|
177
|
+
arguments[haystack_idx],
|
178
|
+
min_length.to_i,
|
179
|
+
MAX_DEPTH
|
283
180
|
)
|
284
181
|
end
|
285
182
|
|
286
183
|
arguments
|
287
184
|
end
|
288
185
|
|
289
|
-
def
|
290
|
-
|
291
|
-
|
186
|
+
def build_arg_requirements(rule)
|
187
|
+
@ba_expressions = {}
|
188
|
+
callbacks = rule[Attrs::CALLBACKS]
|
189
|
+
callbacks.each do |name, args_or_func|
|
190
|
+
next unless args_or_func.is_a?(Array)
|
191
|
+
args_bas = args_or_func[0..-2] unless args_or_func.empty?
|
192
|
+
@ba_expressions[name] =
|
193
|
+
ExecJSCB.build_accessors(args_bas).map(&:expression)
|
292
194
|
end
|
293
195
|
end
|
294
196
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
@source << "var #{name} = "
|
303
|
-
if args_or_func.is_a?(Array)
|
304
|
-
@source << args_or_func.pop
|
305
|
-
@argument_requirements[name] = build_accessor(args_or_func)
|
197
|
+
private
|
198
|
+
|
199
|
+
def each_hash_val_include(condition, depth = 10)
|
200
|
+
return if depth <= 0
|
201
|
+
condition.each do |key, values|
|
202
|
+
if key == ConditionEvaluator::HASH_INC_OPERATOR
|
203
|
+
yield values
|
306
204
|
else
|
307
|
-
|
308
|
-
|
205
|
+
values.map do |v|
|
206
|
+
each_hash_val_include(v, depth - 1) { |vals| yield vals } if v.is_a?(Hash)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def self.hash_val_included(needed, haystack, min_length = 8, max_depth = 20)
|
213
|
+
new_obj = {}
|
214
|
+
insert = []
|
215
|
+
to_do = haystack.map { |k, v| [new_obj, k, v, 0] }
|
216
|
+
until to_do.empty?
|
217
|
+
where, key, value, deepness = to_do.pop
|
218
|
+
safe_key = key.is_a?(Integer) ? key : key.to_s
|
219
|
+
if value.is_a?(Hash) && deepness < max_depth
|
220
|
+
val = {}
|
221
|
+
insert << [where, safe_key, val]
|
222
|
+
to_do += value.map { |k, v| [val, k, v, deepness + 1] }
|
223
|
+
elsif value.is_a?(Array) && deepness < max_depth
|
224
|
+
val = []
|
225
|
+
insert << [where, safe_key, val]
|
226
|
+
i = -1
|
227
|
+
to_do += value.map { |v| [val, i += 1, v, deepness + 1] }
|
228
|
+
elsif deepness >= max_depth # if we are after max_depth don't try to filter
|
229
|
+
insert << [where, safe_key, value]
|
230
|
+
else
|
231
|
+
v = value.to_s
|
232
|
+
if v.size >= min_length && ConditionEvaluator.str_include?(needed.to_s, v)
|
233
|
+
case where
|
234
|
+
when Array
|
235
|
+
where << value
|
236
|
+
else
|
237
|
+
where[safe_key] = value
|
238
|
+
end
|
239
|
+
end
|
309
240
|
end
|
310
|
-
@source << ";\n"
|
311
241
|
end
|
242
|
+
insert.reverse.each do |wh, ikey, ival|
|
243
|
+
case wh
|
244
|
+
when Array
|
245
|
+
wh << ival unless ival.respond_to?(:empty?) && ival.empty?
|
246
|
+
else
|
247
|
+
wh[ikey] = ival unless ival.respond_to?(:empty?) && ival.empty?
|
248
|
+
end
|
249
|
+
end
|
250
|
+
new_obj
|
312
251
|
end
|
313
252
|
end
|
314
253
|
end
|
315
254
|
end
|
255
|
+
|
@@ -0,0 +1,315 @@
|
|
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
|
+
if defined?(::JRUBY_VERSION)
|
5
|
+
require 'rhino'
|
6
|
+
SQREEN_MINI_RACER = false
|
7
|
+
else
|
8
|
+
begin
|
9
|
+
require 'mini_racer'
|
10
|
+
SQREEN_MINI_RACER = true
|
11
|
+
GC_MINI_RACER = 10_000
|
12
|
+
rescue LoadError
|
13
|
+
require 'therubyracer'
|
14
|
+
SQREEN_MINI_RACER = false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'weakref'
|
19
|
+
require 'execjs'
|
20
|
+
|
21
|
+
require 'sqreen/rule_attributes'
|
22
|
+
require 'sqreen/rule_callback'
|
23
|
+
require 'sqreen/condition_evaluator'
|
24
|
+
require 'sqreen/binding_accessor'
|
25
|
+
require 'sqreen/events/remote_exception'
|
26
|
+
|
27
|
+
module Sqreen
|
28
|
+
if SQREEN_MINI_RACER
|
29
|
+
# Context specialized for Sqreen usage
|
30
|
+
class SqreenContext < MiniRacer::Context
|
31
|
+
def eval_unsafe(str, filename = nil, timeoutv = nil)
|
32
|
+
# Beware, timeout could be kept in the context
|
33
|
+
# if perf cap is removed after having been activated
|
34
|
+
# As it's unused by execjscb we are not cleaning it
|
35
|
+
return super(str, filename) if timeoutv.nil?
|
36
|
+
return if timeoutv <= 0.0
|
37
|
+
timeoutv *= 1000 # Timeout are currently expressed in seconds
|
38
|
+
@timeout = timeoutv
|
39
|
+
@eval_thread = Thread.current
|
40
|
+
timeout do
|
41
|
+
super(str, filename)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Weak ref to a context
|
47
|
+
# enables us to skip a method missing call
|
48
|
+
class WeakCtx < WeakRef
|
49
|
+
def initialize(*args)
|
50
|
+
super(*args)
|
51
|
+
end
|
52
|
+
|
53
|
+
def eval_unsafe(str, filename, timeoutv)
|
54
|
+
__getobj__.eval_unsafe(str, filename, timeoutv)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
module Rules
|
59
|
+
# Exec js callbacks
|
60
|
+
class ExecJSCBOld < RuleCB
|
61
|
+
attr_accessor :restrict_max_depth
|
62
|
+
attr_reader :runtimes
|
63
|
+
attr_accessor :recycle_runtime_every
|
64
|
+
|
65
|
+
def initialize(klass, method, rule_hash)
|
66
|
+
super(klass, method, rule_hash)
|
67
|
+
callbacks = @rule[Attrs::CALLBACKS]
|
68
|
+
@conditions = @rule.fetch(Attrs::CONDITIONS, {})
|
69
|
+
|
70
|
+
if callbacks['pre'].nil? &&
|
71
|
+
callbacks['post'].nil? &&
|
72
|
+
callbacks['failing'].nil?
|
73
|
+
raise(Sqreen::Exception, 'no JS CB provided')
|
74
|
+
end
|
75
|
+
|
76
|
+
build_runnable(callbacks)
|
77
|
+
@restrict_max_depth = 20
|
78
|
+
unless SQREEN_MINI_RACER
|
79
|
+
@compiled = ExecJS.compile(@source)
|
80
|
+
return
|
81
|
+
end
|
82
|
+
@recycle_runtime_every = GC_MINI_RACER
|
83
|
+
@snapshot = MiniRacer::Snapshot.new(@source)
|
84
|
+
@runtimes = []
|
85
|
+
@key = "SQREEN_MINI_RACER_CONTEXT_#{object_id}".freeze
|
86
|
+
end
|
87
|
+
|
88
|
+
def pre?
|
89
|
+
@js_pre
|
90
|
+
end
|
91
|
+
|
92
|
+
def post?
|
93
|
+
@js_post
|
94
|
+
end
|
95
|
+
|
96
|
+
def failing?
|
97
|
+
@js_failing
|
98
|
+
end
|
99
|
+
|
100
|
+
def pre(inst, args, budget = nil, &_block)
|
101
|
+
return unless pre?
|
102
|
+
|
103
|
+
call_callback('pre', inst, budget, args)
|
104
|
+
end
|
105
|
+
|
106
|
+
def post(rv, inst, args, budget = nil, &_block)
|
107
|
+
return unless post?
|
108
|
+
|
109
|
+
call_callback('post', inst, budget, args, rv)
|
110
|
+
end
|
111
|
+
|
112
|
+
def failing(rv, inst, args, budget = nil, &_block)
|
113
|
+
return unless failing?
|
114
|
+
|
115
|
+
call_callback('failing', inst, budget, args, rv)
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.hash_val_included(needed, haystack, min_length = 8, max_depth = 20)
|
119
|
+
new_obj = {}
|
120
|
+
insert = []
|
121
|
+
to_do = haystack.map { |k, v| [new_obj, k, v, 0] }
|
122
|
+
until to_do.empty?
|
123
|
+
where, key, value, deepness = to_do.pop
|
124
|
+
safe_key = key.is_a?(Integer) ? key : key.to_s
|
125
|
+
if value.is_a?(Hash) && deepness < max_depth
|
126
|
+
val = {}
|
127
|
+
insert << [where, safe_key, val]
|
128
|
+
to_do += value.map { |k, v| [val, k, v, deepness + 1] }
|
129
|
+
elsif value.is_a?(Array) && deepness < max_depth
|
130
|
+
val = []
|
131
|
+
insert << [where, safe_key, val]
|
132
|
+
i = -1
|
133
|
+
to_do += value.map { |v| [val, i += 1, v, deepness + 1] }
|
134
|
+
elsif deepness >= max_depth # if we are after max_depth don't try to filter
|
135
|
+
insert << [where, safe_key, value]
|
136
|
+
else
|
137
|
+
v = value.to_s
|
138
|
+
if v.size >= min_length && ConditionEvaluator.str_include?(needed.to_s, v)
|
139
|
+
case where
|
140
|
+
when Array
|
141
|
+
where << value
|
142
|
+
else
|
143
|
+
where[safe_key] = value
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
insert.reverse.each do |wh, ikey, ival|
|
149
|
+
case wh
|
150
|
+
when Array
|
151
|
+
wh << ival unless ival.respond_to?(:empty?) && ival.empty?
|
152
|
+
else
|
153
|
+
wh[ikey] = ival unless ival.respond_to?(:empty?) && ival.empty?
|
154
|
+
end
|
155
|
+
end
|
156
|
+
new_obj
|
157
|
+
end
|
158
|
+
|
159
|
+
protected
|
160
|
+
|
161
|
+
def record_and_continue?(ret)
|
162
|
+
case ret
|
163
|
+
when NilClass
|
164
|
+
false
|
165
|
+
when Hash
|
166
|
+
ret.keys.each do |k|
|
167
|
+
ret[(begin
|
168
|
+
k.to_sym
|
169
|
+
rescue StandardError
|
170
|
+
k
|
171
|
+
end)] = ret[k] end
|
172
|
+
record_event(ret[:record]) unless ret[:record].nil?
|
173
|
+
unless ret['observations'].nil?
|
174
|
+
ret['observations'].each do |obs|
|
175
|
+
obs[3] = Time.parse(obs[3]) if obs.size >= 3 && obs[3].is_a?(String)
|
176
|
+
record_observation(*obs)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
!ret[:call].nil?
|
180
|
+
else
|
181
|
+
raise Sqreen::Exception, "Invalid return type #{ret.inspect}"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def push_runtime(runtime)
|
186
|
+
@runtimes.delete_if do |th, runt, _thid|
|
187
|
+
del = th.nil? || !th.weakref_alive? || !th.alive?
|
188
|
+
runt.dispose if del
|
189
|
+
del
|
190
|
+
end
|
191
|
+
@runtimes.push [WeakRef.new(Thread.current), runtime, Thread.current.object_id]
|
192
|
+
end
|
193
|
+
|
194
|
+
def dispose_runtime(runtime)
|
195
|
+
@runtimes.delete_if { |_th, _runt, thid| thid == Thread.current.object_id }
|
196
|
+
runtime.dispose
|
197
|
+
end
|
198
|
+
|
199
|
+
def call_callback(name, inst, budget, args, rv = nil)
|
200
|
+
mini_racer_context = nil
|
201
|
+
if SQREEN_MINI_RACER
|
202
|
+
mini_racer_context = Thread.current[@key]
|
203
|
+
dead_runtime = !mini_racer_context || !mini_racer_context[:r] || !mini_racer_context[:r].weakref_alive?
|
204
|
+
if !dead_runtime && mini_racer_context[:c] >= @recycle_runtime_every
|
205
|
+
dispose_runtime(mini_racer_context[:r])
|
206
|
+
dead_runtime = true
|
207
|
+
end
|
208
|
+
if dead_runtime
|
209
|
+
new_runtime = SqreenContext.new(:snapshot => @snapshot)
|
210
|
+
push_runtime new_runtime
|
211
|
+
mini_racer_context = {
|
212
|
+
:c => 0,
|
213
|
+
:r => WeakCtx.new(new_runtime),
|
214
|
+
}
|
215
|
+
Thread.current[@key] = mini_racer_context
|
216
|
+
end
|
217
|
+
end
|
218
|
+
ret = nil
|
219
|
+
args_override = nil
|
220
|
+
arguments = nil
|
221
|
+
while true
|
222
|
+
arguments = (args_override || @argument_requirements[name]).map do |accessor|
|
223
|
+
accessor.resolve(binding, framework, inst, args, @data, rv)
|
224
|
+
end
|
225
|
+
arguments = restrict(name, arguments) if @conditions.key?(name)
|
226
|
+
Sqreen.log.debug { [name, arguments].inspect }
|
227
|
+
if SQREEN_MINI_RACER
|
228
|
+
mini_racer_context[:c] += 1
|
229
|
+
begin
|
230
|
+
ret = mini_racer_context[:r].eval_unsafe("#{name}.apply(this, #{::JSON.generate(arguments)})", nil, budget)
|
231
|
+
rescue MiniRacer::ScriptTerminatedError
|
232
|
+
ret = nil
|
233
|
+
end
|
234
|
+
else
|
235
|
+
ret = @compiled.call(name, *arguments)
|
236
|
+
end
|
237
|
+
unless record_and_continue?(ret)
|
238
|
+
return nil if ret.nil?
|
239
|
+
return advise_action(ret[:status], ret)
|
240
|
+
end
|
241
|
+
name = ret[:call]
|
242
|
+
rv = ret[:data]
|
243
|
+
args_override = ret[:args]
|
244
|
+
args_override = build_accessor(args_override) if args_override
|
245
|
+
end
|
246
|
+
rescue StandardError => e
|
247
|
+
Sqreen.log.warn { "we catch a JScb exception: #{e.inspect}" }
|
248
|
+
Sqreen.log.debug e.backtrace
|
249
|
+
record_exception(e, :cb => name, :args => arguments)
|
250
|
+
nil
|
251
|
+
end
|
252
|
+
|
253
|
+
def each_hash_val_include(condition, depth = 10)
|
254
|
+
return if depth <= 0
|
255
|
+
condition.each do |key, values|
|
256
|
+
if key == ConditionEvaluator::HASH_INC_OPERATOR
|
257
|
+
yield values
|
258
|
+
else
|
259
|
+
values.map do |v|
|
260
|
+
each_hash_val_include(v, depth - 1) { |vals| yield vals } if v.is_a?(Hash)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def restrict(cbname, arguments)
|
267
|
+
condition = @conditions[cbname]
|
268
|
+
return arguments if condition.nil? || @argument_requirements[cbname].nil?
|
269
|
+
|
270
|
+
each_hash_val_include(condition) do |needle, haystack, min_length|
|
271
|
+
# We could actually run the binding accessor expression here.
|
272
|
+
needed_idx = @argument_requirements[cbname].map(&:expression).index(needle)
|
273
|
+
next unless needed_idx
|
274
|
+
|
275
|
+
haystack_idx = @argument_requirements[cbname].map(&:expression).index(haystack)
|
276
|
+
next unless haystack_idx
|
277
|
+
|
278
|
+
arguments[haystack_idx] = ExecJSCB.hash_val_included(
|
279
|
+
arguments[needed_idx],
|
280
|
+
arguments[haystack_idx],
|
281
|
+
min_length.to_i,
|
282
|
+
@restrict_max_depth
|
283
|
+
)
|
284
|
+
end
|
285
|
+
|
286
|
+
arguments
|
287
|
+
end
|
288
|
+
|
289
|
+
def build_accessor(reqs)
|
290
|
+
reqs.map do |req|
|
291
|
+
BindingAccessor.new(req, true)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def build_runnable(callbacks)
|
296
|
+
@argument_requirements = {}
|
297
|
+
@source = ''
|
298
|
+
@js_pre = !callbacks['pre'].nil?
|
299
|
+
@js_post = !callbacks['post'].nil?
|
300
|
+
@js_failing = !callbacks['failing'].nil?
|
301
|
+
callbacks.each do |name, args_or_func|
|
302
|
+
@source << "var #{name} = "
|
303
|
+
if args_or_func.is_a?(Array)
|
304
|
+
@source << args_or_func.pop
|
305
|
+
@argument_requirements[name] = build_accessor(args_or_func)
|
306
|
+
else
|
307
|
+
@source << args_or_func
|
308
|
+
@argument_requirements[name] = []
|
309
|
+
end
|
310
|
+
@source << ";\n"
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
@@ -122,7 +122,11 @@ module Sqreen
|
|
122
122
|
if escape_html == false &&
|
123
123
|
text.respond_to?(:include?) &&
|
124
124
|
!text.include?('html_escape')
|
125
|
-
|
125
|
+
if text.respond_to? :text=
|
126
|
+
args[0].text = "Sqreen.escape_haml((#{args[0].text}))"
|
127
|
+
else
|
128
|
+
args[0].replace("Sqreen.escape_haml((#{args[0]}))")
|
129
|
+
end
|
126
130
|
end
|
127
131
|
nil
|
128
132
|
end
|
data/lib/sqreen/version.rb
CHANGED
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.
|
4
|
+
version: 1.14.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sqreen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-08-
|
11
|
+
date: 2018-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: execjs
|
@@ -77,6 +77,9 @@ files:
|
|
77
77
|
- lib/sqreen/frameworks/sinatra.rb
|
78
78
|
- lib/sqreen/frameworks/sqreen_test.rb
|
79
79
|
- lib/sqreen/instrumentation.rb
|
80
|
+
- lib/sqreen/js/execjs_adapter.rb
|
81
|
+
- lib/sqreen/js/js_service.rb
|
82
|
+
- lib/sqreen/js/mini_racer_adapter.rb
|
80
83
|
- lib/sqreen/log.rb
|
81
84
|
- lib/sqreen/metrics.rb
|
82
85
|
- lib/sqreen/metrics/average.rb
|
@@ -106,6 +109,7 @@ files:
|
|
106
109
|
- lib/sqreen/rules_callbacks/crawler_user_agent_matches_metrics.rb
|
107
110
|
- lib/sqreen/rules_callbacks/custom_error.rb
|
108
111
|
- lib/sqreen/rules_callbacks/execjs.rb
|
112
|
+
- lib/sqreen/rules_callbacks/execjs_old.rb
|
109
113
|
- lib/sqreen/rules_callbacks/headers_insert.rb
|
110
114
|
- lib/sqreen/rules_callbacks/inspect_rule.rb
|
111
115
|
- lib/sqreen/rules_callbacks/matcher_rule.rb
|
@@ -142,12 +146,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
142
146
|
version: '0'
|
143
147
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
148
|
requirements:
|
145
|
-
- - "
|
149
|
+
- - ">"
|
146
150
|
- !ruby/object:Gem::Version
|
147
|
-
version:
|
151
|
+
version: 1.3.1
|
148
152
|
requirements: []
|
149
153
|
rubyforge_project:
|
150
|
-
rubygems_version: 2.7.
|
154
|
+
rubygems_version: 2.7.7
|
151
155
|
signing_key:
|
152
156
|
specification_version: 4
|
153
157
|
summary: Sqreen Ruby agent
|