sqreen 1.18.3.beta1 → 1.18.3.beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +0 -5
- data/lib/sqreen/actions.rb +11 -337
- data/lib/sqreen/actions/base.rb +110 -0
- data/lib/sqreen/actions/block_ip.rb +32 -0
- data/lib/sqreen/actions/block_user.rb +44 -0
- data/lib/sqreen/actions/ip_range_indexed_action_class.rb +36 -0
- data/lib/sqreen/actions/ip_ranges_index.rb +36 -0
- data/lib/sqreen/actions/redirect_ip.rb +40 -0
- data/lib/sqreen/actions/redirect_user.rb +45 -0
- data/lib/sqreen/actions/repository.rb +24 -0
- data/lib/sqreen/actions/unknown_action_type.rb +16 -0
- data/lib/sqreen/actions/user_action_class.rb +41 -0
- data/lib/sqreen/agent.rb +4 -1
- data/lib/sqreen/attack_blocked.rb +17 -0
- data/lib/sqreen/binding_accessor.rb +9 -102
- data/lib/sqreen/binding_accessor/path_elem.rb +8 -0
- data/lib/sqreen/binding_accessor/transforms.rb +107 -0
- data/lib/sqreen/capped_queue.rb +2 -0
- data/lib/sqreen/{callbacks.rb → cb.rb} +1 -53
- data/lib/sqreen/{callback_tree.rb → cb_tree.rb} +2 -2
- data/lib/sqreen/condition_evaluator.rb +22 -5
- data/lib/sqreen/configuration.rb +3 -0
- data/lib/sqreen/default_cb.rb +20 -0
- data/lib/sqreen/deferred_logger.rb +63 -0
- data/lib/sqreen/deliveries.rb +10 -0
- data/lib/sqreen/deliveries/batch.rb +7 -1
- data/lib/sqreen/deliveries/simple.rb +5 -0
- data/lib/sqreen/dependency/rails.rb +4 -0
- data/lib/sqreen/dependency/sinatra.rb +4 -0
- data/lib/sqreen/error_handling_middleware.rb +30 -0
- data/lib/sqreen/event.rb +2 -0
- data/lib/sqreen/events/attack.rb +2 -0
- data/lib/sqreen/events/request_record.rb +11 -56
- data/lib/sqreen/exception.rb +9 -40
- data/lib/sqreen/formatter_with_tid.rb +45 -0
- data/lib/sqreen/framework_cb.rb +28 -0
- data/lib/sqreen/frameworks.rb +7 -0
- data/lib/sqreen/frameworks/generic.rb +5 -1
- data/lib/sqreen/frameworks/rails.rb +2 -0
- data/lib/sqreen/frameworks/request_recorder.rb +3 -0
- data/lib/sqreen/frameworks/sinatra.rb +2 -0
- data/lib/sqreen/frameworks/sqreen_test.rb +2 -0
- data/lib/sqreen/instrumentation.rb +5 -5
- data/lib/sqreen/invalid_signature_exception.rb +8 -0
- data/lib/{sqreen-alt.rb → sqreen/js.rb} +6 -1
- data/lib/sqreen/js/call_context.rb +10 -0
- data/lib/sqreen/js/context_pool.rb +60 -0
- data/lib/sqreen/js/exec_js_runnable.rb +20 -0
- data/lib/sqreen/js/execjs_adapter.rb +6 -47
- data/lib/sqreen/js/executable_js.rb +12 -0
- data/lib/sqreen/js/js_service.rb +2 -22
- data/lib/sqreen/js/js_service_adapter.rb +18 -0
- data/lib/sqreen/js/mini_racer_adapter.rb +6 -180
- data/lib/sqreen/js/mini_racer_executable_js.rb +142 -0
- data/lib/sqreen/js/thread_local_exec_js_runnable.rb +47 -0
- data/lib/sqreen/log.rb +8 -188
- data/lib/sqreen/logger.rb +83 -0
- data/lib/sqreen/metrics_store.rb +3 -11
- data/lib/sqreen/metrics_store/already_registered_metric.rb +11 -0
- data/lib/sqreen/metrics_store/unknown_metric.rb +11 -0
- data/lib/sqreen/metrics_store/unregistered_metric.rb +11 -0
- data/lib/sqreen/middleware.rb +0 -44
- data/lib/sqreen/mono_time.rb +2 -0
- data/lib/sqreen/node.rb +44 -0
- data/lib/sqreen/not_implemented_yet.rb +8 -0
- data/lib/sqreen/null_logger.rb +24 -0
- data/lib/sqreen/payload_creator.rb +2 -19
- data/lib/sqreen/payload_creator/header_section.rb +28 -0
- data/lib/sqreen/prefix.rb +33 -0
- data/lib/sqreen/rails_middleware.rb +14 -0
- data/lib/sqreen/remote_command.rb +1 -8
- data/lib/sqreen/remote_command/failure_output.rb +11 -0
- data/lib/sqreen/rules.rb +32 -2
- data/lib/sqreen/{rule_attributes.rb → rules/attrs.rb} +0 -0
- data/lib/sqreen/{rules_callbacks/sdk_auth_track.rb → rules/auth_track_cb.rb} +2 -2
- data/lib/sqreen/{rules_callbacks/binding_accessor_matcher.rb → rules/binding_accessor_matcher_cb.rb} +4 -8
- data/lib/sqreen/{rules_callbacks → rules}/binding_accessor_metrics.rb +1 -1
- data/lib/sqreen/{rules_callbacks/blacklist_ips.rb → rules/blacklist_ips_cb.rb} +3 -2
- data/lib/sqreen/{rules_callbacks → rules}/count_http_codes.rb +2 -2
- data/lib/sqreen/{rules_callbacks/crawler_user_agent_matches.rb → rules/crawler_user_agent_matches_cb.rb} +1 -1
- data/lib/sqreen/{rules_callbacks/crawler_user_agent_matches_metrics.rb → rules/crawler_user_agent_matches_metrics_cb.rb} +1 -1
- data/lib/sqreen/{rules_callbacks/custom_error.rb → rules/custom_error_cb.rb} +1 -1
- data/lib/sqreen/{rules_callbacks/devise_auth_track.rb → rules/devise_auth_track_cb.rb} +2 -2
- data/lib/sqreen/{rules_callbacks/devise_signup_track.rb → rules/devise_signup_track_cb.rb} +2 -2
- data/lib/sqreen/{rules_callbacks/execjs.rb → rules/execjs_cb.rb} +49 -50
- data/lib/sqreen/{rules_callbacks/headers_insert.rb → rules/headers_insert_cb.rb} +1 -1
- data/lib/sqreen/{rules_callbacks → rules}/matcher_rule.rb +2 -2
- data/lib/sqreen/{rules_callbacks/not_found.rb → rules/not_found_cb.rb} +2 -2
- data/lib/sqreen/{rules_callbacks/rails_parameters.rb → rules/rails_parameters_cb.rb} +1 -1
- data/lib/sqreen/{rules_callbacks → rules}/record_request_context.rb +1 -1
- data/lib/sqreen/{rules_callbacks/regexp_rule.rb → rules/regexp_rule_cb.rb} +1 -1
- data/lib/sqreen/{rule_callback.rb → rules/rule_cb.rb} +2 -2
- data/lib/sqreen/{rules_callbacks → rules}/run_req_start_actions.rb +4 -2
- data/lib/sqreen/{rules_callbacks → rules}/run_user_actions.rb +1 -1
- data/lib/sqreen/{rules_callbacks/shell_env.rb → rules/shell_env_cb.rb} +1 -1
- data/lib/sqreen/{rules_callbacks/sdk_signup_track.rb → rules/signup_track_cb.rb} +2 -2
- data/lib/sqreen/{rules_callbacks → rules}/update_request_context.rb +1 -1
- data/lib/sqreen/{rules_callbacks/url_matches.rb → rules/url_matches_cb.rb} +1 -1
- data/lib/sqreen/{rules_callbacks/user_agent_matches.rb → rules/user_agent_matches_cb.rb} +1 -1
- data/lib/sqreen/{rules_callbacks/waf.rb → rules/waf_cb.rb} +7 -3
- data/lib/sqreen/{rules_callbacks/reflected_xss.rb → rules/xss_cb.rb} +10 -7
- data/lib/sqreen/run_when_called_cb.rb +21 -0
- data/lib/sqreen/sensitive_data_redactor.rb +111 -0
- data/lib/sqreen/signature_verifier.rb +20 -0
- data/lib/sqreen/sinatra_middleware.rb +14 -0
- data/lib/sqreen/{rules_signature.rb → sqreen_signed_verifier.rb} +5 -17
- data/lib/sqreen/token_invalid_exception.rb +8 -0
- data/lib/sqreen/token_not_found_exception.rb +9 -0
- data/lib/sqreen/trie.rb +3 -64
- data/lib/sqreen/unauthorized.rb +8 -0
- data/lib/sqreen/util.rb +2 -0
- data/lib/sqreen/util/capped_array.rb +30 -0
- data/lib/sqreen/util/capped_hash.rb +36 -0
- data/lib/sqreen/util/capped_string.rb +22 -0
- data/lib/sqreen/util/capper.rb +57 -0
- data/lib/sqreen/version.rb +1 -1
- data/lib/sqreen/waf_error.rb +18 -0
- metadata +85 -36
- data/lib/sqreen/rules_callbacks.rb +0 -36
- data/lib/sqreen/rules_callbacks/inspect_rule.rb +0 -25
@@ -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
|
+
# TODO: => Sqreen::JS:ExecJS
|
5
|
+
|
6
|
+
require 'sqreen/js/executable_js'
|
7
|
+
|
8
|
+
module Sqreen
|
9
|
+
module Js
|
10
|
+
class ExecJsRunnable < ExecutableJs
|
11
|
+
def initialize(compiled)
|
12
|
+
@compiled = compiled
|
13
|
+
end
|
14
|
+
|
15
|
+
def run_js_cb(cbname, _budget, arguments)
|
16
|
+
@compiled.call(cbname, *arguments)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,8 +1,14 @@
|
|
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
|
+
# TODO: => Sqreen::JS:ExecJS
|
5
|
+
|
4
6
|
require 'execjs'
|
5
7
|
require 'weakref'
|
8
|
+
require 'sqreen/js/executable_js'
|
9
|
+
require 'sqreen/js/js_service_adapter'
|
10
|
+
require 'sqreen/js/exec_js_runnable'
|
11
|
+
require 'sqreen/js/thread_local_exec_js_runnable'
|
6
12
|
|
7
13
|
module Sqreen
|
8
14
|
module Js
|
@@ -25,52 +31,5 @@ module Sqreen
|
|
25
31
|
ExecJS.runtime.name != 'therubyrhino (Rhino)'
|
26
32
|
end
|
27
33
|
end
|
28
|
-
|
29
|
-
class ExecJsRunnable < ExecutableJs
|
30
|
-
def initialize(compiled)
|
31
|
-
@compiled = compiled
|
32
|
-
end
|
33
|
-
|
34
|
-
def run_js_cb(cbname, _budget, arguments)
|
35
|
-
@compiled.call(cbname, *arguments)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
class ThreadLocalExecJsRunnable < ExecutableJs
|
40
|
-
def initialize(code)
|
41
|
-
@code = code
|
42
|
-
@tl_key = "SQREEN_EXECJS_CONTEXT_#{object_id}".freeze
|
43
|
-
@runtimes = [] # place where to keep strong references
|
44
|
-
@runtimes_mutex = Mutex.new
|
45
|
-
end
|
46
|
-
|
47
|
-
def run_js_cb(cbname, _budget, arguments)
|
48
|
-
tl_exec_js_runnable.call(cbname, *arguments)
|
49
|
-
end
|
50
|
-
|
51
|
-
def with_runtimes_mutex
|
52
|
-
@runtimes_mutex.synchronize { yield }
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def dispose_from_dead_threads
|
58
|
-
with_runtimes_mutex do
|
59
|
-
@runtimes.delete_if { |th, _runtime| !th.alive? }
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def tl_exec_js_runnable
|
64
|
-
runnable = Thread.current[@tl_key]
|
65
|
-
return runnable if runnable && runnable.weakref_alive?
|
66
|
-
|
67
|
-
dispose_from_dead_threads
|
68
|
-
runtime = ExecJS.compile(@code)
|
69
|
-
with_runtimes_mutex do
|
70
|
-
@runtimes << [Thread.current, runtime]
|
71
|
-
end
|
72
|
-
Thread.current[@tl_key] = WeakRef.new(runtime)
|
73
|
-
end
|
74
|
-
end
|
75
34
|
end
|
76
35
|
end
|
@@ -0,0 +1,12 @@
|
|
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
|
+
module Js
|
6
|
+
class ExecutableJs
|
7
|
+
def run_js_cb(_cb_name, _budget, _arguments)
|
8
|
+
raise Sqreen::NotImplementedYet
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/sqreen/js/js_service.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
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/log'
|
4
5
|
require 'sqreen/exception'
|
6
|
+
require 'singleton'
|
5
7
|
|
6
8
|
module Sqreen
|
7
9
|
module Js
|
8
|
-
# start public interface
|
9
|
-
|
10
10
|
class JsService
|
11
11
|
include ::Singleton
|
12
12
|
|
@@ -66,25 +66,5 @@ module Sqreen
|
|
66
66
|
false
|
67
67
|
end
|
68
68
|
end
|
69
|
-
|
70
|
-
CallContext = Struct.new(:inst, :args, :rv)
|
71
|
-
|
72
|
-
class ExecutableJs
|
73
|
-
def run_js_cb(_cb_name, _budget, _arguments)
|
74
|
-
raise Sqreen::NotImplementedYet
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# end public interface
|
79
|
-
|
80
|
-
class JsServiceAdapter
|
81
|
-
def preprocess(rule_name, code)
|
82
|
-
raise Sqreen::NotImplementedYet
|
83
|
-
end
|
84
|
-
|
85
|
-
def variant_name
|
86
|
-
'unspecified'
|
87
|
-
end
|
88
|
-
end
|
89
69
|
end
|
90
70
|
end
|
@@ -0,0 +1,18 @@
|
|
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
|
+
module Js
|
8
|
+
class JsServiceAdapter
|
9
|
+
def preprocess(_rule_name, _code)
|
10
|
+
raise Sqreen::NotImplementedYet
|
11
|
+
end
|
12
|
+
|
13
|
+
def variant_name
|
14
|
+
'unspecified'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,14 +1,19 @@
|
|
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
|
+
# TODO: => Sqreen::JS:MiniRacer
|
5
|
+
|
4
6
|
require 'digest'
|
5
7
|
require 'json'
|
8
|
+
require 'sqreen/js/executable_js'
|
9
|
+
require 'sqreen/js/js_service_adapter'
|
10
|
+
require 'sqreen/js/context_pool'
|
11
|
+
require 'sqreen/js/mini_racer_executable_js'
|
6
12
|
|
7
13
|
module Sqreen
|
8
14
|
module Js
|
9
15
|
DEFAULT_GC_THRESHOLD = 15000000 # 15 MB
|
10
16
|
|
11
|
-
|
12
17
|
class MiniRacerAdapter < JsServiceAdapter
|
13
18
|
def initialize(vendored = false)
|
14
19
|
@vendored = vendored
|
@@ -30,184 +35,5 @@ module Sqreen
|
|
30
35
|
@done_static_init = true
|
31
36
|
end
|
32
37
|
end
|
33
|
-
|
34
|
-
# Auxiliary classes
|
35
|
-
|
36
|
-
class ContextPool
|
37
|
-
def initialize
|
38
|
-
@mutex = Mutex.new
|
39
|
-
@total_ctxs = 0
|
40
|
-
@contexts = []
|
41
|
-
end
|
42
|
-
|
43
|
-
def with_context(&block)
|
44
|
-
isolate = get_context
|
45
|
-
begin
|
46
|
-
block[isolate]
|
47
|
-
ensure
|
48
|
-
give_back_context isolate
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
def get_context
|
55
|
-
@mutex.synchronize do
|
56
|
-
if @contexts.empty?
|
57
|
-
@total_ctxs += 1
|
58
|
-
Sqreen.log.debug "Creating new V8 context (#{@total_ctxs})"
|
59
|
-
SqreenContext.new
|
60
|
-
else
|
61
|
-
@contexts.pop
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def give_back_context(context)
|
67
|
-
context.possibly_gc
|
68
|
-
|
69
|
-
if context.gc_load > 30
|
70
|
-
if context.gc_threshold_in_bytes == DEFAULT_GC_THRESHOLD
|
71
|
-
context.gc_threshold_in_bytes *= 2
|
72
|
-
Sqreen.log.warn("Context #{context} had too many close garbage " \
|
73
|
-
'collections; doubling the threshold to ' \
|
74
|
-
"#{context.gc_threshold_in_bytes} bytes")
|
75
|
-
context.gc_load = 0
|
76
|
-
else
|
77
|
-
Sqreen.log.warn("Context #{context} had too many close garbage " \
|
78
|
-
'collections; discarding it')
|
79
|
-
context.dispose
|
80
|
-
return
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
@mutex.synchronize { @contexts.push(context); }
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
class MiniRacerExecutableJs < ExecutableJs
|
89
|
-
@@ctx_defined = false
|
90
|
-
|
91
|
-
def initialize(pool, code, vendored)
|
92
|
-
@pool = pool
|
93
|
-
@code = code
|
94
|
-
@code_id = self.class.code_id(code)
|
95
|
-
|
96
|
-
@module = vendored ? Sqreen::MiniRacer : MiniRacer
|
97
|
-
|
98
|
-
mod = vendored ? Sqreen::MiniRacer : MiniRacer
|
99
|
-
unless @@ctx_defined
|
100
|
-
self.class.define_sqreen_context(mod)
|
101
|
-
@@ctx_defined = true
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def run_js_cb(cb_name, budget, arguments)
|
106
|
-
@pool.with_context do |ctx|
|
107
|
-
if ctx.code_failed?(@code_id)
|
108
|
-
Sqreen.log.debug do
|
109
|
-
"Skipping execution of callback #{cb_name} (code md5 #{@code_id})" \
|
110
|
-
" due to prev failure of definition evaluation"
|
111
|
-
end
|
112
|
-
return nil
|
113
|
-
end
|
114
|
-
|
115
|
-
ctx.add_code(@code_id, @code) unless ctx.has_code?(@code_id)
|
116
|
-
|
117
|
-
# mini_racer expects timeout to be in ms
|
118
|
-
ctx.timeout = budget ? budget * 1000.0 : nil
|
119
|
-
begin
|
120
|
-
ctx.call("sqreen_#{@code_id}_#{cb_name}", *arguments)
|
121
|
-
rescue @module::ScriptTerminatedError
|
122
|
-
Sqreen.log.debug "ScriptTerminatedError/#{cb_name}"
|
123
|
-
nil
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def self.code_id(code)
|
129
|
-
Digest::MD5.hexdigest(code)
|
130
|
-
end
|
131
|
-
|
132
|
-
private
|
133
|
-
|
134
|
-
class << self
|
135
|
-
def define_sqreen_context(modoole)
|
136
|
-
# Context specialized for Sqreen usage
|
137
|
-
Sqreen::Js.const_set 'SqreenContext', Class.new(modoole.const_get('Context'))
|
138
|
-
SqreenContext.class_eval do
|
139
|
-
attr_accessor :gc_threshold_in_bytes
|
140
|
-
attr_accessor :gc_load
|
141
|
-
attr_writer :timeout
|
142
|
-
|
143
|
-
def has_code?(code_id)
|
144
|
-
return false unless @code_ids
|
145
|
-
@code_ids.include?(code_id)
|
146
|
-
end
|
147
|
-
|
148
|
-
def code_failed?(code_id)
|
149
|
-
return false unless @failed_code_ids
|
150
|
-
@failed_code_ids.include?(code_id)
|
151
|
-
end
|
152
|
-
|
153
|
-
def add_code(code_id, code)
|
154
|
-
# It's important that the definition is run in its own scope (by executing it inside an anonymous function)
|
155
|
-
# Otherwise some auxiliary functions that the backend server sends will collide the name
|
156
|
-
# Because they're defined with `var`, running the definitions inside a function is enough
|
157
|
-
eval_unsafe "(function() { #{code} })()"
|
158
|
-
transf_global_funcs code_id
|
159
|
-
@code_ids ||= Set.new
|
160
|
-
@code_ids << code_id
|
161
|
-
rescue
|
162
|
-
@failed_code_ids ||= Set.new
|
163
|
-
@failed_code_ids << code_id
|
164
|
-
raise
|
165
|
-
end
|
166
|
-
|
167
|
-
def eval_unsafe(str, filename = nil, timeoutv = nil)
|
168
|
-
# Beware, timeout could be kept in the context
|
169
|
-
# if perf cap is removed after having been activated
|
170
|
-
# As it's unused by execjscb we are not cleaning it
|
171
|
-
return super(str, filename) if timeoutv.nil?
|
172
|
-
return if timeoutv <= 0.0
|
173
|
-
timeoutv *= 1000 # Timeout are currently expressed in seconds
|
174
|
-
@timeout = timeoutv
|
175
|
-
@eval_thread = Thread.current
|
176
|
-
timeout do
|
177
|
-
super(str, filename)
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
def possibly_gc
|
182
|
-
@gc_threshold_in_bytes ||= DEFAULT_GC_THRESHOLD
|
183
|
-
@gc_load ||= 0
|
184
|
-
|
185
|
-
# garbage collections max 1 in every 4 calls (avg)
|
186
|
-
if heap_stats[:total_heap_size] > @gc_threshold_in_bytes
|
187
|
-
low_memory_notification
|
188
|
-
@gc_load += 4
|
189
|
-
else
|
190
|
-
@gc_load = [0, @gc_load - 1].max
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
private
|
195
|
-
|
196
|
-
def transf_global_funcs(code_id)
|
197
|
-
# Multiple callbacks may share the same name. In order to avoid collisions, we rename them here.
|
198
|
-
eval_unsafe <<EOD
|
199
|
-
Object.keys(this).forEach(name => {
|
200
|
-
if (typeof this[name] === "function" && !name.startsWith("sqreen_")) {
|
201
|
-
this['sqreen_#{code_id}_' + name] = this[name];
|
202
|
-
this[name] = undefined;
|
203
|
-
}
|
204
|
-
});
|
205
|
-
EOD
|
206
|
-
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
38
|
end
|
213
39
|
end
|
@@ -0,0 +1,142 @@
|
|
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::JS:MiniRacer
|
5
|
+
# TODO: remove class vars
|
6
|
+
|
7
|
+
require 'sqreen/log'
|
8
|
+
|
9
|
+
module Sqreen
|
10
|
+
module Js
|
11
|
+
class MiniRacerExecutableJs < ExecutableJs
|
12
|
+
@@ctx_defined = false # rubocop:disable Style/ClassVars
|
13
|
+
|
14
|
+
def ctx_defined?
|
15
|
+
@@ctx_defined
|
16
|
+
end
|
17
|
+
|
18
|
+
def define_ctx!
|
19
|
+
@@ctx_defined = true # rubocop:disable Style/ClassVars
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(pool, code, vendored)
|
23
|
+
@pool = pool
|
24
|
+
@code = code
|
25
|
+
@code_id = self.class.code_id(code)
|
26
|
+
|
27
|
+
@module = vendored ? Sqreen::MiniRacer : MiniRacer
|
28
|
+
|
29
|
+
mod = vendored ? Sqreen::MiniRacer : MiniRacer
|
30
|
+
|
31
|
+
return if ctx_defined?
|
32
|
+
|
33
|
+
self.class.define_sqreen_context(mod)
|
34
|
+
define_ctx!
|
35
|
+
end
|
36
|
+
|
37
|
+
def run_js_cb(cb_name, budget, arguments)
|
38
|
+
@pool.with_context do |ctx|
|
39
|
+
if ctx.code_failed?(@code_id)
|
40
|
+
Sqreen.log.debug do
|
41
|
+
"Skipping execution of callback #{cb_name} (code md5 #{@code_id})" \
|
42
|
+
" due to prev failure of definition evaluation"
|
43
|
+
end
|
44
|
+
return nil
|
45
|
+
end
|
46
|
+
|
47
|
+
ctx.add_code(@code_id, @code) unless ctx.code?(@code_id)
|
48
|
+
|
49
|
+
# mini_racer expects timeout to be in ms
|
50
|
+
ctx.timeout = budget ? budget * 1000.0 : nil
|
51
|
+
begin
|
52
|
+
ctx.call("sqreen_#{@code_id}_#{cb_name}", *arguments)
|
53
|
+
rescue @module::ScriptTerminatedError
|
54
|
+
Sqreen.log.debug "ScriptTerminatedError/#{cb_name}"
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.code_id(code)
|
61
|
+
Digest::MD5.hexdigest(code)
|
62
|
+
end
|
63
|
+
|
64
|
+
class << self
|
65
|
+
def define_sqreen_context(modoole)
|
66
|
+
# Context specialized for Sqreen usage
|
67
|
+
Sqreen::Js.const_set 'SqreenContext', Class.new(modoole.const_get('Context'))
|
68
|
+
SqreenContext.class_eval do
|
69
|
+
attr_accessor :gc_threshold_in_bytes
|
70
|
+
attr_accessor :gc_load
|
71
|
+
attr_writer :timeout
|
72
|
+
|
73
|
+
def code?(code_id)
|
74
|
+
return false unless @code_ids
|
75
|
+
@code_ids.include?(code_id)
|
76
|
+
end
|
77
|
+
|
78
|
+
def code_failed?(code_id)
|
79
|
+
return false unless @failed_code_ids
|
80
|
+
@failed_code_ids.include?(code_id)
|
81
|
+
end
|
82
|
+
|
83
|
+
def add_code(code_id, code)
|
84
|
+
# It's important that the definition is run in its own scope (by executing it inside an anonymous function)
|
85
|
+
# Otherwise some auxiliary functions that the backend server sends will collide the name
|
86
|
+
# Because they're defined with `var`, running the definitions inside a function is enough
|
87
|
+
eval_unsafe "(function() { #{code} })()"
|
88
|
+
transf_global_funcs code_id
|
89
|
+
@code_ids ||= Set.new
|
90
|
+
@code_ids << code_id
|
91
|
+
rescue StandardError
|
92
|
+
@failed_code_ids ||= Set.new
|
93
|
+
@failed_code_ids << code_id
|
94
|
+
raise
|
95
|
+
end
|
96
|
+
|
97
|
+
def eval_unsafe(str, filename = nil, timeoutv = nil)
|
98
|
+
# Beware, timeout could be kept in the context
|
99
|
+
# if perf cap is removed after having been activated
|
100
|
+
# As it's unused by execjscb we are not cleaning it
|
101
|
+
return super(str, filename) if timeoutv.nil?
|
102
|
+
return if timeoutv <= 0.0
|
103
|
+
timeoutv *= 1000 # Timeout are currently expressed in seconds
|
104
|
+
@timeout = timeoutv
|
105
|
+
@eval_thread = Thread.current
|
106
|
+
timeout do
|
107
|
+
super(str, filename)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def possibly_gc
|
112
|
+
@gc_threshold_in_bytes ||= DEFAULT_GC_THRESHOLD
|
113
|
+
@gc_load ||= 0
|
114
|
+
|
115
|
+
# garbage collections max 1 in every 4 calls (avg)
|
116
|
+
if heap_stats[:total_heap_size] > @gc_threshold_in_bytes
|
117
|
+
low_memory_notification
|
118
|
+
@gc_load += 4
|
119
|
+
else
|
120
|
+
@gc_load = [0, @gc_load - 1].max
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def transf_global_funcs(code_id)
|
127
|
+
# Multiple callbacks may share the same name. In order to avoid collisions, we rename them here.
|
128
|
+
eval_unsafe <<-JS
|
129
|
+
Object.keys(this).forEach(name => {
|
130
|
+
if (typeof this[name] === "function" && !name.startsWith("sqreen_")) {
|
131
|
+
this['sqreen_#{code_id}_' + name] = this[name];
|
132
|
+
this[name] = undefined;
|
133
|
+
}
|
134
|
+
});
|
135
|
+
JS
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|