perimeter_x 1.0.4.pre.alpha → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/Dockerfile +4 -2
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +44 -2
  6. data/LICENSE.txt +9 -12
  7. data/Rakefile +9 -2
  8. data/changelog.md +12 -0
  9. data/examples/app/controllers/home_controller.rb +9 -0
  10. data/examples/app/views/home/index.html.erb.dist +20 -0
  11. data/examples/config/initializers/perimeterx.rb.dist +8 -0
  12. data/lib/perimeter_x.rb +109 -33
  13. data/lib/perimeterx/configuration.rb +24 -17
  14. data/lib/perimeterx/internal/clients/perimeter_x_activity_client.rb +92 -0
  15. data/lib/perimeterx/internal/clients/perimeter_x_risk_client.rb +28 -0
  16. data/lib/perimeterx/internal/exceptions/px_cookie_decryption_exception.rb +5 -0
  17. data/lib/perimeterx/internal/perimeter_x_context.rb +66 -58
  18. data/lib/perimeterx/internal/perimeter_x_cookie.rb +140 -0
  19. data/lib/perimeterx/internal/perimeter_x_cookie_v1.rb +42 -0
  20. data/lib/perimeterx/internal/perimeter_x_cookie_v3.rb +37 -0
  21. data/lib/perimeterx/internal/validators/perimeter_x_captcha_validator.rb +65 -0
  22. data/lib/perimeterx/internal/validators/perimeter_x_cookie_validator.rb +70 -0
  23. data/lib/perimeterx/internal/validators/perimeter_x_s2s_validator.rb +114 -0
  24. data/lib/perimeterx/utils/px_constants.rb +44 -0
  25. data/lib/perimeterx/utils/px_http_client.rb +47 -26
  26. data/lib/perimeterx/utils/px_logger.rb +12 -6
  27. data/lib/perimeterx/utils/px_template_factory.rb +31 -0
  28. data/lib/perimeterx/utils/templates/block.mustache +146 -0
  29. data/lib/perimeterx/utils/templates/captcha.mustache +185 -0
  30. data/lib/perimeterx/version.rb +2 -2
  31. data/perimeter_x.gemspec +6 -1
  32. data/readme.md +216 -34
  33. metadata +89 -10
  34. data/bin/console +0 -14
  35. data/bin/setup +0 -8
  36. data/examples/home_controller.rb.dist +0 -23
  37. data/lib/perimeterx/internal/perimeter_x_risk_client.rb +0 -29
  38. data/lib/perimeterx/internal/perimeter_x_s2s_validator.rb +0 -68
  39. /data/examples/{routes.rb → config/routes.rb} +0 -0
@@ -1,74 +1,82 @@
1
1
  require 'perimeterx/utils/px_logger'
2
2
 
3
- class PerimeterXContext
4
- L = PxLogger.instance
3
+ module PxModule
4
+ class PerimeterXContext
5
5
 
6
- attr_accessor :context
7
- attr_accessor :px_config
6
+ attr_accessor :context
7
+ attr_accessor :px_config
8
8
 
9
- def initialize(px_config, req)
10
- L.info("PerimeterXContext: initialize")
11
- @context = Hash.new
9
+ def initialize(px_config, req)
10
+ @logger = px_config[:logger];
11
+ @logger.debug("PerimeterXContext[initialize] ")
12
+ @context = Hash.new
12
13
 
13
- @context[:px_cookies] = Hash.new
14
- @context[:headers] = Hash.new
15
- cookies = req.cookies
16
- if (!cookies.empty?)
17
- # Prepare hashed cookies
18
- cookies.each do |k,v|
19
- case k
20
- when"_px3"
21
- @context[:px_cookies] = v
22
- when "_px"
23
- @context[:px_cookies] = v
24
- when "_pxCaptcha"
25
- @context[:px_captcha] = v
14
+ @context[:px_cookie] = Hash.new
15
+ @context[:headers] = Hash.new
16
+ cookies = req.cookies
17
+ if (!cookies.empty?)
18
+ # Prepare hashed cookies
19
+ cookies.each do |k, v|
20
+ case k.to_s
21
+ when "_px3"
22
+ @context[:px_cookie][:v3] = v
23
+ when "_px"
24
+ @context[:px_cookie][:v1] = v
25
+ when "_pxCaptcha"
26
+ @context[:px_captcha] = v
27
+ end
28
+ end #end case
29
+ end #end empty cookies
30
+
31
+ req.headers.each do |k, v|
32
+ if (k.start_with? "HTTP_")
33
+ header = k.to_s.gsub("HTTP_", "")
34
+ header = header.gsub("_", "-").downcase
35
+ @context[:headers][header.to_sym] = v
26
36
  end
27
- end #end case
28
- end#end empty cookies
37
+ end #end headers foreach
38
+
39
+ @context[:hostname]= req.server_name
40
+ @context[:user_agent] = req.user_agent ? req.user_agent : ''
41
+ @context[:uri] = px_config[:custom_uri] ? px_config[:custom_uri].call(req) : req.headers['REQUEST_URI']
42
+ @context[:full_url] = req.original_url
43
+ @context[:score] = 0
29
44
 
30
- @context[:start_time] = DateTime.now.strftime('%Q')
31
- req.headers.each do |k,v|
32
- if(k.start_with? "HTTP_")
33
- header = k.to_s.gsub("HTTP_","")
34
- header = header.gsub("_","-").downcase
35
- @context[:headers][header.to_sym] = v
45
+ if px_config.key?(:custom_user_ip)
46
+ @context[:ip] = req.headers[px_config[:custom_user_ip]]
47
+ elsif px_config.key?(:px_custom_user_ip_method)
48
+ @context[:ip] = px_config[:px_custom_user_ip_method].call(req)
49
+ else
50
+ @context[:ip] = req.ip
36
51
  end
37
- end#end headers foreach
38
52
 
39
- @context[:hostname]= req.headers['HTTP_HOST']
40
- @context[:user_agent] = req.headers['HTTP_USER_AGENT'] ? req.headers['HTTP_USER_AGENT'] : ''
41
- @context[:uri] = px_config[:custom_uri] ? px_config[:custom_uri] : req.headers['REQUEST_URI']
42
- @context[:full_url] = self_url(req)
43
- @context[:score] = 0
53
+ if req.server_protocol
54
+ httpVer = req.server_protocol.split("/")
55
+ if httpVer.size > 0
56
+ @context[:http_version] = httpVer[1];
57
+ end
58
+ end
59
+ @context[:http_method] = req.method
44
60
 
45
- if px_config.key?('custom_user_ip')
46
- @context[:ip] = px_config['custom_user_ip']
47
- elsif px_config.key?('px_custom_user_ip_method')
48
- puts "px_custom_user_ip_method triggered"
49
- @context[:ip] = px_config['px_custom_user_ip_method'].call(req)
50
- else
51
- @context[:ip] = req.headers['REMOTE_ADDR'];
52
- end
61
+ end #end init
53
62
 
54
- if req.headers['SERVER_PROTOCOL']
55
- httpVer = req.headers['SERVER_PROTOCOL'].split("/")
56
- if httpVer.size > 0
57
- @context[:http_version] = httpVer[1];
63
+ def set_block_action_type(action)
64
+ @context[:block_action] = case action
65
+ when "c"
66
+ "captcha"
67
+ when "b"
68
+ return "block"
69
+ when "j"
70
+ return "challenge"
71
+ else
72
+ return "captcha"
58
73
  end
59
74
  end
60
- @context[:http_method] = req.headers['REQUEST_METHOD'];
61
75
 
62
- end #end init
76
+ def get_px_cookie
77
+ cookie = @context[:px_cookie].key?(:v3) ? @context[:px_cookie][:v3] : @context[:px_cookie][:v1]
78
+ return cookie.tr(' ','+') if !cookie.nil?
79
+ end
63
80
 
64
- def self_url(req)
65
- s = req.headers.key?('HTTPS') && req.headers['HTTPS'] == "on" ? "s" : "" #check if HTTPS or HTTP
66
- l = req.headers['SERVER_PROTOCOL'].downcase #get protocol and downcase it
67
- protocol = "#{l[0,l.index('/')]}#{s}#{l[(l.index('/') ),l.size]}" #concat http{s}:/x.y
68
- port = (req.headers["SERVER_PORT"] != "80") ? ":#{req.headers["SERVER_PORT"]}" : ""
69
- return "#{l}://#{req.headers['HTTP_HOST']}#{@uri}" #concant str
70
81
  end
71
-
72
- private :self_url
73
-
74
- end #end class
82
+ end
@@ -0,0 +1,140 @@
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
@@ -0,0 +1,42 @@
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
@@ -0,0 +1,37 @@
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
@@ -0,0 +1,65 @@
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
@@ -0,0 +1,70 @@
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::COOKIE_DECRYPTION_FAILED
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 true, 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[:px_orig_cookie] = cookie.px_cookie
64
+ px_ctx.context[:s2s_call_reason] = PxModule::COOKIE_DECRYPTION_FAILED
65
+ return false, px_ctx
66
+ end
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,114 @@
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
+ @logger.debug("px_ctx cookie_hmac key = #{px_ctx.context.key?(:cookie_hmac)}, value is: #{px_ctx.context[:cookie_hmac]}")
36
+ if px_ctx.context.key?(:cookie_hmac)
37
+ request_body[:additional][:px_cookie_hmac] = px_ctx.context[:cookie_hmac]
38
+ end
39
+
40
+
41
+ #Check for VID
42
+ if px_ctx.context.key?(:vid)
43
+ request_body[:vid] = px_ctx.context[:vid]
44
+ end
45
+
46
+ #Check for uuid
47
+ if px_ctx.context.key?(:uuid)
48
+ request_body[:uuid] = px_ctx.context[:uuid]
49
+ end
50
+
51
+ #S2S Call reason
52
+ decode_cookie_reasons = [PxModule::EXPIRED_COOKIE, PxModule::COOKIE_VALIDATION_FAILED]
53
+ if ( px_ctx.context[:s2s_call_reason] == PxModule::COOKIE_DECRYPTION_FAILED )
54
+ @logger.debug("PerimeterxS2SValidator[send_risk_request]: attaching px_orig_cookie to request")
55
+ request_body[:additional][:px_orig_cookie] = px_ctx.context[:px_orig_cookie]
56
+ elsif decode_cookie_reasons.include? (px_ctx.context[:s2s_call_reason])
57
+ if (px_ctx.context.key?(:decoded_cookie))
58
+ request_body[:additional][:px_cookie] = px_ctx.context[:decoded_cookie]
59
+ end
60
+ end
61
+
62
+ # Prepare request
63
+ headers = {
64
+ "Authorization" => "Bearer #{@px_config[:auth_token]}" ,
65
+ "Content-Type" => "application/json"
66
+ };
67
+
68
+ # Custom risk handler
69
+ if (risk_mode == PxModule::ACTIVE_MODE && @px_config.key?(:custom_risk_handler))
70
+ response = @px_config[:custom_risk_handler].call(PxModule::API_V2_RISK, request_body, headers, @px_config[:api_timeout])
71
+ else
72
+ response = @http_client.post(PxModule::API_V2_RISK , request_body, headers)
73
+ end
74
+ return response
75
+ end
76
+
77
+ def verify(px_ctx)
78
+ @logger.debug("PerimeterxS2SValidator[verify]")
79
+ response = send_risk_request(px_ctx)
80
+ if (!response)
81
+ return px_ctx
82
+ end
83
+ px_ctx.context[:made_s2s_risk_api_call] = true
84
+
85
+ # From here response should be valid, if success or error
86
+ response_body = eval(response.content);
87
+ # When success
88
+ if (response.status == 200 && response_body.key?(:score) && response_body.key?(:action))
89
+ @logger.debug("PerimeterxS2SValidator[verify]: response ok")
90
+ score = response_body[:score]
91
+ px_ctx.context[:score] = score
92
+ px_ctx.context[:uuid] = response_body[:uuid]
93
+ px_ctx.context[:block_action] = px_ctx.set_block_action_type(response_body[:action])
94
+ if (response_body[:action] == 'j' && response_body.key?(:action_data) && response_body[:action_data].key?(:body))
95
+ px_ctx.context[:block_action_data] = response_body[:action_data][:body]
96
+ px_ctx.context[:blocking_reason] = 'challenge'
97
+ elsif (score >= @px_config[:blocking_score])
98
+ px_ctx.context[:blocking_reason] = 's2s_high_score'
99
+ end #end challange or blocking score
100
+ end #end success response
101
+
102
+ # When error
103
+ if(response.status != 200)
104
+ @logger.warn("PerimeterxS2SValidator[verify]: bad response, return code #{response.code}")
105
+ px_ctx.context[:uuid] = ""
106
+ px_ctx.context[:s2s_error_msg] = response_body[:message]
107
+ end
108
+
109
+ @logger.debug("PerimeterxS2SValidator[verify]: done")
110
+ return px_ctx
111
+ end #end method
112
+
113
+ end
114
+ end
@@ -0,0 +1,44 @@
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