sqreen 1.18.6-java → 1.20.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -0
- data/lib/sqreen/actions.rb +2 -0
- data/lib/sqreen/actions/actions_index.rb +16 -0
- data/lib/sqreen/actions/base.rb +4 -10
- data/lib/sqreen/actions/block_ip.rb +2 -0
- data/lib/sqreen/actions/block_user.rb +2 -0
- data/lib/sqreen/actions/ip_range_indexed_action_class.rb +4 -24
- data/lib/sqreen/actions/ip_ranges_index.rb +32 -11
- data/lib/sqreen/actions/redirect_ip.rb +2 -0
- data/lib/sqreen/actions/redirect_user.rb +2 -0
- data/lib/sqreen/actions/repository.rb +27 -8
- data/lib/sqreen/actions/unknown_action_type.rb +4 -0
- data/lib/sqreen/actions/user_action_class.rb +5 -30
- data/lib/sqreen/actions/users_index.rb +35 -0
- data/lib/sqreen/agent.rb +2 -1
- data/lib/sqreen/aggregated_metric.rb +25 -0
- data/lib/sqreen/attack_blocked.rb +2 -0
- data/lib/sqreen/binding_accessor.rb +2 -0
- data/lib/sqreen/binding_accessor/path_elem.rb +2 -0
- data/lib/sqreen/binding_accessor/transforms.rb +8 -1
- data/lib/sqreen/call_countable.rb +2 -0
- data/lib/sqreen/capped_queue.rb +2 -0
- data/lib/sqreen/cb.rb +2 -0
- data/lib/sqreen/cb_tree.rb +2 -0
- data/lib/sqreen/condition_evaluator.rb +2 -0
- data/lib/sqreen/conditionable.rb +2 -0
- data/lib/sqreen/configuration.rb +19 -1
- data/lib/sqreen/context.rb +2 -0
- data/lib/sqreen/default_cb.rb +2 -0
- data/lib/sqreen/deferred_logger.rb +2 -0
- data/lib/sqreen/deliveries.rb +2 -0
- data/lib/sqreen/deliveries/batch.rb +6 -1
- data/lib/sqreen/deliveries/simple.rb +6 -0
- data/lib/sqreen/dependency.rb +3 -1
- data/lib/sqreen/dependency/detector.rb +22 -14
- data/lib/sqreen/dependency/libsqreen.rb +4 -0
- data/lib/sqreen/dependency/new_relic.rb +2 -0
- data/lib/sqreen/dependency/rack.rb +10 -5
- data/lib/sqreen/dependency/rails.rb +4 -0
- data/lib/sqreen/dependency/sentry.rb +2 -0
- data/lib/sqreen/dependency/sinatra.rb +12 -1
- data/lib/sqreen/encoding_sanitizer.rb +2 -0
- data/lib/sqreen/error_handling_middleware.rb +2 -0
- data/lib/sqreen/event.rb +9 -5
- data/lib/sqreen/events/attack.rb +25 -18
- data/lib/sqreen/events/remote_exception.rb +2 -22
- data/lib/sqreen/events/request_record.rb +17 -70
- data/lib/sqreen/exception.rb +2 -0
- data/lib/sqreen/formatter_with_tid.rb +2 -0
- data/lib/sqreen/framework_cb.rb +2 -0
- data/lib/sqreen/frameworks.rb +2 -0
- data/lib/sqreen/frameworks/generic.rb +2 -0
- data/lib/sqreen/frameworks/rails.rb +1 -0
- data/lib/sqreen/frameworks/rails3.rb +2 -0
- data/lib/sqreen/frameworks/request_recorder.rb +15 -2
- data/lib/sqreen/frameworks/sinatra.rb +2 -0
- data/lib/sqreen/frameworks/sqreen_test.rb +2 -0
- data/lib/sqreen/graft.rb +12 -0
- data/lib/sqreen/graft/call.rb +150 -0
- data/lib/sqreen/{dependency → graft}/callback.rb +12 -4
- data/lib/sqreen/graft/hook.rb +316 -0
- data/lib/sqreen/{dependency → graft}/hook_point.rb +152 -33
- data/lib/sqreen/graft/hook_point_error.rb +10 -0
- data/lib/sqreen/invalid_signature_exception.rb +2 -0
- data/lib/sqreen/js.rb +2 -0
- data/lib/sqreen/js/call_context.rb +2 -0
- data/lib/sqreen/js/context_pool.rb +2 -0
- data/lib/sqreen/js/exec_js_runnable.rb +2 -0
- data/lib/sqreen/js/execjs_adapter.rb +2 -0
- data/lib/sqreen/js/executable_js.rb +2 -0
- data/lib/sqreen/js/js_service.rb +2 -0
- data/lib/sqreen/js/js_service_adapter.rb +2 -0
- data/lib/sqreen/js/mini_racer_adapter.rb +2 -0
- data/lib/sqreen/js/mini_racer_executable_js.rb +2 -0
- data/lib/sqreen/js/thread_local_exec_js_runnable.rb +2 -0
- data/lib/sqreen/kit/signals/specialized/aggregated_metric.rb +72 -0
- data/lib/sqreen/kit/signals/specialized/attack.rb +57 -0
- data/lib/sqreen/kit/signals/specialized/binning_metric.rb +76 -0
- data/lib/sqreen/kit/signals/specialized/http_trace.rb +26 -0
- data/lib/sqreen/kit/signals/specialized/sdk_track_call.rb +50 -0
- data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +57 -0
- data/lib/sqreen/{backport.rb → legacy.rb} +3 -2
- data/lib/sqreen/{instrumentation.rb → legacy/instrumentation.rb} +31 -2
- data/lib/sqreen/legacy/old_event_submission_strategy.rb +221 -0
- data/lib/sqreen/legacy/waf_redactions.rb +49 -0
- data/lib/sqreen/log.rb +2 -0
- data/lib/sqreen/log/loggable.rb +28 -0
- data/lib/sqreen/logger.rb +2 -0
- data/lib/sqreen/metrics.rb +2 -0
- data/lib/sqreen/metrics/average.rb +2 -0
- data/lib/sqreen/metrics/base.rb +5 -0
- data/lib/sqreen/metrics/binning.rb +2 -0
- data/lib/sqreen/metrics/collect.rb +2 -0
- data/lib/sqreen/metrics/sum.rb +2 -0
- data/lib/sqreen/metrics_store.rb +24 -12
- data/lib/sqreen/metrics_store/already_registered_metric.rb +2 -0
- data/lib/sqreen/metrics_store/unknown_metric.rb +2 -0
- data/lib/sqreen/metrics_store/unregistered_metric.rb +2 -0
- data/lib/sqreen/middleware.rb +2 -0
- data/lib/sqreen/mono_time.rb +2 -0
- data/lib/sqreen/node.rb +2 -0
- data/lib/sqreen/not_implemented_yet.rb +2 -0
- data/lib/sqreen/null_logger.rb +2 -0
- data/lib/sqreen/payload_creator.rb +2 -0
- data/lib/sqreen/payload_creator/header_section.rb +2 -0
- data/lib/sqreen/performance_notifications.rb +2 -0
- data/lib/sqreen/performance_notifications/binned_metrics.rb +10 -2
- data/lib/sqreen/performance_notifications/log.rb +2 -0
- data/lib/sqreen/performance_notifications/log_performance.rb +2 -0
- data/lib/sqreen/performance_notifications/metrics.rb +2 -0
- data/lib/sqreen/performance_notifications/newrelic.rb +2 -0
- data/lib/sqreen/prefix.rb +2 -0
- data/lib/sqreen/rails_middleware.rb +2 -0
- data/lib/sqreen/remote_command.rb +2 -0
- data/lib/sqreen/remote_command/failure_output.rb +5 -0
- data/lib/sqreen/rules.rb +6 -2
- data/lib/sqreen/rules/attrs.rb +2 -0
- data/lib/sqreen/rules/auth_track_cb.rb +2 -0
- data/lib/sqreen/rules/binding_accessor_matcher_cb.rb +2 -0
- data/lib/sqreen/rules/binding_accessor_metrics.rb +2 -0
- data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -0
- data/lib/sqreen/rules/count_http_codes.rb +2 -0
- data/lib/sqreen/rules/crawler_user_agent_matches_cb.rb +2 -0
- data/lib/sqreen/rules/crawler_user_agent_matches_metrics_cb.rb +2 -0
- data/lib/sqreen/rules/custom_error_cb.rb +2 -0
- data/lib/sqreen/rules/devise_auth_track_cb.rb +2 -0
- data/lib/sqreen/rules/devise_signup_track_cb.rb +2 -0
- data/lib/sqreen/rules/execjs_cb.rb +2 -0
- data/lib/sqreen/rules/headers_insert_cb.rb +7 -0
- data/lib/sqreen/rules/matcher_rule.rb +2 -0
- data/lib/sqreen/rules/not_found_cb.rb +7 -0
- data/lib/sqreen/rules/rails_parameters_cb.rb +2 -0
- data/lib/sqreen/rules/record_request_context.rb +2 -0
- data/lib/sqreen/rules/regexp_rule_cb.rb +2 -0
- data/lib/sqreen/rules/rule_cb.rb +4 -0
- data/lib/sqreen/rules/run_req_start_actions.rb +3 -1
- data/lib/sqreen/rules/run_user_actions.rb +3 -1
- data/lib/sqreen/rules/shell_env_cb.rb +2 -0
- data/lib/sqreen/rules/signup_track_cb.rb +2 -0
- data/lib/sqreen/rules/update_request_context.rb +2 -0
- data/lib/sqreen/rules/url_matches_cb.rb +2 -0
- data/lib/sqreen/rules/user_agent_matches_cb.rb +2 -0
- data/lib/sqreen/rules/waf_cb.rb +41 -16
- data/lib/sqreen/rules/xss_cb.rb +2 -0
- data/lib/sqreen/run_when_called_cb.rb +2 -0
- data/lib/sqreen/runner.rb +68 -12
- data/lib/sqreen/runtime_infos.rb +2 -0
- data/lib/sqreen/safe_json.rb +2 -0
- data/lib/sqreen/sdk.rb +4 -0
- data/lib/sqreen/sensitive_data_redactor.rb +21 -31
- data/lib/sqreen/serializer.rb +2 -0
- data/lib/sqreen/session.rb +41 -37
- data/lib/sqreen/shared_storage.rb +2 -0
- data/lib/sqreen/shared_storage23.rb +2 -0
- data/lib/sqreen/shrink_wrap.rb +16 -0
- data/lib/sqreen/signals/conversions.rb +283 -0
- data/lib/sqreen/signals/http_trace_redaction.rb +111 -0
- data/lib/sqreen/signals/signals_submission_strategy.rb +78 -0
- data/lib/sqreen/signature_verifier.rb +2 -0
- data/lib/sqreen/sinatra_middleware.rb +2 -0
- data/lib/sqreen/sqreen_signed_verifier.rb +2 -0
- data/lib/sqreen/token_invalid_exception.rb +2 -0
- data/lib/sqreen/token_not_found_exception.rb +2 -0
- data/lib/sqreen/trie.rb +2 -0
- data/lib/sqreen/unauthorized.rb +2 -0
- data/lib/sqreen/util.rb +5 -0
- data/lib/sqreen/util/capped_array.rb +2 -0
- data/lib/sqreen/util/capped_hash.rb +2 -0
- data/lib/sqreen/util/capped_string.rb +2 -0
- data/lib/sqreen/util/capper.rb +2 -0
- data/lib/sqreen/version.rb +3 -1
- data/lib/sqreen/waf_error.rb +2 -0
- data/lib/sqreen/weave.rb +12 -0
- data/lib/sqreen/weave/hardcoded.rb +19 -0
- data/lib/sqreen/weave/instrumentor.rb +48 -0
- data/lib/sqreen/weave/legacy.rb +12 -0
- data/lib/sqreen/weave/legacy/instrumentation.rb +406 -0
- data/lib/sqreen/web_server.rb +2 -0
- data/lib/sqreen/web_server/generic.rb +2 -0
- data/lib/sqreen/web_server/passenger.rb +2 -0
- data/lib/sqreen/web_server/puma.rb +2 -0
- data/lib/sqreen/web_server/rainbows.rb +2 -0
- data/lib/sqreen/web_server/thin.rb +2 -0
- data/lib/sqreen/web_server/unicorn.rb +2 -0
- data/lib/sqreen/web_server/webrick.rb +2 -0
- data/lib/sqreen/worker.rb +2 -0
- metadata +65 -9
- data/lib/sqreen/backport/original_name.rb +0 -86
- data/lib/sqreen/dependency/hook.rb +0 -102
@@ -1,3 +1,5 @@
|
|
1
|
+
# typed: true
|
2
|
+
|
1
3
|
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
4
|
# Please refer to our terms for more information: https://www.sqreen.com/terms.html
|
3
5
|
|
@@ -59,7 +61,7 @@ module Sqreen
|
|
59
61
|
obj.each do |k, v|
|
60
62
|
ck = k.is_a?(String) ? k.downcase : k
|
61
63
|
if @keys.include?(ck)
|
62
|
-
redacted
|
64
|
+
redacted += SensitiveDataRedactor.all_strings(v)
|
63
65
|
v = MASK
|
64
66
|
else
|
65
67
|
v, r = redact(v)
|
@@ -72,39 +74,27 @@ module Sqreen
|
|
72
74
|
[result, redacted]
|
73
75
|
end
|
74
76
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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)
|
77
|
+
class << self
|
78
|
+
def all_strings(v)
|
79
|
+
accum = []
|
80
|
+
all_strings_impl(v, accum)
|
81
|
+
accum
|
82
|
+
end
|
91
83
|
|
92
|
-
|
93
|
-
|
84
|
+
private
|
85
|
+
|
86
|
+
def all_strings_impl(obj, accum)
|
87
|
+
case obj
|
88
|
+
when String
|
89
|
+
accum << obj
|
90
|
+
when Array
|
91
|
+
obj.each { |el| all_strings_impl(el, accum) }
|
92
|
+
when Hash
|
93
|
+
obj.each do |k, v|
|
94
|
+
all_strings_impl(k, accum)
|
95
|
+
all_strings_impl(v, accum)
|
94
96
|
end
|
95
97
|
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
98
|
end
|
109
99
|
end
|
110
100
|
end
|
data/lib/sqreen/serializer.rb
CHANGED
data/lib/sqreen/session.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# typed: ignore
|
2
|
+
|
1
3
|
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
2
4
|
# Please refer to our terms for more information: https://www.sqreen.com/terms.html
|
3
5
|
|
@@ -9,6 +11,10 @@ require 'sqreen/events/attack'
|
|
9
11
|
require 'sqreen/events/request_record'
|
10
12
|
require 'sqreen/exception'
|
11
13
|
require 'sqreen/safe_json'
|
14
|
+
require 'sqreen/kit'
|
15
|
+
require 'sqreen/kit/configuration'
|
16
|
+
require 'sqreen/signals/signals_submission_strategy'
|
17
|
+
require 'sqreen/legacy/old_event_submission_strategy'
|
12
18
|
|
13
19
|
require 'net/https'
|
14
20
|
require 'uri'
|
@@ -39,13 +45,12 @@ module Sqreen
|
|
39
45
|
RETRY_MANY = 301
|
40
46
|
|
41
47
|
MUTEX = Mutex.new
|
42
|
-
METRICS_KEY = 'metrics'.freeze
|
43
48
|
|
44
49
|
@@path_prefix = '/sqreen/v0/'
|
45
50
|
|
46
51
|
attr_accessor :request_compression
|
47
52
|
|
48
|
-
def initialize(server_url, token, app_name = nil)
|
53
|
+
def initialize(server_url, token, app_name = nil, proxy_url = nil)
|
49
54
|
@token = token
|
50
55
|
@app_name = app_name
|
51
56
|
@session_id = nil
|
@@ -57,16 +62,35 @@ module Sqreen
|
|
57
62
|
uri = parse_uri(server_url)
|
58
63
|
use_ssl = (uri.scheme == 'https')
|
59
64
|
|
65
|
+
proxy_params = []
|
66
|
+
if proxy_url
|
67
|
+
proxy_uri = parse_uri(proxy_url)
|
68
|
+
proxy_params = [proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password]
|
69
|
+
end
|
70
|
+
|
60
71
|
@req_nb = 0
|
61
72
|
|
62
|
-
@http = Net::HTTP.new(uri.host, uri.port)
|
73
|
+
@http = Net::HTTP.new(uri.host, uri.port, *proxy_params)
|
63
74
|
@http.use_ssl = use_ssl
|
75
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE if ENV['SQREEN_SSL_NO_VERIFY'] # for testing
|
64
76
|
if use_ssl
|
65
77
|
cert_file = File.join(File.dirname(__FILE__), 'ca.crt')
|
66
78
|
cert_store = OpenSSL::X509::Store.new
|
67
79
|
cert_store.add_file cert_file
|
68
80
|
@http.cert_store = cert_store
|
69
81
|
end
|
82
|
+
self.use_signals = false
|
83
|
+
end
|
84
|
+
|
85
|
+
def use_signals=(do_use)
|
86
|
+
return if do_use == @use_signals
|
87
|
+
|
88
|
+
@use_signals = do_use
|
89
|
+
if do_use
|
90
|
+
@evt_sub_strategy = Sqreen::Signals::SignalsSubmissionStrategy.new
|
91
|
+
else
|
92
|
+
@evt_sub_strategy = Sqreen::Legacy::OldEventSubmissionStrategy.new(method(:post))
|
93
|
+
end
|
70
94
|
end
|
71
95
|
|
72
96
|
def parse_uri(uri)
|
@@ -233,6 +257,8 @@ module Sqreen
|
|
233
257
|
end
|
234
258
|
Sqreen.log.info 'Login success.'
|
235
259
|
@session_id = res['session_id']
|
260
|
+
Kit::Configuration.session_key = @session_id
|
261
|
+
Kit.reset
|
236
262
|
Sqreen.log.debug { "received session_id #{@session_id}" }
|
237
263
|
Sqreen.logged_in = true
|
238
264
|
res
|
@@ -244,20 +270,24 @@ module Sqreen
|
|
244
270
|
|
245
271
|
def heartbeat(cmd_res = {}, metrics = [])
|
246
272
|
payload = {}
|
247
|
-
|
273
|
+
unless metrics.nil? || metrics.empty?
|
274
|
+
# never reached with signals
|
275
|
+
payload['metrics'] = metrics.map do |m|
|
276
|
+
Sqreen::Legacy::EventToHash.convert_agg_metric(m)
|
277
|
+
end
|
278
|
+
end
|
248
279
|
payload['command_results'] = cmd_res unless cmd_res.nil? || cmd_res.empty?
|
249
280
|
|
250
281
|
post('app-beat', payload.empty? ? nil : payload, {}, RETRY_MANY)
|
251
282
|
end
|
252
283
|
|
253
284
|
def post_metrics(metrics)
|
254
|
-
|
255
|
-
payload = { METRICS_KEY => metrics }
|
256
|
-
post(METRICS_KEY, payload, {}, RETRY_MANY)
|
285
|
+
@evt_sub_strategy.post_metrics(metrics)
|
257
286
|
end
|
258
287
|
|
288
|
+
# XXX never called
|
259
289
|
def post_attack(attack)
|
260
|
-
|
290
|
+
@evt_sub_strategy.post_attack(attack)
|
261
291
|
end
|
262
292
|
|
263
293
|
def post_bundle(bundle_sig, dependencies)
|
@@ -269,33 +299,17 @@ module Sqreen
|
|
269
299
|
end
|
270
300
|
|
271
301
|
def post_request_record(request_record)
|
272
|
-
|
302
|
+
@evt_sub_strategy.post_request_record(request_record)
|
273
303
|
end
|
274
304
|
|
275
305
|
# Post an exception to Sqreen for analysis
|
276
306
|
# @param exception [RemoteException] Exception and context to be sent over
|
277
307
|
def post_sqreen_exception(exception)
|
278
|
-
|
279
|
-
rescue StandardError => e
|
280
|
-
Sqreen.log.warn(format('Could not post exception (network down? %s) %s',
|
281
|
-
e.inspect,
|
282
|
-
exception.to_hash.inspect))
|
283
|
-
nil
|
308
|
+
@evt_sub_strategy.post_sqreen_exception(exception)
|
284
309
|
end
|
285
310
|
|
286
|
-
BATCH_KEY = 'batch'.freeze
|
287
|
-
EVENT_TYPE_KEY = 'event_type'.freeze
|
288
311
|
def post_batch(events)
|
289
|
-
|
290
|
-
h = event.to_hash
|
291
|
-
h[EVENT_TYPE_KEY] = event_kind(event)
|
292
|
-
h
|
293
|
-
end
|
294
|
-
Sqreen.log.debug do
|
295
|
-
tally = Hash[events.group_by(&:class).map{ |k,v| [k, v.count] }]
|
296
|
-
"Doing batch with the following tally of event types: #{tally}"
|
297
|
-
end
|
298
|
-
post(BATCH_KEY, { BATCH_KEY => batch }, {}, RETRY_MANY)
|
312
|
+
@evt_sub_strategy.post_batch(events)
|
299
313
|
end
|
300
314
|
|
301
315
|
# Perform agent logout
|
@@ -311,15 +325,5 @@ module Sqreen
|
|
311
325
|
Sqreen.logged_in = false
|
312
326
|
disconnect
|
313
327
|
end
|
314
|
-
|
315
|
-
protected
|
316
|
-
|
317
|
-
def event_kind(event)
|
318
|
-
case event
|
319
|
-
when Sqreen::RemoteException then 'sqreen_exception'
|
320
|
-
when Sqreen::Attack then 'attack'
|
321
|
-
when Sqreen::RequestRecord then 'request_record'
|
322
|
-
end
|
323
|
-
end
|
324
328
|
end
|
325
329
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# typed: true
|
2
|
+
|
3
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
4
|
+
# Please refer to our terms for more information: https://www.sqreen.com/terms.html
|
5
|
+
|
6
|
+
module Sqreen
|
7
|
+
class ShrinkWrap
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
@app.call(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,283 @@
|
|
1
|
+
require 'sqreen/version'
|
2
|
+
require 'sqreen/rules/rule_cb'
|
3
|
+
require 'sqreen/metrics/base'
|
4
|
+
require 'sqreen/metrics/binning'
|
5
|
+
require 'sqreen/signals/http_trace_redaction'
|
6
|
+
require 'sqreen/kit/signals/signal_attributes'
|
7
|
+
require 'sqreen/kit/signals/specialized/aggregated_metric'
|
8
|
+
require 'sqreen/kit/signals/specialized/attack'
|
9
|
+
require 'sqreen/kit/signals/specialized/binning_metric'
|
10
|
+
require 'sqreen/kit/signals/specialized/sqreen_exception'
|
11
|
+
require 'sqreen/kit/signals/specialized/http_trace'
|
12
|
+
require 'sqreen/kit/signals/specialized/sdk_track_call'
|
13
|
+
|
14
|
+
module Sqreen
|
15
|
+
module Signals
|
16
|
+
module Conversions # rubocop:disable Metrics/ModuleLength
|
17
|
+
class << self
|
18
|
+
# @param [Sqreen::AggregatedMetric] agg
|
19
|
+
# @return [Sqreen::Kit::Signals::Metric]
|
20
|
+
def convert_metric_sample(agg)
|
21
|
+
attrs = {
|
22
|
+
signal_name: "sq.agent.metric.#{agg.name}",
|
23
|
+
source: if agg.rule
|
24
|
+
"sqreen:rules:#{agg.rule.rulespack_id}:#{agg.rule.rule_name}"
|
25
|
+
else
|
26
|
+
agent_gen_source
|
27
|
+
end,
|
28
|
+
time: agg.finish,
|
29
|
+
}
|
30
|
+
|
31
|
+
if agg.metric.is_a?(Sqreen::Metric::Binning)
|
32
|
+
conv_binning_metric(agg, attrs)
|
33
|
+
else
|
34
|
+
conv_generic_metric(agg, attrs)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param [Sqreen::Attack] attack
|
39
|
+
# XXX: not used because we don't use Sqreen::Attack
|
40
|
+
def convert_attack(attack)
|
41
|
+
# no need to set actor/context as we only include them in request records/traces
|
42
|
+
Kit::Signals::Specialized::Attack.new(
|
43
|
+
signal_name: "sq.agent.attack.#{attack.attack_type}",
|
44
|
+
source: "sqreen:rule:#{attack.rulespack_id}:#{attack.rule_name}",
|
45
|
+
time: attack.time,
|
46
|
+
location: Kit::Signals::Location.new(stack_trace: attack.backtrace),
|
47
|
+
payload: Kit::Signals::Specialized::Attack::Payload.new(
|
48
|
+
test: attack.test?,
|
49
|
+
block: attack.block?,
|
50
|
+
infos: attack.infos
|
51
|
+
)
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
# see Sqreen::Rules::RuleCB.record_event
|
56
|
+
def convert_unstructured_attack(payload)
|
57
|
+
Kit::Signals::Specialized::Attack.new(
|
58
|
+
signal_name: "sq.agent.attack.#{payload[:attack_type]}",
|
59
|
+
source: "sqreen:rule:#{payload[:rulespack_id]}:#{payload[:rule_name]}",
|
60
|
+
time: payload[:time],
|
61
|
+
location: (Kit::Signals::Location.new(stack_trace: payload[:backtrace]) if payload[:backtrace]),
|
62
|
+
payload: Kit::Signals::Specialized::Attack::Payload.new(
|
63
|
+
test: payload[:test],
|
64
|
+
block: payload[:block],
|
65
|
+
infos: payload[:infos]
|
66
|
+
)
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
# @param [Sqreen::RemoteException] exception
|
71
|
+
# @return [Sqreen::Kit::Signals::Specialized::SqreenException]
|
72
|
+
def convert_exception(exception)
|
73
|
+
payload = exception.payload
|
74
|
+
|
75
|
+
infos = payload['client_ip'] ? { client_ip: payload['client_ip'] } : {}
|
76
|
+
infos.merge!(payload['infos'] || {})
|
77
|
+
|
78
|
+
Kit::Signals::Specialized::SqreenException.new(
|
79
|
+
source: if payload['rule_name']
|
80
|
+
"sqreen:rule:#{payload['rulespack_id']}:#{payload['rule_name']}"
|
81
|
+
else
|
82
|
+
agent_gen_source
|
83
|
+
end,
|
84
|
+
time: exception.time,
|
85
|
+
ruby_exception: payload['exception'],
|
86
|
+
infos: infos
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
# see Sqreen::Rules::RuleCB.record_exception
|
91
|
+
# @param [Hash] payload
|
92
|
+
# @return [Sqreen::Kit::Signals::Specialized::SqreenException]
|
93
|
+
def convert_unstructured_exception(payload)
|
94
|
+
Kit::Signals::Specialized::SqreenException.new(
|
95
|
+
source: "sqreen:rule:#{payload[:rulespack_id]}:#{payload[:rule_name]}",
|
96
|
+
time: payload[:time],
|
97
|
+
ruby_exception: payload[:exception],
|
98
|
+
infos: payload[:infos]
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
# @param [Sqreen::RequestRecord] req_rec
|
103
|
+
# @return [Sqreen::Kit::Signals::Specialized::HttpTrace]
|
104
|
+
def convert_req_record(req_rec)
|
105
|
+
payload = req_rec.payload
|
106
|
+
|
107
|
+
request_p = payload['request']
|
108
|
+
id_args = req_rec.last_identify_args
|
109
|
+
identifiers = id_args[0] if id_args
|
110
|
+
traits = id_args[1] if id_args
|
111
|
+
|
112
|
+
observed = payload[:observed] || {}
|
113
|
+
signals = []
|
114
|
+
signals += (observed[:attacks] || [])
|
115
|
+
.map { |att| convert_unstructured_attack(att) }
|
116
|
+
signals += (observed[:sqreen_exceptions] || [])
|
117
|
+
.map { |sq_exc| convert_unstructured_exception(sq_exc) }
|
118
|
+
signals += req_rec.processed_sdk_calls
|
119
|
+
.select { |h| h[:name] == :track }
|
120
|
+
.map { |h| convert_track(h) }
|
121
|
+
|
122
|
+
trace = Kit::Signals::Specialized::HttpTrace.new(
|
123
|
+
actor: Kit::Signals::Actor.new(
|
124
|
+
ip_addresses: [request_p[:client_ip]].compact,
|
125
|
+
user_agent: request_p[:user_agent],
|
126
|
+
identifiers: identifiers,
|
127
|
+
traits: traits,
|
128
|
+
),
|
129
|
+
location_infra: location_infra,
|
130
|
+
context: convert_request(request_p,
|
131
|
+
payload['response'],
|
132
|
+
payload['headers'],
|
133
|
+
payload['params']),
|
134
|
+
data: signals
|
135
|
+
)
|
136
|
+
HttpTraceRedaction.redact_trace!(trace, req_rec.redactor)
|
137
|
+
trace
|
138
|
+
end
|
139
|
+
|
140
|
+
# @param [Array<Sqreen::Kit::Signals::Signal|Sqreen::Kit::Signals::Trace>] batch
|
141
|
+
def convert_batch(batch)
|
142
|
+
batch.map do |evt|
|
143
|
+
case evt
|
144
|
+
when RemoteException
|
145
|
+
convert_exception(evt)
|
146
|
+
when AggregatedMetric
|
147
|
+
convert_metric_sample(evt)
|
148
|
+
when RequestRecord
|
149
|
+
convert_req_record(evt)
|
150
|
+
else
|
151
|
+
raise NotImplementedError, "Unknown type of event in batch: #{evt}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
def agent_gen_source
|
159
|
+
"sqreen:agent:ruby:#{Sqreen::VERSION}"
|
160
|
+
end
|
161
|
+
|
162
|
+
def location_infra
|
163
|
+
@location_infra ||= begin
|
164
|
+
Kit::Signals::LocationInfra.new(
|
165
|
+
agent_version: Sqreen::VERSION,
|
166
|
+
os_type: RuntimeInfos.os[:os_type],
|
167
|
+
hostname: RuntimeInfos.hostname,
|
168
|
+
runtime_type: RuntimeInfos.runtime[:runtime_type],
|
169
|
+
runtime_version: RuntimeInfos.runtime[:runtime_version],
|
170
|
+
libsqreen_version: RuntimeInfos.libsqreen_version,
|
171
|
+
)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# see Sqreen::RequestRecord.processed_sdk_calls
|
176
|
+
def convert_track(call_info)
|
177
|
+
options = call_info[:args][1] || {}
|
178
|
+
Kit::Signals::Specialized::SdkTrackCall.new(
|
179
|
+
signal_name: "sq.sdk.#{call_info[:args][0]}",
|
180
|
+
time: call_info[:time],
|
181
|
+
payload: Kit::Signals::Specialized::SdkTrackCall::Payload.new(
|
182
|
+
properties: options[:properties],
|
183
|
+
user_identifiers: options[:user_identifiers]
|
184
|
+
)
|
185
|
+
)
|
186
|
+
end
|
187
|
+
|
188
|
+
# @param [Hash] req_payload
|
189
|
+
# @param [Hash] headers_payload
|
190
|
+
# @param [Hash] params_payload
|
191
|
+
# see the PayloadCreator abomination for reference
|
192
|
+
# TODO: do not convert from the old payload to the new payload
|
193
|
+
# Have an intermediate object that gets the data from the framework.
|
194
|
+
# (Or convert directly from the framework, but this needs to be
|
195
|
+
# done during the request, not just before event is transmitted)
|
196
|
+
def convert_request(req_payload, resp_payload, headers_payload, params_payload)
|
197
|
+
req_payload ||= {}
|
198
|
+
headers_payload ||= {}
|
199
|
+
resp_payload ||= {}
|
200
|
+
params_payload ||= {}
|
201
|
+
|
202
|
+
other = params_payload['other']
|
203
|
+
other = merge_hash_append(other, params_payload['rack'])
|
204
|
+
other = merge_hash_append(other, params_payload['grape_params'])
|
205
|
+
other = merge_hash_append(other, params_payload['rack_routing'])
|
206
|
+
|
207
|
+
Sqreen::Kit::Signals::Context::HttpContext.new(
|
208
|
+
{
|
209
|
+
rid: req_payload[:rid],
|
210
|
+
headers: headers_payload,
|
211
|
+
user_agent: req_payload[:user_agent],
|
212
|
+
scheme: req_payload[:scheme],
|
213
|
+
verb: req_payload[:verb],
|
214
|
+
host: req_payload[:host],
|
215
|
+
port: req_payload[:port],
|
216
|
+
remote_ip: req_payload[:remote_ip],
|
217
|
+
remote_port: req_payload[:remote_port] || 0,
|
218
|
+
path: req_payload[:path],
|
219
|
+
referer: req_payload[:referer],
|
220
|
+
params_query: params_payload['query'],
|
221
|
+
params_form: params_payload['form'],
|
222
|
+
params_other: other,
|
223
|
+
# endpoint, is_reveal_replayed not set
|
224
|
+
status: resp_payload[:status],
|
225
|
+
content_length: resp_payload[:content_length],
|
226
|
+
content_type: resp_payload[:content_type],
|
227
|
+
}
|
228
|
+
)
|
229
|
+
end
|
230
|
+
|
231
|
+
def merge_hash_append(hash1, hash2)
|
232
|
+
return nil if hash1.nil? && hash2.nil?
|
233
|
+
return hash1 if hash2.nil? || hash2.empty?
|
234
|
+
return hash2 if hash1.nil? || hash1.empty?
|
235
|
+
|
236
|
+
pairs = (hash1.keys + hash2.keys).map do |key|
|
237
|
+
values1 = hash1[key]
|
238
|
+
values2 = hash2[key]
|
239
|
+
values = [values1, values2].compact
|
240
|
+
values = values.first if values.size == 1
|
241
|
+
[key, values]
|
242
|
+
end
|
243
|
+
Hash[pairs]
|
244
|
+
end
|
245
|
+
|
246
|
+
# @param [Sqreen::AggregatedMetric] agg
|
247
|
+
# @param [Hash] attrs
|
248
|
+
def conv_generic_metric(agg, attrs)
|
249
|
+
attrs[:payload] = Kit::Signals::Specialized::AggregatedMetric::Payload.new(
|
250
|
+
kind: metric_kind(agg.metric),
|
251
|
+
capture_interval_s: agg.metric.period,
|
252
|
+
date_started: agg.start,
|
253
|
+
date_ended: agg.finish,
|
254
|
+
values: agg.data
|
255
|
+
)
|
256
|
+
|
257
|
+
Kit::Signals::Specialized::AggregatedMetric.new(attrs)
|
258
|
+
end
|
259
|
+
|
260
|
+
# @param [Sqreen::AggregatedMetric] agg
|
261
|
+
# @param [Hash] attrs
|
262
|
+
def conv_binning_metric(agg, attrs)
|
263
|
+
attrs[:payload] = Kit::Signals::Specialized::BinningMetric::Payload.new(
|
264
|
+
capture_interval_s: agg.metric.period,
|
265
|
+
date_started: agg.start,
|
266
|
+
date_ended: agg.finish,
|
267
|
+
base: agg.data['b'],
|
268
|
+
unit: agg.data['u'],
|
269
|
+
max: agg.data['v']['max'],
|
270
|
+
bins: agg.data['v'].reject { |k, _v| k == 'max' }
|
271
|
+
)
|
272
|
+
|
273
|
+
Kit::Signals::Specialized::BinningMetric.new(attrs)
|
274
|
+
end
|
275
|
+
|
276
|
+
# @param [Sqreen::Metric::Base] metric
|
277
|
+
def metric_kind(metric)
|
278
|
+
metric.class.name.sub(/.*::/, '').sub(/Metric$/, '')
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|