sqreen 1.20.0 → 1.20.4
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 +29 -0
- data/lib/sqreen/actions/block_user.rb +1 -1
- data/lib/sqreen/actions/redirect_ip.rb +1 -1
- data/lib/sqreen/actions/redirect_user.rb +1 -1
- data/lib/sqreen/agent_message.rb +20 -0
- data/lib/sqreen/attack_detected.html +1 -2
- data/lib/sqreen/ca.crt +24 -0
- data/lib/sqreen/condition_evaluator.rb +8 -2
- data/lib/sqreen/configuration.rb +5 -3
- data/lib/sqreen/deferred_logger.rb +50 -14
- data/lib/sqreen/deprecation.rb +38 -0
- data/lib/sqreen/endpoint_testing.rb +184 -0
- data/lib/sqreen/events/request_record.rb +0 -1
- data/lib/sqreen/frameworks/generic.rb +9 -0
- data/lib/sqreen/frameworks/rails.rb +0 -7
- data/lib/sqreen/frameworks/request_recorder.rb +2 -0
- data/lib/sqreen/graft/call.rb +76 -18
- data/lib/sqreen/graft/callback.rb +1 -1
- data/lib/sqreen/graft/hook.rb +187 -85
- data/lib/sqreen/graft/hook_point.rb +1 -1
- data/lib/sqreen/legacy/instrumentation.rb +22 -10
- data/lib/sqreen/legacy/old_event_submission_strategy.rb +2 -1
- data/lib/sqreen/log.rb +3 -2
- data/lib/sqreen/log/loggable.rb +2 -1
- data/lib/sqreen/logger.rb +24 -0
- data/lib/sqreen/metrics_store.rb +11 -0
- data/lib/sqreen/null_logger.rb +22 -0
- data/lib/sqreen/remote_command.rb +1 -0
- data/lib/sqreen/rules.rb +8 -4
- data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
- data/lib/sqreen/rules/custom_error_cb.rb +3 -3
- data/lib/sqreen/rules/rule_cb.rb +2 -0
- data/lib/sqreen/rules/waf_cb.rb +3 -3
- data/lib/sqreen/runner.rb +64 -9
- data/lib/sqreen/session.rb +17 -11
- data/lib/sqreen/version.rb +1 -1
- data/lib/sqreen/weave/budget.rb +46 -0
- data/lib/sqreen/weave/legacy/instrumentation.rb +194 -103
- data/lib/sqreen/worker.rb +6 -2
- metadata +9 -7
- data/lib/sqreen/encoding_sanitizer.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7324df5cecbb626299a4e048550c6f7c5a3e15bef2eecc8d89011d0342914aa
|
4
|
+
data.tar.gz: eabb5203769dcf898d8a4e373c6cfee7e5b0eac8bbfc3977fb8924a54504b126
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e7f4bb53e01c0f5328a5190b189c82b596bcf28eada2104b1491c5601b1275866ef8950ae9ad92c91303011636a3c11ebcb3c3dbccd75280d6b89c1c69d301a
|
7
|
+
data.tar.gz: 77770ff7b00b9d07ea7f4137eadce1e840bc1ad94e885b42623354707306ebd42425187833e0403e33d02bea7471010bf934bda9010c5fe1d604715c5daf88c1
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,32 @@
|
|
1
|
+
## 1.20.4
|
2
|
+
|
3
|
+
* Fix missing budget check
|
4
|
+
* Improve performance
|
5
|
+
* Align internal setting name for WAF
|
6
|
+
* Include response information in all payloads
|
7
|
+
* Improve robustness against invalid Unicode
|
8
|
+
* Prevent rule execution to pursue in early block cases
|
9
|
+
|
10
|
+
## 1.20.4.beta1
|
11
|
+
|
12
|
+
* Add optional dynamic time budget
|
13
|
+
* Add advanced per request metrics
|
14
|
+
* Improve robustness against exception in instrumentation
|
15
|
+
* Improve metric engine thread safety
|
16
|
+
* Restrict deferred logger to final logger severity on agent boot
|
17
|
+
|
18
|
+
## 1.20.3
|
19
|
+
|
20
|
+
* Fix signature check
|
21
|
+
|
22
|
+
## 1.20.2
|
23
|
+
|
24
|
+
* Fix performance regression in instrumentation engine
|
25
|
+
|
26
|
+
## 1.20.1
|
27
|
+
|
28
|
+
* Add fallback mechanisms when connecting to new Sqreen backend API domains
|
29
|
+
|
1
30
|
## 1.20.0
|
2
31
|
|
3
32
|
* Enable new instrumentation engine by default
|
@@ -24,7 +24,7 @@ module Sqreen
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def do_run(identity_params)
|
27
|
-
Sqreen.log.
|
27
|
+
Sqreen.log.debug 'Will request redirect for user with identity ' \
|
28
28
|
"#{identity_params} (action: #{id})."
|
29
29
|
|
30
30
|
e = Sqreen::AttackBlocked.new(
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'digest'
|
2
|
+
|
3
|
+
module Sqreen
|
4
|
+
class AgentMessage
|
5
|
+
def initialize(kind, message, id = nil)
|
6
|
+
id ||= message + "\x00" + kind
|
7
|
+
@hash_hex = Digest::SHA1.hexdigest(id)
|
8
|
+
@kind = kind
|
9
|
+
@message = message
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_h
|
13
|
+
{
|
14
|
+
id: @hash_hex,
|
15
|
+
kind: @kind,
|
16
|
+
message: @message,
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,2 +1 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
<!-- Sorry, you’ve been blocked --><!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>You've been blocked</title><style>a,body,div,h1,html,span{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}body{background:-webkit-radial-gradient(26% 19%,circle,#fff,#f4f7f9);background:radial-gradient(circle at 26% 19%,#fff,#f4f7f9);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:center;align-content:center;width:100%;min-height:100vh;line-height:1;flex-direction:column}h1,p,svg{display:block}svg{margin:0 auto 4vh}main{text-align:center;flex:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-line-pack:center;align-content:center;flex-direction:column}h1{font-family:sans-serif;font-weight:600;font-size:34px;color:#1e0936;line-height:1.2}p{font-size:18px;line-height:normal;color:#646464;font-family:sans-serif;font-weight:400}a{color:#4842b7}footer{width:100%;text-align:center}footer p{font-size:16px}</style></head><body><main><svg width="170px" height="193px" viewBox="0 0 170 193" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true"><g id="exports" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="Artboard" transform="translate(-186.000000, -189.000000)"><g id="logo-cmyk-indigo" transform="translate(186.000000, 189.000000)"><g id="nest-cmyk-indigo"><ellipse id="sqreen" fill="#B0ACFF" cx="85" cy="96.5" rx="45.7692308" ry="45.7966102"></ellipse><path d="M78.4615385,175.749389 L78.4615385,102.2092 L13.1398162,64.4731256 L13.1398162,129.181112 L36.352167,115.771438 C37.9764468,119.873152 40.1038639,123.720553 42.6582364,127.237412 L18.5723996,141.151695 L78.4615385,175.749389 Z M91.5384615,175.749389 L151.4276,141.151695 L127.341764,127.237412 C129.896136,123.720553 132.023553,119.873152 133.647833,115.771438 L156.860184,129.181112 L156.860184,64.4731256 L91.5384615,102.2092 L91.5384615,175.749389 Z M18.0061522,52.1754237 L85,90.8774777 L151.993848,52.1754237 L91.5384615,17.2506105 L91.5384615,44.565949 C89.3964992,44.2986903 87.2143177,44.1610169 85,44.1610169 C82.7856823,44.1610169 80.6035008,44.2986903 78.4615385,44.565949 L78.4615385,17.2506105 L18.0061522,52.1754237 Z M90.8846156,1.76392358 L164.052491,44.0326866 C167.693904,46.1363149 169.937107,50.0239804 169.937107,54.231237 L169.937107,138.768763 C169.937107,142.97602 167.693904,146.863685 164.052491,148.967313 L90.8846156,191.236076 C87.2432028,193.339705 82.7567972,193.339705 79.1153844,191.236076 L5.94750871,148.967313 C2.30609589,146.863685 0.0628930904,142.97602 0.0628930904,138.768763 L0.0628930904,54.231237 C0.0628930904,50.0239804 2.30609589,46.1363149 5.94750871,44.0326866 L79.1153844,1.76392358 C82.7567972,-0.339704735 87.2432028,-0.339704735 90.8846156,1.76392358 Z" id="app" fill="#4842B7"></path></g></g></g></g></svg><h1>Sorry, you've been blocked</h1><p>Contact the website owner</p></main><footer><p>Security provided by <a href="https://www.sqreen.com/?utm_medium=block_page" target="_blank">Sqreen</a></p></footer></body></html>
|
data/lib/sqreen/ca.crt
CHANGED
@@ -70,3 +70,27 @@ WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
|
|
70
70
|
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
|
71
71
|
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
|
72
72
|
-----END CERTIFICATE-----
|
73
|
+
-----BEGIN CERTIFICATE-----
|
74
|
+
MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
|
75
|
+
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
76
|
+
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
|
77
|
+
ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
|
78
|
+
MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
|
79
|
+
VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
|
80
|
+
ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
|
81
|
+
dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
|
82
|
+
hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
|
83
|
+
OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
|
84
|
+
8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
|
85
|
+
Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
|
86
|
+
hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
|
87
|
+
6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
|
88
|
+
DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
|
89
|
+
AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
|
90
|
+
bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
|
91
|
+
ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
|
92
|
+
qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
|
93
|
+
iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
|
94
|
+
0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
|
95
|
+
sSi6
|
96
|
+
-----END CERTIFICATE-----
|
@@ -67,7 +67,7 @@ module Sqreen
|
|
67
67
|
return true if rem <= 0
|
68
68
|
if hash.is_a?(Array)
|
69
69
|
return hash.any? do |v|
|
70
|
-
|
70
|
+
hash_key_include?(values, v, min_value_size, rem - 1)
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
@@ -81,7 +81,13 @@ module Sqreen
|
|
81
81
|
if hkey.respond_to?(:empty?) && hkey.empty?
|
82
82
|
false
|
83
83
|
else
|
84
|
-
|
84
|
+
key_incl = if values.is_a?(String)
|
85
|
+
str_include?(values, hkey.to_s)
|
86
|
+
else
|
87
|
+
values.include?(hkey.to_s)
|
88
|
+
end
|
89
|
+
|
90
|
+
key_incl || hash_key_include?(values, hval, min_value_size, rem - 1)
|
85
91
|
end
|
86
92
|
end
|
87
93
|
end
|
data/lib/sqreen/configuration.rb
CHANGED
@@ -43,9 +43,9 @@ module Sqreen
|
|
43
43
|
{ :env => :SQREEN_WEAVE_STRATEGY, :name => :weave_strategy,
|
44
44
|
:default => :prepend, :convert => :to_sym },
|
45
45
|
{ :env => :SQREEN_URL, :name => :url,
|
46
|
-
:default =>
|
46
|
+
:default => nil },
|
47
47
|
{ :env => :SQREEN_INGESTION_URL, :name => :ingestion_url,
|
48
|
-
:default =>
|
48
|
+
:default => nil },
|
49
49
|
{ :env => :SQREEN_PROXY_URL, :name => :proxy_url,
|
50
50
|
:default => nil },
|
51
51
|
{ :env => :SQREEN_TOKEN, :name => :token,
|
@@ -57,7 +57,7 @@ module Sqreen
|
|
57
57
|
{ :env => :SQREEN_RULES_SIGNATURE, :name => :rules_verify_signature,
|
58
58
|
:default => true },
|
59
59
|
{ :env => :SQREEN_LOG_LEVEL, :name => :log_level,
|
60
|
-
:default => '
|
60
|
+
:default => 'INFO', :choice => %w[UNKNOWN FATAL ERROR WARN INFO DEBUG] },
|
61
61
|
{ :env => :SQREEN_LOG_LOCATION, :name => :log_location,
|
62
62
|
:default => 'log/sqreen.log' },
|
63
63
|
{ :env => :SQREEN_RUN_IN_TEST, :name => :run_in_test,
|
@@ -78,6 +78,8 @@ module Sqreen
|
|
78
78
|
:default => nil },
|
79
79
|
{ :env => :SQREEN_STRIP_SENSITIVE_REGEX, :name => :strip_sensitive_regex,
|
80
80
|
:default => nil },
|
81
|
+
{ :env => :SQREEN_NO_SNIFF_DOMAINS, :name => :no_sniff_domains,
|
82
|
+
:default => false },
|
81
83
|
|
82
84
|
].freeze
|
83
85
|
|
@@ -9,35 +9,70 @@ require 'sqreen/logger'
|
|
9
9
|
|
10
10
|
module Sqreen
|
11
11
|
class DeferredLogger
|
12
|
-
|
12
|
+
MAX_ENTRIES = 1000
|
13
|
+
|
14
|
+
Entry = Struct.new(:severity, :message)
|
13
15
|
|
14
16
|
def initialize
|
15
17
|
@buffer = StringIO.new
|
16
18
|
@logger = ::Logger.new(@buffer)
|
19
|
+
@entries = []
|
20
|
+
@mutex = Mutex.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def debug?
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
def info?
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
def warn?
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
def error?
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
def fatal?
|
40
|
+
true
|
17
41
|
end
|
18
42
|
|
19
43
|
def debug(msg = nil, &block)
|
20
|
-
|
44
|
+
add(::Logger::DEBUG, msg, &block)
|
21
45
|
end
|
22
46
|
|
23
47
|
def info(msg = nil, &block)
|
24
|
-
|
48
|
+
add(::Logger::INFO, msg, &block)
|
25
49
|
end
|
26
50
|
|
27
51
|
def warn(msg = nil, &block)
|
28
|
-
|
52
|
+
add(::Logger::WARN, msg, &block)
|
29
53
|
end
|
30
54
|
|
31
55
|
def error(msg = nil, &block)
|
32
|
-
|
56
|
+
add(::Logger::ERROR, msg, &block)
|
33
57
|
end
|
34
58
|
|
35
59
|
def fatal(msg = nil, &block)
|
36
|
-
|
60
|
+
add(::Logger::FATAL, msg, &block)
|
61
|
+
end
|
62
|
+
|
63
|
+
def unknown(msg = nil, &block)
|
64
|
+
add(::Logger::UNKNOWN, msg, &block)
|
37
65
|
end
|
38
66
|
|
39
67
|
def add(severity, msg = nil, &block)
|
40
|
-
|
68
|
+
@mutex.synchronize do
|
69
|
+
@entries.shift if @entries.count >= MAX_ENTRIES
|
70
|
+
mark = @buffer.pos
|
71
|
+
@logger.add(severity, msg, &block)
|
72
|
+
@buffer.seek(mark)
|
73
|
+
@entries << Entry.new(severity, @buffer.read)
|
74
|
+
@buffer.truncate(0)
|
75
|
+
end
|
41
76
|
end
|
42
77
|
|
43
78
|
def formatter=(value)
|
@@ -45,21 +80,22 @@ module Sqreen
|
|
45
80
|
end
|
46
81
|
|
47
82
|
def flush_to(logger)
|
48
|
-
|
83
|
+
@mutex.synchronize do
|
84
|
+
@entries.each do |entry|
|
85
|
+
next if entry.severity < logger.level
|
86
|
+
logger.instance_eval { @logdev }.write(entry.message)
|
87
|
+
end
|
88
|
+
reset
|
89
|
+
end
|
49
90
|
end
|
50
91
|
|
51
92
|
private
|
52
93
|
|
53
|
-
def read
|
54
|
-
@buffer.rewind
|
55
|
-
@buffer.read
|
56
|
-
end
|
57
|
-
|
58
94
|
def reset
|
59
95
|
buffer = StringIO.new
|
60
96
|
logger = ::Logger.new(buffer)
|
61
97
|
logger.formatter = @logger.formatter
|
62
|
-
@buffer, @logger = buffer, logger
|
98
|
+
@buffer, @logger, @entries = buffer, logger, []
|
63
99
|
end
|
64
100
|
end
|
65
101
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# typed: strong
|
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
|
+
require 'sqreen/log/loggable'
|
7
|
+
|
8
|
+
module Sqreen
|
9
|
+
module Deprecation
|
10
|
+
include Sqreen::Log::Loggable
|
11
|
+
|
12
|
+
module_function
|
13
|
+
|
14
|
+
def deprecate(method)
|
15
|
+
return unless ENV['SQREEN_DEBUG_DEPRECATION']
|
16
|
+
|
17
|
+
owner = method.owner
|
18
|
+
deprecated = :"_deprecated_#{method.name}"
|
19
|
+
klass = owner.is_a?(Module)
|
20
|
+
target = klass ? owner.to_s : owner.class.to_s
|
21
|
+
|
22
|
+
method.owner.instance_eval do
|
23
|
+
alias_method deprecated, method.name
|
24
|
+
|
25
|
+
define_method(method.name) do |*args, &block|
|
26
|
+
msg = [
|
27
|
+
"deprecation",
|
28
|
+
"target:#{target}",
|
29
|
+
"method:#{method.name}",
|
30
|
+
"caller:#{Kernel.caller_locations[0]}",
|
31
|
+
].join(' ')
|
32
|
+
Sqreen::Deprecation.logger.info(msg)
|
33
|
+
send(deprecated, *args, &block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'sqreen/agent_message'
|
3
|
+
require 'sqreen/log/loggable'
|
4
|
+
|
5
|
+
module Sqreen
|
6
|
+
class EndpointTesting
|
7
|
+
Endpoint = Struct.new(:url, :ca_store)
|
8
|
+
class ChosenEndpoints
|
9
|
+
def initialize
|
10
|
+
@messages = []
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Sqreen::EndpointTesting::Endpoint]
|
14
|
+
attr_accessor :control
|
15
|
+
|
16
|
+
# @return [Sqreen::EndpointTesting::Endpoint]
|
17
|
+
attr_accessor :ingestion
|
18
|
+
|
19
|
+
# @return [Array<Sqreen::AgentMessage>]
|
20
|
+
attr_reader :messages
|
21
|
+
|
22
|
+
# @param [Sqreen::AgentMessage] message
|
23
|
+
def add_message(message)
|
24
|
+
@messages << message
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
MAIN_CONTROL_HOST = 'back.sqreen.com'.freeze
|
29
|
+
MAIN_INJECTION_HOST = 'ingestion.sqreen.com'.freeze
|
30
|
+
FALLBACK_ENDPOINT_URL = 'https://back.sqreen.io/'.freeze
|
31
|
+
GLOBAL_TIMEOUT = 30
|
32
|
+
|
33
|
+
CONTROL_ERROR_KIND = 'back_sqreen_com_unavailable'.freeze
|
34
|
+
INGESTION_ERROR_KIND = 'ingestion_sqreen_com_unavailable'.freeze
|
35
|
+
|
36
|
+
class << self
|
37
|
+
include Log::Loggable
|
38
|
+
|
39
|
+
# reproduces behaviour before endpoint testing was introduced
|
40
|
+
def no_test_endpoints(config_url, config_ingestion_url)
|
41
|
+
endpoints = ChosenEndpoints.new
|
42
|
+
|
43
|
+
endpoints.control = Endpoint.new(
|
44
|
+
config_url || "https://#{MAIN_CONTROL_HOST}/", cert_store
|
45
|
+
)
|
46
|
+
endpoints.ingestion = Endpoint.new(
|
47
|
+
config_ingestion_url || "https://#{MAIN_INJECTION_HOST}/", nil
|
48
|
+
)
|
49
|
+
|
50
|
+
endpoints
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_endpoints(proxy_url, config_url, config_ingestion_url)
|
54
|
+
proxy_params = create_proxy_params(proxy_url)
|
55
|
+
|
56
|
+
# execute the tests in separate threads and wait for them
|
57
|
+
thread_control = Thread.new do
|
58
|
+
thread_main(config_url, proxy_params, MAIN_CONTROL_HOST)
|
59
|
+
end
|
60
|
+
thread_injection = Thread.new do
|
61
|
+
thread_main(config_ingestion_url, proxy_params, MAIN_INJECTION_HOST)
|
62
|
+
end
|
63
|
+
|
64
|
+
wait_for_threads(thread_control, thread_injection)
|
65
|
+
|
66
|
+
# build and return result
|
67
|
+
fallback = Endpoint.new(FALLBACK_ENDPOINT_URL, cert_store)
|
68
|
+
endpoints = ChosenEndpoints.new
|
69
|
+
endpoints.control = thread_control[:endpoint] || fallback
|
70
|
+
endpoints.ingestion = thread_injection[:endpoint] || fallback
|
71
|
+
|
72
|
+
if thread_control[:endpoint_error]
|
73
|
+
msg = AgentMessage.new(CONTROL_ERROR_KIND, thread_control[:endpoint_error])
|
74
|
+
endpoints.add_message msg
|
75
|
+
end
|
76
|
+
if thread_injection[:endpoint_error]
|
77
|
+
msg = AgentMessage.new(INGESTION_ERROR_KIND, thread_injection[:endpoint_error])
|
78
|
+
endpoints.add_message msg
|
79
|
+
end
|
80
|
+
|
81
|
+
endpoints
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def thread_main(configured_url, proxy_params, host)
|
87
|
+
res = if configured_url
|
88
|
+
Endpoint.new(configured_url, nil)
|
89
|
+
else
|
90
|
+
EndpointTesting.send(:test_with_store_variants, proxy_params, host)
|
91
|
+
end
|
92
|
+
|
93
|
+
Thread.current[:endpoint] = res
|
94
|
+
rescue StandardError => e
|
95
|
+
Thread.current[:endpoint_error] = e.message
|
96
|
+
end
|
97
|
+
|
98
|
+
def create_proxy_params(proxy_url)
|
99
|
+
return [] unless proxy_url
|
100
|
+
|
101
|
+
proxy = URI.parse(proxy_url)
|
102
|
+
|
103
|
+
return [] unless proxy.scheme == 'http'
|
104
|
+
|
105
|
+
[proxy.host, proxy.port, proxy.user, proxy.password]
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_with_store_variants(proxy_params, server_name)
|
109
|
+
# first without custom store
|
110
|
+
do_test(proxy_params, server_name, false)
|
111
|
+
rescue StandardError => _e
|
112
|
+
do_test(proxy_params, server_name, true)
|
113
|
+
end
|
114
|
+
|
115
|
+
# @param [Array] proxy_params
|
116
|
+
# @param [String] server_name
|
117
|
+
# @param [Boolean] custom_store
|
118
|
+
def do_test(proxy_params, server_name, custom_store)
|
119
|
+
http = Net::HTTP.new(server_name, 443, *proxy_params)
|
120
|
+
http.use_ssl = true
|
121
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if ENV['SQREEN_SSL_NO_VERIFY']
|
122
|
+
http.verify_callback = lambda do |preverify_ok, ctx|
|
123
|
+
unless preverify_ok
|
124
|
+
logger.warn do
|
125
|
+
"Certificate validation failure for certificate issued to " \
|
126
|
+
"#{ctx.chain[0].subject}: #{ctx.error_string}"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
preverify_ok
|
131
|
+
end
|
132
|
+
|
133
|
+
http.open_timeout = 13
|
134
|
+
http.ssl_timeout = 7
|
135
|
+
http.read_timeout = 7
|
136
|
+
http.close_on_empty_response = true
|
137
|
+
|
138
|
+
http.cert_store = cert_store if custom_store
|
139
|
+
|
140
|
+
resp = http.get('/ping')
|
141
|
+
|
142
|
+
logger.info do
|
143
|
+
"Got response from #{server_name}'s ping endpoint. " \
|
144
|
+
"Status code is #{resp.code} (custom CA store: #{custom_store})"
|
145
|
+
end
|
146
|
+
|
147
|
+
unless resp.code == '200'
|
148
|
+
raise "Response code for /ping is #{resp.code}, not 200"
|
149
|
+
end
|
150
|
+
|
151
|
+
Endpoint.new("https://#{server_name}/", http.cert_store)
|
152
|
+
rescue StandardError => e
|
153
|
+
logger.info do
|
154
|
+
"Error in request to #{server_name} " \
|
155
|
+
"(custom store: #{custom_store}): #{e.message}"
|
156
|
+
end
|
157
|
+
|
158
|
+
raise "Error in request to #{server_name}: #{e.message}"
|
159
|
+
end
|
160
|
+
|
161
|
+
def wait_for_threads(thread_control, thread_injection)
|
162
|
+
deadline = Time.now + GLOBAL_TIMEOUT
|
163
|
+
[thread_control, thread_injection].each do |thread|
|
164
|
+
rem = deadline - Time.now
|
165
|
+
rem = 0.1 if rem < 0.1
|
166
|
+
next if thread.join(rem)
|
167
|
+
logger.debug { "Timeout for thread #{thread}" }
|
168
|
+
thread.kill
|
169
|
+
thread[:endpoint_error] = "Timeout doing endpoint testing"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def cert_store
|
174
|
+
@cert_store ||= begin
|
175
|
+
cert_file = File.join(File.dirname(__FILE__), 'ca.crt')
|
176
|
+
cert_store = OpenSSL::X509::Store.new
|
177
|
+
cert_store.add_file cert_file
|
178
|
+
|
179
|
+
cert_store
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|