perimeter_x 1.2.0 → 2.2.0
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 +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +3 -0
- data/Dockerfile +12 -7
- data/Gemfile.lock +36 -30
- data/Rakefile +1 -0
- data/changelog.md +58 -0
- data/examples/app/controllers/home_controller.rb +1 -1
- data/lib/perimeter_x.rb +195 -71
- data/lib/perimeterx/configuration.rb +74 -22
- data/lib/perimeterx/internal/clients/perimeter_x_activity_client.rb +32 -6
- data/lib/perimeterx/internal/exceptions/px_config_exception.rb +6 -0
- data/lib/perimeterx/internal/first_party/px_first_party.rb +124 -0
- data/lib/perimeterx/internal/{perimeter_x_cookie_v1.rb → payload/perimeter_x_cookie_v1.rb} +1 -1
- data/lib/perimeterx/internal/{perimeter_x_cookie_v3.rb → payload/perimeter_x_cookie_v3.rb} +1 -1
- data/lib/perimeterx/internal/{perimeter_x_cookie.rb → payload/perimeter_x_payload.rb} +12 -4
- data/lib/perimeterx/internal/payload/perimeter_x_token_v1.rb +38 -0
- data/lib/perimeterx/internal/payload/perimeter_x_token_v3.rb +36 -0
- data/lib/perimeterx/internal/perimeter_x_context.rb +74 -32
- data/lib/perimeterx/internal/validators/hash_schema_validator.rb +26 -0
- data/lib/perimeterx/internal/validators/perimeter_x_cookie_validator.rb +29 -21
- data/lib/perimeterx/internal/validators/perimeter_x_s2s_validator.rb +33 -9
- data/lib/perimeterx/utils/px_constants.rb +35 -17
- data/lib/perimeterx/utils/px_http_client.rb +60 -3
- data/lib/perimeterx/utils/px_template_factory.rb +18 -8
- data/lib/perimeterx/utils/templates/block_template.mustache +175 -0
- data/lib/perimeterx/utils/templates/ratelimit.mustache +9 -0
- data/lib/perimeterx/version.rb +1 -1
- data/perimeter_x.gemspec +3 -3
- data/readme.md +115 -31
- metadata +24 -20
- data/lib/perimeterx/internal/validators/perimeter_x_captcha_validator.rb +0 -65
- data/lib/perimeterx/utils/templates/block.mustache +0 -146
- data/lib/perimeterx/utils/templates/captcha.mustache +0 -185
@@ -1,41 +1,89 @@
|
|
1
1
|
require 'perimeterx/utils/px_logger'
|
2
|
+
require 'perimeterx/utils/px_constants'
|
2
3
|
|
3
4
|
module PxModule
|
4
5
|
class PerimeterXContext
|
5
6
|
|
6
7
|
attr_accessor :context
|
7
8
|
attr_accessor :px_config
|
9
|
+
|
10
|
+
# class methods
|
11
|
+
|
12
|
+
def self.extract_ip(req, px_config)
|
13
|
+
# Get IP from header/custom function
|
14
|
+
if px_config[:ip_headers].length() > 0
|
15
|
+
px_config[:ip_headers].each do |ip_header|
|
16
|
+
if req.headers[ip_header]
|
17
|
+
return PerimeterXContext.force_utf8(req.headers[ip_header])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
elsif px_config[:ip_header_function] != nil
|
21
|
+
return px_config[:ip_header_function].call(req)
|
22
|
+
end
|
23
|
+
return req.ip
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.force_utf8(str)
|
27
|
+
return str.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
|
28
|
+
end
|
29
|
+
|
30
|
+
# instance methods
|
8
31
|
|
9
32
|
def initialize(px_config, req)
|
10
|
-
@logger = px_config[:logger]
|
11
|
-
@logger.debug(
|
33
|
+
@logger = px_config[:logger]
|
34
|
+
@logger.debug('PerimeterXContext[initialize]')
|
12
35
|
@context = Hash.new
|
13
36
|
|
14
37
|
@context[:px_cookie] = Hash.new
|
15
38
|
@context[:headers] = Hash.new
|
39
|
+
@context[:cookie_origin] = 'cookie'
|
40
|
+
@context[:made_s2s_risk_api_call] = false
|
41
|
+
@context[:first_party_enabled] = px_config[:first_party_enabled]
|
42
|
+
|
16
43
|
cookies = req.cookies
|
17
|
-
|
44
|
+
|
45
|
+
@context[:ip] = PerimeterXContext.extract_ip(req, px_config)
|
46
|
+
|
47
|
+
# Get token from header
|
48
|
+
if req.headers[PxModule::TOKEN_HEADER]
|
49
|
+
@context[:cookie_origin] = 'header'
|
50
|
+
token = PerimeterXContext.force_utf8(req.headers[PxModule::TOKEN_HEADER])
|
51
|
+
if token.match(PxModule::MOBILE_TOKEN_V3_REGEX)
|
52
|
+
@context[:px_cookie][:v3] = token[2..-1]
|
53
|
+
elsif token.match(PxModule::MOBILE_ERROR_REGEX)
|
54
|
+
@context[:mobile_error] = token
|
55
|
+
if req.headers[PxModule::ORIGINAL_TOKEN_HEADER]
|
56
|
+
token = PerimeterXContext.force_utf8(req.headers[PxModule::ORIGINAL_TOKEN_HEADER])
|
57
|
+
if token.match(PxModule::MOBILE_TOKEN_V3_REGEX)
|
58
|
+
@context[:px_cookie][:v3] = token[2..-1]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
elsif !cookies.empty? # Get cookie from jar
|
18
63
|
# Prepare hashed cookies
|
19
64
|
cookies.each do |k, v|
|
20
65
|
case k.to_s
|
21
|
-
when
|
22
|
-
@context[:px_cookie][:v3] = v
|
23
|
-
when
|
24
|
-
@context[:px_cookie][:v1] = v
|
25
|
-
when
|
26
|
-
|
66
|
+
when '_px3'
|
67
|
+
@context[:px_cookie][:v3] = PerimeterXContext.force_utf8(v)
|
68
|
+
when '_px'
|
69
|
+
@context[:px_cookie][:v1] = PerimeterXContext.force_utf8(v)
|
70
|
+
when '_pxvid'
|
71
|
+
if v.is_a?(String) && v.match(PxModule::VID_REGEX)
|
72
|
+
@context[:vid_source] = "vid_cookie"
|
73
|
+
@context[:vid] = PerimeterXContext.force_utf8(v)
|
74
|
+
end
|
27
75
|
end
|
28
76
|
end #end case
|
29
77
|
end #end empty cookies
|
30
78
|
|
31
79
|
req.headers.each do |k, v|
|
32
|
-
if (k.start_with?
|
33
|
-
header = k.to_s.gsub(
|
34
|
-
header = header.gsub(
|
35
|
-
@context[:headers][header.to_sym] = v
|
80
|
+
if (k.start_with? 'HTTP_')
|
81
|
+
header = k.to_s.gsub('HTTP_', '')
|
82
|
+
header = header.gsub('_', '-').downcase
|
83
|
+
@context[:headers][header.to_sym] = PerimeterXContext.force_utf8(v)
|
36
84
|
end
|
37
85
|
end #end headers foreach
|
38
|
-
|
86
|
+
|
39
87
|
@context[:hostname]= req.server_name
|
40
88
|
@context[:user_agent] = req.user_agent ? req.user_agent : ''
|
41
89
|
@context[:uri] = px_config[:custom_uri] ? px_config[:custom_uri].call(req) : req.fullpath
|
@@ -43,18 +91,10 @@ module PxModule
|
|
43
91
|
@context[:format] = req.format.symbol
|
44
92
|
@context[:score] = 0
|
45
93
|
|
46
|
-
if px_config.key?(:custom_user_ip)
|
47
|
-
@context[:ip] = req.headers[px_config[:custom_user_ip]]
|
48
|
-
elsif px_config.key?(:px_custom_user_ip_method)
|
49
|
-
@context[:ip] = px_config[:px_custom_user_ip_method].call(req)
|
50
|
-
else
|
51
|
-
@context[:ip] = req.ip
|
52
|
-
end
|
53
|
-
|
54
94
|
if req.server_protocol
|
55
|
-
httpVer = req.server_protocol.split(
|
95
|
+
httpVer = req.server_protocol.split('/')
|
56
96
|
if httpVer.size > 0
|
57
|
-
@context[:http_version] = httpVer[1]
|
97
|
+
@context[:http_version] = httpVer[1]
|
58
98
|
end
|
59
99
|
end
|
60
100
|
@context[:http_method] = req.method
|
@@ -65,19 +105,21 @@ module PxModule
|
|
65
105
|
sensitive_routes.each do |sensitive_route|
|
66
106
|
return true if uri.start_with? sensitive_route
|
67
107
|
end
|
68
|
-
|
108
|
+
false
|
69
109
|
end
|
70
110
|
|
71
111
|
def set_block_action_type(action)
|
72
112
|
@context[:block_action] = case action
|
73
|
-
when
|
74
|
-
|
75
|
-
when
|
76
|
-
return
|
77
|
-
when
|
78
|
-
return
|
113
|
+
when 'c'
|
114
|
+
'captcha'
|
115
|
+
when 'b'
|
116
|
+
return 'block'
|
117
|
+
when 'j'
|
118
|
+
return 'challenge'
|
119
|
+
when 'r'
|
120
|
+
return 'rate_limit'
|
79
121
|
else
|
80
|
-
return
|
122
|
+
return captcha
|
81
123
|
end
|
82
124
|
end
|
83
125
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
def validate_hash_schema(hash, schema)
|
2
|
+
hash.each do |key, value|
|
3
|
+
if schema.key?(key) && value != nil
|
4
|
+
# validate value types in hash are according to schema
|
5
|
+
if !schema[key][:types].include?(value.class)
|
6
|
+
raise PxConfigurationException.new("PerimeterX: Type of #{key} should be one of #{schema[key][:types]} but instead is #{value.class}")
|
7
|
+
end
|
8
|
+
|
9
|
+
# validate arrays elments types are according to schema
|
10
|
+
if value.class == Array
|
11
|
+
value.each do |element|
|
12
|
+
if !schema[key][:allowed_element_types].include?(element.class)
|
13
|
+
raise PxConfigurationException.new("PerimeterX: #{key} may only contain elements of the following types: #{schema[key][:allowed_element_types]} but includes element of type #{element.class}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# validate required fields exist in hash
|
21
|
+
schema.each do |key, value|
|
22
|
+
if value[:required] && hash[key].nil?
|
23
|
+
raise PxConfigurationException.new("PerimeterX: #{key} configuration is missing")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'perimeterx/utils/px_constants'
|
2
|
-
require 'perimeterx/internal/
|
3
|
-
require 'perimeterx/internal/
|
4
|
-
require 'perimeterx/internal/
|
2
|
+
require 'perimeterx/internal/payload/perimeter_x_payload'
|
3
|
+
require 'perimeterx/internal/payload/perimeter_x_token_v1'
|
4
|
+
require 'perimeterx/internal/payload/perimeter_x_token_v3'
|
5
|
+
require 'perimeterx/internal/payload/perimeter_x_cookie_v1'
|
6
|
+
require 'perimeterx/internal/payload/perimeter_x_cookie_v3'
|
5
7
|
|
6
8
|
module PxModule
|
7
9
|
class PerimeterxCookieValidator
|
@@ -16,57 +18,63 @@ module PxModule
|
|
16
18
|
|
17
19
|
def verify(px_ctx)
|
18
20
|
begin
|
19
|
-
# Case no cookie
|
20
21
|
if px_ctx.context[:px_cookie].empty?
|
21
|
-
@logger.warn("PerimeterxCookieValidator:[verify]: cookie
|
22
|
+
@logger.warn("PerimeterxCookieValidator:[verify]: no cookie")
|
22
23
|
px_ctx.context[:s2s_call_reason] = PxModule::NO_COOKIE
|
23
24
|
return false, px_ctx
|
24
25
|
end
|
25
|
-
|
26
|
+
|
26
27
|
# Deserialize cookie start
|
27
|
-
cookie =
|
28
|
-
if
|
28
|
+
cookie = PerimeterxPayload.px_cookie_factory(px_ctx, @px_config)
|
29
|
+
if !cookie.deserialize()
|
29
30
|
@logger.warn("PerimeterxCookieValidator:[verify]: invalid cookie")
|
31
|
+
px_ctx.context[:px_orig_cookie] = px_ctx.get_px_cookie
|
30
32
|
px_ctx.context[:s2s_call_reason] = PxModule::COOKIE_DECRYPTION_FAILED
|
31
33
|
return false, px_ctx
|
32
34
|
end
|
33
35
|
px_ctx.context[:decoded_cookie] = cookie.decoded_cookie
|
34
36
|
px_ctx.context[:score] = cookie.cookie_score()
|
35
37
|
px_ctx.context[:uuid] = cookie.decoded_cookie[:u]
|
36
|
-
px_ctx.context[:vid] = cookie.decoded_cookie[:v]
|
37
38
|
px_ctx.context[:block_action] = px_ctx.set_block_action_type(cookie.cookie_block_action())
|
38
39
|
px_ctx.context[:cookie_hmac] = cookie.cookie_hmac()
|
39
40
|
|
40
|
-
|
41
|
+
vid = cookie.decoded_cookie[:v]
|
42
|
+
if vid.is_a?(String) && vid.match(PxModule::VID_REGEX)
|
43
|
+
px_ctx.context[:vid_source] = "risk_cookie"
|
44
|
+
px_ctx.context[:vid] = vid
|
45
|
+
end
|
46
|
+
|
47
|
+
if cookie.expired?
|
41
48
|
@logger.warn("PerimeterxCookieValidator:[verify]: cookie expired")
|
42
49
|
px_ctx.context[:s2s_call_reason] = PxModule::EXPIRED_COOKIE
|
43
50
|
return false, px_ctx
|
44
51
|
end
|
45
52
|
|
46
|
-
if
|
53
|
+
if cookie.high_score?
|
47
54
|
@logger.warn("PerimeterxCookieValidator:[verify]: cookie high score")
|
48
|
-
px_ctx.context[:
|
55
|
+
px_ctx.context[:blocking_reason] = 'cookie_high_score'
|
49
56
|
return true, px_ctx
|
50
57
|
end
|
51
58
|
|
52
|
-
if
|
59
|
+
if !cookie.secured?
|
53
60
|
@logger.warn("PerimeterxCookieValidator:[verify]: cookie invalid hmac")
|
54
|
-
px_ctx.context[:s2s_call_reason] = PxModule::COOKIE_VALIDATION_FAILED
|
61
|
+
px_ctx.context[:s2s_call_reason] = PxModule:: COOKIE_VALIDATION_FAILED
|
62
|
+
return false, px_ctx
|
63
|
+
end
|
64
|
+
|
65
|
+
if px_ctx.context[:sensitive_route]
|
66
|
+
@logger.info("PerimeterxCookieValidator:[verify]: cookie was verified but route is sensitive")
|
67
|
+
px_ctx.context[:s2s_call_reason] = PxModule::SENSITIVE_ROUTE
|
55
68
|
return false, px_ctx
|
56
69
|
end
|
57
|
-
|
58
|
-
if (px_ctx.context[:sensitive_route])
|
59
|
-
@logger.info("PerimeterxCookieValidator:[verify]: cookie was verified but route is sensitive")
|
60
|
-
px_ctx.context[:s2s_call_reason] = PxModule::SENSITIVE_ROUTE
|
61
|
-
return false, px_ctx
|
62
|
-
end
|
63
70
|
|
64
71
|
@logger.debug("PerimeterxCookieValidator:[verify]: cookie validation passed succesfully")
|
65
72
|
|
73
|
+
px_ctx.context[:pass_reason] = 'cookie'
|
66
74
|
return true, px_ctx
|
67
75
|
rescue Exception => e
|
68
76
|
@logger.error("PerimeterxCookieValidator:[verify]: exception while verifying cookie => #{e.message}")
|
69
|
-
px_ctx.context[:px_orig_cookie] =
|
77
|
+
px_ctx.context[:px_orig_cookie] = px_ctx.context[:px_cookie]
|
70
78
|
px_ctx.context[:s2s_call_reason] = PxModule::COOKIE_DECRYPTION_FAILED
|
71
79
|
return false, px_ctx
|
72
80
|
end
|
@@ -5,11 +5,11 @@ module PxModule
|
|
5
5
|
|
6
6
|
def initialize(px_config, http_client)
|
7
7
|
super(px_config, http_client)
|
8
|
-
@logger.debug(
|
8
|
+
@logger.debug('PerimeterxS2SValidator[initialize]')
|
9
9
|
end
|
10
10
|
|
11
11
|
def send_risk_request(px_ctx)
|
12
|
-
@logger.debug(
|
12
|
+
@logger.debug('PerimeterxS2SValidator[send_risk_request]: send_risk_request')
|
13
13
|
|
14
14
|
risk_mode = PxModule::RISK_MODE_ACTIVE
|
15
15
|
if @px_config[:module_mode] == PxModule::MONITOR_MODE
|
@@ -31,6 +31,17 @@ module PxModule
|
|
31
31
|
:risk_mode => risk_mode
|
32
32
|
}
|
33
33
|
}
|
34
|
+
|
35
|
+
#Check for cookie_origin
|
36
|
+
if !px_ctx.context[:px_cookie].empty?
|
37
|
+
request_body[:additional][:cookie_origin] = px_ctx.context[:cookie_origin]
|
38
|
+
end
|
39
|
+
|
40
|
+
#Override s2s_call_reason in case of mobile error
|
41
|
+
if !px_ctx.context[:mobile_error].nil?
|
42
|
+
request_body[:additional][:s2s_call_reason] = "mobile_error_#{px_ctx.context[:mobile_error]}"
|
43
|
+
end
|
44
|
+
|
34
45
|
#Check for hmac
|
35
46
|
@logger.debug("px_ctx cookie_hmac key = #{px_ctx.context.key?(:cookie_hmac)}, value is: #{px_ctx.context[:cookie_hmac]}")
|
36
47
|
if px_ctx.context.key?(:cookie_hmac)
|
@@ -66,11 +77,19 @@ module PxModule
|
|
66
77
|
};
|
67
78
|
|
68
79
|
# Custom risk handler
|
80
|
+
risk_start = Time.now
|
69
81
|
if (risk_mode == PxModule::ACTIVE_MODE && @px_config.key?(:custom_risk_handler))
|
70
|
-
response = @px_config[:custom_risk_handler].call(PxModule::
|
82
|
+
response = @px_config[:custom_risk_handler].call(PxModule::API_V3_RISK, request_body, headers, @px_config[:api_timeout], @px_config[:api_timeout_connection])
|
71
83
|
else
|
72
|
-
response = @http_client.post(PxModule::
|
84
|
+
response = @http_client.post(PxModule::API_V3_RISK , request_body, headers, @px_config[:api_timeout], @px_config[:api_timeout_connection])
|
85
|
+
end
|
86
|
+
|
87
|
+
# Set risk_rtt
|
88
|
+
if(response)
|
89
|
+
risk_end = Time.now
|
90
|
+
px_ctx.context[:risk_rtt] = ((risk_end-risk_start)*1000).round
|
73
91
|
end
|
92
|
+
|
74
93
|
return response
|
75
94
|
end
|
76
95
|
|
@@ -78,6 +97,7 @@ module PxModule
|
|
78
97
|
@logger.debug("PerimeterxS2SValidator[verify]")
|
79
98
|
response = send_risk_request(px_ctx)
|
80
99
|
if (!response)
|
100
|
+
px_ctx.context[:pass_reason] = "s2s_timeout"
|
81
101
|
return px_ctx
|
82
102
|
end
|
83
103
|
px_ctx.context[:made_s2s_risk_api_call] = true
|
@@ -85,7 +105,7 @@ module PxModule
|
|
85
105
|
# From here response should be valid, if success or error
|
86
106
|
response_body = eval(response.body);
|
87
107
|
# When success
|
88
|
-
if (response.code == 200 && response_body.key?(:score) && response_body.key?(:action))
|
108
|
+
if (response.code == 200 && response_body.key?(:score) && response_body.key?(:action) && response_body.key?(:status) && response_body[:status] == 0 )
|
89
109
|
@logger.debug("PerimeterxS2SValidator[verify]: response ok")
|
90
110
|
score = response_body[:score]
|
91
111
|
px_ctx.context[:score] = score
|
@@ -96,14 +116,18 @@ module PxModule
|
|
96
116
|
px_ctx.context[:blocking_reason] = 'challenge'
|
97
117
|
elsif (score >= @px_config[:blocking_score])
|
98
118
|
px_ctx.context[:blocking_reason] = 's2s_high_score'
|
119
|
+
else
|
120
|
+
px_ctx.context[:pass_reason] = 's2s'
|
99
121
|
end #end challange or blocking score
|
100
122
|
end #end success response
|
101
123
|
|
102
124
|
# When error
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
px_ctx.context[:
|
125
|
+
risk_error_status = response_body && response_body.key?(:status) && response_body[:status] == -1
|
126
|
+
if(response.code != 200 || risk_error_status)
|
127
|
+
@logger.warn("PerimeterxS2SValidator[verify]: bad response, returned code #{response.code} #{risk_error_status ? "risk status: -1" : ""}")
|
128
|
+
px_ctx.context[:pass_reason] = 'request_failed'
|
129
|
+
px_ctx.context[:uuid] = (!response_body || response_body[:uuid].nil?)? "" : response_body[:uuid]
|
130
|
+
px_ctx.context[:s2s_error_msg] = !response_body || response_body[:message].nil? ? 'unknown' : response_body[:message]
|
107
131
|
end
|
108
132
|
|
109
133
|
@logger.debug("PerimeterxS2SValidator[verify]: done")
|
@@ -4,33 +4,34 @@ module PxModule
|
|
4
4
|
# Misc
|
5
5
|
MONITOR_MODE = 1
|
6
6
|
ACTIVE_MODE = 2
|
7
|
-
RISK_MODE_ACTIVE =
|
8
|
-
RISK_MODE_MONITOR =
|
7
|
+
RISK_MODE_ACTIVE = 'active_blocking'
|
8
|
+
RISK_MODE_MONITOR = 'monitor'
|
9
9
|
SDK_NAME = "RUBY SDK v#{PxModule::VERSION}"
|
10
10
|
|
11
11
|
# Routes
|
12
|
-
API_V1_S2S =
|
13
|
-
|
14
|
-
API_V2_RISK = "/api/v2/risk"
|
12
|
+
API_V1_S2S = '/api/v1/collector/s2s'
|
13
|
+
API_V3_RISK = '/api/v3/risk'
|
15
14
|
|
16
15
|
# Activity Types
|
17
|
-
BLOCK_ACTIVITY =
|
18
|
-
PAGE_REQUESTED_ACTIVITY =
|
16
|
+
BLOCK_ACTIVITY = 'block'
|
17
|
+
PAGE_REQUESTED_ACTIVITY = 'page_requested'
|
19
18
|
|
20
19
|
# PxContext
|
21
|
-
NO_COOKIE =
|
22
|
-
INVALID_COOKIE =
|
23
|
-
EXPIRED_COOKIE =
|
24
|
-
COOKIE_HIGH_SCORE =
|
25
|
-
COOKIE_VALIDATION_FAILED =
|
26
|
-
COOKIE_DECRYPTION_FAILED =
|
27
|
-
SENSITIVE_ROUTE =
|
20
|
+
NO_COOKIE = 'no_cookie'
|
21
|
+
INVALID_COOKIE = 'invalid_cookie'
|
22
|
+
EXPIRED_COOKIE = 'cookie_expired'
|
23
|
+
COOKIE_HIGH_SCORE = 'cookie_high_score'
|
24
|
+
COOKIE_VALIDATION_FAILED = 'cookie_validation_failed'
|
25
|
+
COOKIE_DECRYPTION_FAILED = 'cookie_decryption_failed'
|
26
|
+
SENSITIVE_ROUTE = 'sensitive_route'
|
28
27
|
|
29
28
|
# Templates
|
30
|
-
|
31
|
-
|
29
|
+
CHALLENGE_TEMPLATE = 'block_template'
|
30
|
+
TEMPLATE_EXT = '.mustache'
|
31
|
+
RATELIMIT_TEMPLATE = 'ratelimit'
|
32
32
|
|
33
|
-
|
33
|
+
|
34
|
+
# Template Props
|
34
35
|
PROP_REF_ID = :refId
|
35
36
|
PROP_APP_ID = :appId
|
36
37
|
PROP_VID = :vid
|
@@ -39,7 +40,24 @@ module PxModule
|
|
39
40
|
PROP_CUSTOM_LOGO = :customLogo
|
40
41
|
PROP_CSS_REF = :cssRef
|
41
42
|
PROP_JS_REF = :jsRef
|
43
|
+
PROP_BLOCK_SCRIPT = :blockScript
|
44
|
+
PROP_JS_CLIENT_SRC = :jsClientSrc
|
45
|
+
PROP_HOST_URL = :hostUrl
|
46
|
+
PROP_FIRST_PARTY_ENABLED = :firstPartyEnabled
|
47
|
+
|
48
|
+
# Hosts
|
49
|
+
CLIENT_HOST = 'client.perimeterx.net'
|
50
|
+
CAPTCHA_HOST = 'captcha.px-cdn.net'
|
42
51
|
|
43
52
|
VISIBLE = 'visible'
|
44
53
|
HIDDEN = 'hidden'
|
54
|
+
|
55
|
+
# Mobile SDK
|
56
|
+
TOKEN_HEADER = 'X-PX-AUTHORIZATION'
|
57
|
+
ORIGINAL_TOKEN_HEADER = 'X-PX-ORIGINAL-TOKEN'
|
58
|
+
|
59
|
+
# Regular Expressions
|
60
|
+
VID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/
|
61
|
+
MOBILE_TOKEN_V3_REGEX = /\A3:(.*)\z/
|
62
|
+
MOBILE_ERROR_REGEX = /\A[0-9]\z/
|
45
63
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'perimeterx/utils/px_logger'
|
2
2
|
require 'typhoeus'
|
3
3
|
require 'concurrent'
|
4
|
+
require 'net/http'
|
4
5
|
|
5
6
|
module PxModule
|
6
7
|
class PxHttpClient
|
@@ -12,10 +13,10 @@ module PxModule
|
|
12
13
|
def initialize(px_config)
|
13
14
|
@px_config = px_config
|
14
15
|
@logger = px_config[:logger]
|
15
|
-
@logger.debug("PxHttpClient[initialize]: HTTP client is being initilized with base_uri: #{px_config[:
|
16
|
+
@logger.debug("PxHttpClient[initialize]: HTTP client is being initilized with base_uri: #{px_config[:backend_url]}")
|
16
17
|
end
|
17
18
|
|
18
|
-
# Runs a POST
|
19
|
+
# Runs a POST command to Perimeter X servers
|
19
20
|
# Params:
|
20
21
|
# +path+:: string containing uri
|
21
22
|
# +body+:: hash object, containing the request body, must be converted to json format
|
@@ -28,7 +29,7 @@ module PxModule
|
|
28
29
|
begin
|
29
30
|
@logger.debug("PxHttpClient[post]: posting to #{path} headers {#{headers.to_json()}} body: {#{body.to_json()}} ")
|
30
31
|
response = Typhoeus.post(
|
31
|
-
"#{px_config[:
|
32
|
+
"#{px_config[:backend_url]}#{path}",
|
32
33
|
headers: headers,
|
33
34
|
body: body.to_json,
|
34
35
|
timeout: api_timeout,
|
@@ -45,5 +46,61 @@ module PxModule
|
|
45
46
|
return response
|
46
47
|
end
|
47
48
|
|
49
|
+
|
50
|
+
def post_xhr(url, body, headers)
|
51
|
+
s = Time.now
|
52
|
+
begin
|
53
|
+
@logger.debug("PxHttpClient[post]: sending xhr post request to #{url} with headers {#{headers.to_json()}}")
|
54
|
+
|
55
|
+
#set url
|
56
|
+
uri = URI(url)
|
57
|
+
req = Net::HTTP::Post.new(uri)
|
58
|
+
|
59
|
+
# set body
|
60
|
+
req.body=body
|
61
|
+
|
62
|
+
# set headers
|
63
|
+
headers.each do |key, value|
|
64
|
+
req[key] = value
|
65
|
+
end
|
66
|
+
|
67
|
+
# send request
|
68
|
+
response = Net::HTTP.start(uri.hostname, uri.port) {|http|
|
69
|
+
http.request(req)
|
70
|
+
}
|
71
|
+
|
72
|
+
ensure
|
73
|
+
e = Time.now
|
74
|
+
@logger.debug("PxHttpClient[get]: runtime: #{(e-s) * 1000.0}")
|
75
|
+
end
|
76
|
+
return response
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def get(url, headers)
|
81
|
+
s = Time.now
|
82
|
+
begin
|
83
|
+
@logger.debug("PxHttpClient[get]: sending get request to #{url} with headers {#{headers.to_json()}}")
|
84
|
+
|
85
|
+
#set url
|
86
|
+
uri = URI(url)
|
87
|
+
req = Net::HTTP::Get.new(uri)
|
88
|
+
|
89
|
+
# set headers
|
90
|
+
headers.each do |key, value|
|
91
|
+
req[key] = value
|
92
|
+
end
|
93
|
+
|
94
|
+
# send request
|
95
|
+
response = Net::HTTP.start(uri.hostname, uri.port) {|http|
|
96
|
+
http.request(req)
|
97
|
+
}
|
98
|
+
|
99
|
+
ensure
|
100
|
+
e = Time.now
|
101
|
+
@logger.debug("PxHttpClient[get]: runtime: #{(e-s) * 1000.0}")
|
102
|
+
end
|
103
|
+
return response
|
104
|
+
end
|
48
105
|
end
|
49
106
|
end
|