perimeter_x 1.0.3 → 1.0.4.pre.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -3
- data/Dockerfile +2 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +2 -44
- data/LICENSE.txt +12 -9
- data/Rakefile +2 -9
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/home_controller.rb.dist +23 -0
- data/lib/perimeter_x.rb +33 -109
- data/lib/perimeterx/configuration.rb +17 -24
- data/lib/perimeterx/internal/perimeter_x_context.rb +58 -66
- data/lib/perimeterx/internal/perimeter_x_risk_client.rb +29 -0
- data/lib/perimeterx/internal/perimeter_x_s2s_validator.rb +68 -0
- data/lib/perimeterx/utils/px_http_client.rb +26 -47
- data/lib/perimeterx/utils/px_logger.rb +6 -12
- data/lib/perimeterx/version.rb +2 -2
- data/perimeter_x.gemspec +1 -6
- data/readme.md +34 -216
- metadata +10 -89
- data/examples/app/controllers/home_controller.rb +0 -9
- data/examples/app/views/home/index.html.erb.dist +0 -20
- data/examples/config/initializers/perimeterx.rb.dist +0 -8
- data/lib/perimeterx/internal/clients/perimeter_x_activity_client.rb +0 -92
- data/lib/perimeterx/internal/clients/perimeter_x_risk_client.rb +0 -28
- data/lib/perimeterx/internal/exceptions/px_cookie_decryption_exception.rb +0 -5
- data/lib/perimeterx/internal/perimeter_x_cookie.rb +0 -140
- data/lib/perimeterx/internal/perimeter_x_cookie_v1.rb +0 -42
- data/lib/perimeterx/internal/perimeter_x_cookie_v3.rb +0 -37
- data/lib/perimeterx/internal/validators/perimeter_x_captcha_validator.rb +0 -65
- data/lib/perimeterx/internal/validators/perimeter_x_cookie_validator.rb +0 -69
- data/lib/perimeterx/internal/validators/perimeter_x_s2s_validator.rb +0 -110
- data/lib/perimeterx/utils/px_constants.rb +0 -44
- data/lib/perimeterx/utils/px_template_factory.rb +0 -31
- data/lib/perimeterx/utils/templates/block.mustache +0 -146
- data/lib/perimeterx/utils/templates/captcha.mustache +0 -185
- /data/examples/{config/routes.rb → routes.rb} +0 -0
@@ -1,92 +0,0 @@
|
|
1
|
-
require 'perimeterx/internal/clients/perimeter_x_risk_client'
|
2
|
-
|
3
|
-
module PxModule
|
4
|
-
class PerimeterxActivitiesClient < PerimeterxRiskClient
|
5
|
-
|
6
|
-
attr_accessor :activities
|
7
|
-
|
8
|
-
def initialize(px_config, http_client)
|
9
|
-
super(px_config, http_client)
|
10
|
-
@logger.debug("PerimeterxActivitiesClients[initialize]")
|
11
|
-
@activities = [];
|
12
|
-
end
|
13
|
-
|
14
|
-
def send_to_perimeterx(activity_type, px_ctx, details = [])
|
15
|
-
@logger.debug("PerimeterxActivitiesClients[send_to_perimeterx]")
|
16
|
-
@logger.debug("PerimeterxActivitiesClients[send_to_perimeterx]: new activity #{activity_type} logged")
|
17
|
-
|
18
|
-
if (@px_config.key?(:additional_activity_handler))
|
19
|
-
@px_config[:additional_activity_handler].call(activity_type, px_ctx, details)
|
20
|
-
end
|
21
|
-
|
22
|
-
details[:module_version] = @px_config[:sdk_name]
|
23
|
-
px_data = {
|
24
|
-
:type => activity_type,
|
25
|
-
:headers => format_headers(px_ctx),
|
26
|
-
:timestamp => (Time.now.to_f*1000).floor,
|
27
|
-
:socket_ip => px_ctx.context[:ip],
|
28
|
-
:px_app_id => @px_config[:app_id],
|
29
|
-
:url => px_ctx.context[:full_url],
|
30
|
-
:details => details,
|
31
|
-
}
|
32
|
-
|
33
|
-
if (px_ctx.context.key?(:vid))
|
34
|
-
@logger.debug("PerimeterxActivitiesClients[send_to_perimeterx]: found vid in ctx")
|
35
|
-
px_data[:vid] = px_ctx.context[:vid]
|
36
|
-
end
|
37
|
-
|
38
|
-
# Prepare request
|
39
|
-
headers = {
|
40
|
-
"Authorization" => "Bearer #{@px_config[:auth_token]}" ,
|
41
|
-
"Content-Type" => "application/json"
|
42
|
-
};
|
43
|
-
|
44
|
-
@activities.push(px_data)
|
45
|
-
if (@activities.size == @px_config[:max_buffer_len])
|
46
|
-
@logger.debug("PerimeterxActivitiesClients[send_to_perimeterx]: max buffer length reached, sending activities")
|
47
|
-
@http_client.async_post(PxModule::API_V1_S2S, @activities, headers)
|
48
|
-
|
49
|
-
@activities.clear
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def send_block_activity(px_ctx)
|
54
|
-
@logger.debug("PerimeterxActivitiesClients[send_block_activity]")
|
55
|
-
if (!@px_config[:send_page_acitivites])
|
56
|
-
@logger.debug("PerimeterxActivitiesClients[send_block_activity]: sending activites is disabled")
|
57
|
-
return
|
58
|
-
end
|
59
|
-
|
60
|
-
details = {
|
61
|
-
:block_uuid => px_ctx.context[:uuid],
|
62
|
-
:block_score => px_ctx.context[:score],
|
63
|
-
:block_reason => px_ctx.context[:block_reason]
|
64
|
-
}
|
65
|
-
|
66
|
-
send_to_perimeterx(PxModule::BLOCK_ACTIVITY, px_ctx, details)
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
def send_page_requested_activity(px_ctx)
|
71
|
-
@logger.debug("PerimeterxActivitiesClients[send_page_requested_activity]")
|
72
|
-
if (!@px_config[:send_page_acitivites])
|
73
|
-
return
|
74
|
-
end
|
75
|
-
|
76
|
-
details = {
|
77
|
-
:http_version => px_ctx.context[:http_version],
|
78
|
-
:http_method => px_ctx.context[:http_method]
|
79
|
-
}
|
80
|
-
|
81
|
-
if (px_ctx.context.key?(:decoded_cookie))
|
82
|
-
details[:px_cookie] = px_ctx.context[:decoded_cookie]
|
83
|
-
end
|
84
|
-
|
85
|
-
if (px_ctx.context.key?(:cookie_hmac))
|
86
|
-
details[:px_cookie_hmac] = px_ctx.context[:cookie_hmac]
|
87
|
-
end
|
88
|
-
|
89
|
-
send_to_perimeterx(PxModule::PAGE_REQUESTED_ACTIVITY, px_ctx, details)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'perimeterx/utils/px_logger'
|
2
|
-
|
3
|
-
module PxModule
|
4
|
-
class PerimeterxRiskClient
|
5
|
-
attr_accessor :px_config
|
6
|
-
attr_accessor :http_client
|
7
|
-
|
8
|
-
def initialize(px_config, http_client)
|
9
|
-
@px_config = px_config
|
10
|
-
@http_client = http_client;
|
11
|
-
@logger = px_config[:logger]
|
12
|
-
end
|
13
|
-
|
14
|
-
def format_headers(px_ctx)
|
15
|
-
@logger.debug("PerimeterxRiskClient[format_headers]")
|
16
|
-
formated_headers = []
|
17
|
-
px_ctx.context[:headers].each do |k,v|
|
18
|
-
if (!@px_config[:sensitive_headers].include? k.to_s)
|
19
|
-
formated_headers.push({
|
20
|
-
:name => k.to_s,
|
21
|
-
:value => v
|
22
|
-
})
|
23
|
-
end #end if
|
24
|
-
end #end forech
|
25
|
-
return formated_headers
|
26
|
-
end #end method
|
27
|
-
end #end class
|
28
|
-
end
|
@@ -1,140 +0,0 @@
|
|
1
|
-
require 'active_support/security_utils'
|
2
|
-
require 'base64'
|
3
|
-
require 'openssl'
|
4
|
-
require 'perimeterx/internal/exceptions/px_cookie_decryption_exception'
|
5
|
-
|
6
|
-
module PxModule
|
7
|
-
class PerimeterxCookie
|
8
|
-
attr_accessor :px_cookie, :px_config, :px_ctx, :cookie_secret, :decoded_cookie
|
9
|
-
|
10
|
-
def initialize(px_config)
|
11
|
-
@px_config = px_config
|
12
|
-
@logger = px_config[:logger]
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.px_cookie_factory(px_ctx, px_config)
|
16
|
-
if (px_ctx.context[:px_cookie].key?(:v3))
|
17
|
-
return PerimeterxCookieV3.new(px_config, px_ctx)
|
18
|
-
end
|
19
|
-
return PerimeterxCookieV1.new(px_config, px_ctx)
|
20
|
-
end
|
21
|
-
|
22
|
-
def cookie_score
|
23
|
-
#abstract, must be implemented
|
24
|
-
raise Exception.new("Unimplemented method")
|
25
|
-
end
|
26
|
-
|
27
|
-
def cookie_hmac
|
28
|
-
#abstract, must be implemented
|
29
|
-
raise Exception.new("Unimplemented method")
|
30
|
-
end
|
31
|
-
|
32
|
-
def valid_format?(cookie)
|
33
|
-
#abstract, must be implemented
|
34
|
-
raise Exception.new("Unimplemented method")
|
35
|
-
end
|
36
|
-
|
37
|
-
def cookie_block_action
|
38
|
-
#abstract, must be implemented
|
39
|
-
raise Exception.new("Unimplemented method")
|
40
|
-
end
|
41
|
-
|
42
|
-
def secured?
|
43
|
-
#abstract, must be implemented
|
44
|
-
raise Exception.new("Unimplemented method")
|
45
|
-
end
|
46
|
-
|
47
|
-
def is_valid?
|
48
|
-
return deserialize && !expired? && secured?
|
49
|
-
end
|
50
|
-
|
51
|
-
def cookie_time
|
52
|
-
return @decoded_cookie[:t]
|
53
|
-
end
|
54
|
-
|
55
|
-
def cookie_uuid
|
56
|
-
return @decoded_cookie[:u]
|
57
|
-
end
|
58
|
-
|
59
|
-
def cookie_vid
|
60
|
-
return @decoded_cookie[:v]
|
61
|
-
end
|
62
|
-
|
63
|
-
def high_score?
|
64
|
-
return cookie_score >= @px_config[:blocking_score]
|
65
|
-
end
|
66
|
-
|
67
|
-
def expired?
|
68
|
-
return cookie_time < (Time.now.to_f*1000).floor
|
69
|
-
end
|
70
|
-
|
71
|
-
|
72
|
-
def deserialize
|
73
|
-
if (!@decoded_cookie.nil?)
|
74
|
-
return true
|
75
|
-
end
|
76
|
-
|
77
|
-
# Decode or decrypt, depends on configuration
|
78
|
-
if (@px_config[:encryption_enabled])
|
79
|
-
cookie = decrypt(@px_cookie)
|
80
|
-
else
|
81
|
-
cookie = decode(@px_cookie)
|
82
|
-
end
|
83
|
-
|
84
|
-
if (cookie.nil?)
|
85
|
-
return false
|
86
|
-
end
|
87
|
-
|
88
|
-
if (!valid_format?(cookie))
|
89
|
-
return false
|
90
|
-
end
|
91
|
-
|
92
|
-
@decoded_cookie = cookie
|
93
|
-
|
94
|
-
return true
|
95
|
-
end
|
96
|
-
|
97
|
-
|
98
|
-
def decrypt(px_cookie)
|
99
|
-
begin
|
100
|
-
if (px_cookie.nil?)
|
101
|
-
return
|
102
|
-
end
|
103
|
-
px_cookie = px_cookie.gsub(' ', '+')
|
104
|
-
salt, iterations, cipher_text = px_cookie.split(':')
|
105
|
-
iterations = iterations.to_i
|
106
|
-
salt = Base64.decode64(salt)
|
107
|
-
cipher_text = Base64.decode64(cipher_text)
|
108
|
-
digest = OpenSSL::Digest::SHA256.new
|
109
|
-
value = OpenSSL::PKCS5.pbkdf2_hmac(@px_config[:cookie_key], salt, iterations, 48, digest)
|
110
|
-
key = value[0..31]
|
111
|
-
iv = value[32..-1]
|
112
|
-
cipher = OpenSSL::Cipher::AES256.new(:CBC)
|
113
|
-
cipher.decrypt
|
114
|
-
cipher.key = key
|
115
|
-
cipher.iv = iv
|
116
|
-
plaintext = cipher.update(cipher_text) + cipher.final
|
117
|
-
|
118
|
-
return eval(plaintext)
|
119
|
-
rescue Exception => e
|
120
|
-
@logger.debug("PerimeterxCookie[decrypt]: Cookie decrypt fail #{e.message}")
|
121
|
-
raise PxCookieDecryptionException.new("Cookie decrypt fail => #{e.message}");
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def decode(px_cookie)
|
126
|
-
return eval(Base64.decode64(px_cookie))
|
127
|
-
end
|
128
|
-
|
129
|
-
|
130
|
-
def hmac_valid?(hmac_str, cookie_hmac)
|
131
|
-
hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, @cookie_secret, hmac_str)
|
132
|
-
# ref: https://thisdata.com/blog/timing-attacks-against-string-comparison/
|
133
|
-
password_correct = ActiveSupport::SecurityUtils.secure_compare(
|
134
|
-
::Digest::SHA256.hexdigest(cookie_hmac),
|
135
|
-
::Digest::SHA256.hexdigest(hmac)
|
136
|
-
)
|
137
|
-
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
module PxModule
|
2
|
-
class PerimeterxCookieV1 < PerimeterxCookie
|
3
|
-
|
4
|
-
attr_accessor :px_config, :px_ctx
|
5
|
-
|
6
|
-
def initialize(px_config, px_ctx)
|
7
|
-
super(px_config)
|
8
|
-
@px_ctx = px_ctx
|
9
|
-
@px_cookie = px_ctx.get_px_cookie
|
10
|
-
@cookie_secret = px_config[:cookie_key]
|
11
|
-
@logger.debug("PerimeterxCookieV1[initialize]")
|
12
|
-
end
|
13
|
-
|
14
|
-
def cookie_score
|
15
|
-
return @decoded_cookie[:s][:b]
|
16
|
-
end
|
17
|
-
|
18
|
-
def cookie_hmac
|
19
|
-
return @decoded_cookie[:h]
|
20
|
-
end
|
21
|
-
|
22
|
-
def valid_format?(cookie)
|
23
|
-
return cookie.key?(:t) && cookie.key?(:s) && cookie[:s].key?(:b) && cookie.key?(:s) && cookie.key?(:v) && cookie.key?(:h)
|
24
|
-
end
|
25
|
-
|
26
|
-
def cookie_block_action
|
27
|
-
return 'c'
|
28
|
-
end
|
29
|
-
|
30
|
-
def secured?
|
31
|
-
base_hmac_str = "#{cookie_time}#{@decoded_cookie[:s][:a]}#{cookie_score}#{cookie_uuid}#{cookie_vid}"
|
32
|
-
|
33
|
-
hmac_str_withip = "#{base_hmac_str}#{@px_ctx.context[:ip]}#{@px_ctx.context[:user_agent]}"
|
34
|
-
|
35
|
-
hmac_str_withoutip = "#{base_hmac_str}#{@px_ctx.context[:user_agent]}"
|
36
|
-
|
37
|
-
return (hmac_valid?(hmac_str_withoutip, cookie_hmac) || hmac_valid?(hmac_str_withip, cookie_hmac))
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
module PxModule
|
2
|
-
class PerimeterxCookieV3 < PerimeterxCookie
|
3
|
-
|
4
|
-
attr_accessor :px_config, :px_ctx, :cookie_hash
|
5
|
-
|
6
|
-
def initialize(px_config, px_ctx)
|
7
|
-
super(px_config)
|
8
|
-
hash, cookie = px_ctx.get_px_cookie().split(':', 2)
|
9
|
-
@px_cookie = cookie
|
10
|
-
@cookie_hash = hash
|
11
|
-
@px_ctx = px_ctx
|
12
|
-
@cookie_secret = px_config[:cookie_key]
|
13
|
-
@logger.debug("PerimeterxCookieV3[initialize]")
|
14
|
-
end
|
15
|
-
|
16
|
-
def cookie_score
|
17
|
-
return @decoded_cookie[:s]
|
18
|
-
end
|
19
|
-
|
20
|
-
def cookie_hmac
|
21
|
-
return @cookie_hash
|
22
|
-
end
|
23
|
-
|
24
|
-
def valid_format?(cookie)
|
25
|
-
return cookie.key?(:t) && cookie.key?(:s) && cookie.key?(:u) && cookie.key?(:u) && cookie.key?(:a)
|
26
|
-
end
|
27
|
-
|
28
|
-
def cookie_block_action
|
29
|
-
@decoded_cookie[:a]
|
30
|
-
end
|
31
|
-
|
32
|
-
def secured?
|
33
|
-
hmac_string = "#{@px_cookie}#{@px_ctx.context[:user_agent]}"
|
34
|
-
return hmac_valid?(hmac_string, cookie_hmac)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,65 +0,0 @@
|
|
1
|
-
require 'perimeterx/internal/clients/perimeter_x_risk_client'
|
2
|
-
|
3
|
-
module PxModule
|
4
|
-
class PerimeterxCaptchaValidator < PerimeterxRiskClient
|
5
|
-
|
6
|
-
def initialize(px_config, http_client)
|
7
|
-
super(px_config, http_client)
|
8
|
-
end
|
9
|
-
|
10
|
-
def send_captcha_request(vid, uuid, captcha, px_ctx)
|
11
|
-
|
12
|
-
request_body = {
|
13
|
-
:request => {
|
14
|
-
:ip => px_ctx.context[:ip],
|
15
|
-
:headers => format_headers(px_ctx),
|
16
|
-
:uri => px_ctx.context[:uri]
|
17
|
-
},
|
18
|
-
:pxCaptcha => captcha,
|
19
|
-
:vid => vid,
|
20
|
-
:uuid => uuid,
|
21
|
-
:hostname => px_ctx.context[:hostname]
|
22
|
-
}
|
23
|
-
|
24
|
-
# Prepare request
|
25
|
-
headers = {
|
26
|
-
"Authorization" => "Bearer #{@px_config[:auth_token]}" ,
|
27
|
-
"Content-Type" => "application/json"
|
28
|
-
};
|
29
|
-
|
30
|
-
return @http_client.post(PxModule::API_V1_CAPTCHA, request_body, headers, @px_config[:api_timeout])
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
def verify(px_ctx)
|
35
|
-
captcha_validated = false
|
36
|
-
begin
|
37
|
-
if(!px_ctx.context.key?(:px_captcha))
|
38
|
-
return captcha_validated, px_ctx
|
39
|
-
end
|
40
|
-
captcha, vid, uuid = px_ctx.context[:px_captcha].split(':', 3)
|
41
|
-
if captcha.nil? || vid.nil? || uuid.nil?
|
42
|
-
return captcha_validated, px_ctx
|
43
|
-
end
|
44
|
-
|
45
|
-
px_ctx.context[:vid] = vid
|
46
|
-
px_ctx.context[:uuid] = uuid
|
47
|
-
response = send_captcha_request(vid, uuid, captcha, px_ctx)
|
48
|
-
|
49
|
-
if (response.status_code == 200)
|
50
|
-
response_body = eval(response.body)
|
51
|
-
if ( response_body[:status] == 0 )
|
52
|
-
captcha_validated = true
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
return captcha_validated, px_ctx
|
57
|
-
|
58
|
-
rescue Exception => e
|
59
|
-
@logger.error("PerimeterxCaptchaValidator[verify]: failed, returning false")
|
60
|
-
return captcha_validated, px_ctx
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
end
|
@@ -1,69 +0,0 @@
|
|
1
|
-
require 'perimeterx/utils/px_constants'
|
2
|
-
require 'perimeterx/internal/perimeter_x_cookie'
|
3
|
-
require 'perimeterx/internal/perimeter_x_cookie_v1'
|
4
|
-
require 'perimeterx/internal/perimeter_x_cookie_v3'
|
5
|
-
|
6
|
-
module PxModule
|
7
|
-
class PerimeterxCookieValidator
|
8
|
-
|
9
|
-
attr_accessor :px_config
|
10
|
-
|
11
|
-
def initialize(px_config)
|
12
|
-
@px_config = px_config
|
13
|
-
@logger = px_config[:logger]
|
14
|
-
end
|
15
|
-
|
16
|
-
|
17
|
-
def verify(px_ctx)
|
18
|
-
begin
|
19
|
-
# Case no cookie
|
20
|
-
if px_ctx.context[:px_cookie].empty?
|
21
|
-
@logger.warn("PerimeterxCookieValidator:[verify]: cookie not found")
|
22
|
-
px_ctx.context[:s2s_call_reason] = PxModule::NO_COOKIE
|
23
|
-
return false, px_ctx
|
24
|
-
end
|
25
|
-
|
26
|
-
# Deserialize cookie start
|
27
|
-
cookie = PerimeterxCookie.px_cookie_factory(px_ctx, @px_config)
|
28
|
-
if (!cookie.deserialize())
|
29
|
-
@logger.warn("PerimeterxCookieValidator:[verify]: invalid cookie")
|
30
|
-
px_ctx.context[:s2s_call_reason] = PxModule::NO_COOKIE
|
31
|
-
return false, px_ctx
|
32
|
-
end
|
33
|
-
px_ctx.context[:decoded_cookie] = cookie.decoded_cookie
|
34
|
-
px_ctx.context[:score] = cookie.cookie_score()
|
35
|
-
px_ctx.context[:uuid] = cookie.decoded_cookie[:u]
|
36
|
-
px_ctx.context[:vid] = cookie.decoded_cookie[:v]
|
37
|
-
px_ctx.context[:block_action] = px_ctx.set_block_action_type(cookie.cookie_block_action())
|
38
|
-
px_ctx.context[:cookie_hmac] = cookie.cookie_hmac()
|
39
|
-
|
40
|
-
if (cookie.expired?)
|
41
|
-
@logger.warn("PerimeterxCookieValidator:[verify]: cookie expired")
|
42
|
-
px_ctx.context[:s2s_call_reason] = PxModule::EXPIRED_COOKIE
|
43
|
-
return false, px_ctx
|
44
|
-
end
|
45
|
-
|
46
|
-
if (cookie.high_score?)
|
47
|
-
@logger.warn("PerimeterxCookieValidator:[verify]: cookie high score")
|
48
|
-
px_ctx.context[:s2s_call_reason] = PxModule::COOKIE_HIGH_SCORE
|
49
|
-
return false, px_ctx
|
50
|
-
end
|
51
|
-
|
52
|
-
if (!cookie.secured?)
|
53
|
-
@logger.warn("PerimeterxCookieValidator:[verify]: cookie invalid hmac")
|
54
|
-
px_ctx.context[:s2s_call_reason] = PxModule::COOKIE_VALIDATION_FAILED
|
55
|
-
return false, px_ctx
|
56
|
-
end
|
57
|
-
|
58
|
-
@logger.debug("PerimeterxCookieValidator:[verify]: cookie validation passed succesfully")
|
59
|
-
|
60
|
-
return true, px_ctx
|
61
|
-
rescue Exception => e
|
62
|
-
@logger.error("PerimeterxCookieValidator:[verify]: exception while verifying cookie => #{e.message}")
|
63
|
-
px_ctx.context[:s2s_call_reason] = PxModule::COOKIE_DECRYPTION_FAILED
|
64
|
-
return false, px_ctx
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
69
|
-
end
|
@@ -1,110 +0,0 @@
|
|
1
|
-
require 'perimeterx/internal/clients/perimeter_x_risk_client'
|
2
|
-
|
3
|
-
module PxModule
|
4
|
-
class PerimeterxS2SValidator < PerimeterxRiskClient
|
5
|
-
|
6
|
-
def initialize(px_config, http_client)
|
7
|
-
super(px_config, http_client)
|
8
|
-
@logger.debug("PerimeterxS2SValidator[initialize]")
|
9
|
-
end
|
10
|
-
|
11
|
-
def send_risk_request(px_ctx)
|
12
|
-
@logger.debug("PerimeterxS2SValidator[send_risk_request]: send_risk_request")
|
13
|
-
|
14
|
-
risk_mode = PxModule::RISK_MODE_ACTIVE
|
15
|
-
if @px_config[:module_mode] == PxModule::MONITOR_MODE
|
16
|
-
risk_mode = PxModule::RISK_MODE_MONITOR
|
17
|
-
end
|
18
|
-
|
19
|
-
request_body = {
|
20
|
-
'request' => {
|
21
|
-
'ip' => px_ctx.context[:ip],
|
22
|
-
'headers' => format_headers(px_ctx),
|
23
|
-
'uri' => px_ctx.context[:uri],
|
24
|
-
'url' => px_ctx.context[:full_url]
|
25
|
-
},
|
26
|
-
'additional' => {
|
27
|
-
's2s_call_reason' => px_ctx.context[:s2s_call_reason],
|
28
|
-
'module_version' => @px_config[:sdk_name],
|
29
|
-
'http_method' => px_ctx.context[:http_method],
|
30
|
-
'http_version' => px_ctx.context[:http_version],
|
31
|
-
'risk_mode' => risk_mode
|
32
|
-
}
|
33
|
-
}
|
34
|
-
#Check for hmac
|
35
|
-
if px_ctx.context.key?(:cookie_hmac)
|
36
|
-
request_body[:additional][:px_cookie_hmac] = px_ctx.context[:cookie_hmac]
|
37
|
-
end
|
38
|
-
|
39
|
-
|
40
|
-
#Check for VID
|
41
|
-
if px_ctx.context.key?(:vid)
|
42
|
-
request_body[:vid] = px_ctx.context[:vid]
|
43
|
-
end
|
44
|
-
|
45
|
-
#Check for uuid
|
46
|
-
if px_ctx.context.key?(:uuid)
|
47
|
-
request_body[:uuid] = px_ctx.context[:uuid]
|
48
|
-
end
|
49
|
-
|
50
|
-
#S2S Call reason
|
51
|
-
decode_cookie_reasons = ['cookie_expired', 'cookie_validation_failed']
|
52
|
-
if decode_cookie_reasons.include? (px_ctx.context[:s2s_call_reason])
|
53
|
-
if (px_ctx.context.key?(:decoded_cookie))
|
54
|
-
request_body[:additional][:px_cookie] = px_ctx.context[:decoded_cookie]
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# Prepare request
|
59
|
-
headers = {
|
60
|
-
"Authorization" => "Bearer #{@px_config[:auth_token]}" ,
|
61
|
-
"Content-Type" => "application/json"
|
62
|
-
};
|
63
|
-
|
64
|
-
# Custom risk handler
|
65
|
-
if (risk_mode == PxModule::ACTIVE_MODE && @px_config.key?(:custom_risk_handler))
|
66
|
-
response = @px_config[:custom_risk_handler].call(PxModule::API_V2_RISK, request_body, headers, @px_config[:api_timeout])
|
67
|
-
else
|
68
|
-
response = @http_client.post(PxModule::API_V2_RISK , request_body, headers)
|
69
|
-
end
|
70
|
-
return response
|
71
|
-
end
|
72
|
-
|
73
|
-
def verify(px_ctx)
|
74
|
-
@logger.debug("PerimeterxS2SValidator[verify]")
|
75
|
-
response = send_risk_request(px_ctx)
|
76
|
-
if (!response)
|
77
|
-
return px_ctx
|
78
|
-
end
|
79
|
-
px_ctx.context[:made_s2s_risk_api_call] = true
|
80
|
-
|
81
|
-
# From here response should be valid, if success or error
|
82
|
-
response_body = eval(response.content);
|
83
|
-
# When success
|
84
|
-
if (response.status == 200 && response_body.key?(:score) && response_body.key?(:action))
|
85
|
-
@logger.debug("PerimeterxS2SValidator[verify]: response ok")
|
86
|
-
score = response_body[:score]
|
87
|
-
px_ctx.context[:score] = score
|
88
|
-
px_ctx.context[:uuid] = response_body[:uuid]
|
89
|
-
px_ctx.context[:block_action] = px_ctx.set_block_action_type(response_body[:action])
|
90
|
-
if (response_body[:action] == 'j' && response_body.key?(:action_data) && response_body[:action_data].key?(:body))
|
91
|
-
px_ctx.context[:block_action_data] = response_body[:action_data][:body]
|
92
|
-
px_ctx.context[:blocking_reason] = 'challenge'
|
93
|
-
elsif (score >= @px_config[:blocking_score])
|
94
|
-
px_ctx.context[:blocking_reason] = 's2s_high_score'
|
95
|
-
end #end challange or blocking score
|
96
|
-
end #end success response
|
97
|
-
|
98
|
-
# When error
|
99
|
-
if(response.status != 200)
|
100
|
-
@logger.warn("PerimeterxS2SValidator[verify]: bad response, return code #{response.code}")
|
101
|
-
px_ctx.context[:uuid] = ""
|
102
|
-
px_ctx.context[:s2s_error_msg] = response_body[:message]
|
103
|
-
end
|
104
|
-
|
105
|
-
@logger.debug("PerimeterxS2SValidator[verify]: done")
|
106
|
-
return px_ctx
|
107
|
-
end #end method
|
108
|
-
|
109
|
-
end
|
110
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'perimeterx/version'
|
2
|
-
|
3
|
-
module PxModule
|
4
|
-
# Misc
|
5
|
-
MONITOR_MODE = 1
|
6
|
-
ACTIVE_MODE = 2
|
7
|
-
RISK_MODE_ACTIVE = "active_blocking"
|
8
|
-
RISK_MODE_MONITOR = "monitor"
|
9
|
-
SDK_NAME = "RUBY SDK v#{PxModule::VERSION}"
|
10
|
-
|
11
|
-
# Routes
|
12
|
-
API_V1_S2S = "/api/v1/collector/s2s"
|
13
|
-
API_V1_CAPTCHA = "/api/v1/risk/captcha"
|
14
|
-
API_V2_RISK = "/api/v2/risk"
|
15
|
-
|
16
|
-
# Activity Types
|
17
|
-
BLOCK_ACTIVITY = "block"
|
18
|
-
PAGE_REQUESTED_ACTIVITY = "page_requested"
|
19
|
-
|
20
|
-
# PxContext
|
21
|
-
NO_COOKIE = "no_cookie"
|
22
|
-
INVALID_COOKIE = "invalid cookie"
|
23
|
-
EXPIRED_COOKIE = "cookie_expired"
|
24
|
-
COOKIE_HIGH_SCORE = "cookie_high_score"
|
25
|
-
COOKIE_VALIDATION_FAILED = "cookie_validation_failed"
|
26
|
-
COOKIE_DECRYPTION_FAILED = "cookie_decryption_failed"
|
27
|
-
|
28
|
-
# Templates
|
29
|
-
BLOCK_TEMPLATE = "block.mustache"
|
30
|
-
CAPTCHA_TEMPLATE = "captcha.mustache"
|
31
|
-
|
32
|
-
# Tempalte Props
|
33
|
-
PROP_REF_ID = :refId
|
34
|
-
PROP_APP_ID = :appId
|
35
|
-
PROP_VID = :vid
|
36
|
-
PROP_UUID = :uuid
|
37
|
-
PROP_LOGO_VISIBILITY = :logoVisibility
|
38
|
-
PROP_CUSTOM_LOGO = :customLogo
|
39
|
-
PROP_CSS_REF = :cssRef
|
40
|
-
PROP_JS_REF = :jsRef
|
41
|
-
|
42
|
-
VISIBLE = 'visible'
|
43
|
-
HIDDEN = 'hidden'
|
44
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'mustache'
|
2
|
-
require 'perimeterx/utils/px_constants'
|
3
|
-
module PxModule
|
4
|
-
module PxTemplateFactory
|
5
|
-
|
6
|
-
def self.get_template(px_ctx, px_config)
|
7
|
-
logger = px_config[:logger]
|
8
|
-
if (px_config[:challenge_enabled] && px_ctx.context[:block_action] == "challenge")
|
9
|
-
logger.debug("PxTemplateFactory[get_template]: px challange triggered")
|
10
|
-
return px_ctx.context[:block_action_data].html_safe
|
11
|
-
end
|
12
|
-
|
13
|
-
logger.debug("PxTemplateFactory[get_template]: rendering template")
|
14
|
-
template_type = px_config[:captcha_enabled] ? PxModule::CAPTCHA_TEMPLATE : BLOCK_TEMPLATE
|
15
|
-
|
16
|
-
Mustache.template_file = "#{File.dirname(__FILE__) }/templates/#{template_type}"
|
17
|
-
view = Mustache.new
|
18
|
-
|
19
|
-
view[PxModule::PROP_APP_ID] = px_config[:app_id]
|
20
|
-
view[PxModule::PROP_REF_ID] = px_ctx.context[:uuid]
|
21
|
-
view[PxModule::PROP_VID] = px_ctx.context[:vid]
|
22
|
-
view[PxModule::PROP_UUID] = px_ctx.context[:uuid]
|
23
|
-
view[PxModule::PROP_CUSTOM_LOGO] = px_config[:custom_logo]
|
24
|
-
view[PxModule::PROP_CSS_REF] = px_config[:css_ref]
|
25
|
-
view[PxModule::PROP_JS_REF] = px_config[:js_ref]
|
26
|
-
view[PxModule::PROP_LOGO_VISIBILITY] = px_config[:custom_logo] ? PxModule::VISIBLE : PxModule::HIDDEN
|
27
|
-
|
28
|
-
return view.render.html_safe
|
29
|
-
end
|
30
|
-
end #end class
|
31
|
-
end #end module
|