perimeter_x 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/changelog.md +4 -0
- data/lib/perimeter_x.rb +52 -10
- data/lib/perimeterx/configuration.rb +5 -2
- data/lib/perimeterx/internal/first_party/px_first_party.rb +124 -0
- data/lib/perimeterx/internal/perimeter_x_context.rb +32 -25
- data/lib/perimeterx/utils/px_constants.rb +2 -2
- data/lib/perimeterx/utils/px_http_client.rb +57 -0
- data/lib/perimeterx/utils/px_template_factory.rb +2 -2
- data/lib/perimeterx/version.rb +1 -1
- data/readme.md +22 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 475e2577bfe9b12bb7edbe3286fb4f1861a9c508791f38b0196dea0f493f355e
|
4
|
+
data.tar.gz: b0c61698741743a62ad0a7c9fb67dc6d5ed9f9b78c01d08b764cb1297ee37c98
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3bae8b3e45c8ee8aba86a56ed977158adec12bccfa2542e1a4e54344b6b6fb0503182585816c1b55640bd49ea4d6323831e93ad6c8d3335703e33d695df362ba
|
7
|
+
data.tar.gz: d7a64faa2f03fd4bc467cdea545a2f530001431f37281c2a9561dd83c28c00006fe827e8cd510560fbbbd1a69d382993ae513edd214a18a277bcca57dd561fdc
|
data/changelog.md
CHANGED
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
7
7
|
|
8
|
+
## [2.2.0] - 2020-09-15
|
9
|
+
### Added
|
10
|
+
- First Party
|
11
|
+
|
8
12
|
## [2.1.0] - 2020-09-01
|
9
13
|
### Added
|
10
14
|
- Added option to set a different px configuration on each request
|
data/lib/perimeter_x.rb
CHANGED
@@ -12,13 +12,23 @@ require 'perimeterx/internal/clients/perimeter_x_activity_client'
|
|
12
12
|
require 'perimeterx/internal/validators/perimeter_x_s2s_validator'
|
13
13
|
require 'perimeterx/internal/validators/perimeter_x_cookie_validator'
|
14
14
|
require 'perimeterx/internal/exceptions/px_config_exception'
|
15
|
+
require 'perimeterx/internal/first_party/px_first_party'
|
15
16
|
|
16
17
|
module PxModule
|
17
18
|
# Module expose API
|
18
19
|
def px_verify_request(request_config={})
|
19
20
|
begin
|
20
21
|
px_instance = PerimeterX.new(request_config)
|
21
|
-
|
22
|
+
req = ActionDispatch::Request.new(request.env)
|
23
|
+
|
24
|
+
# handle first party requests
|
25
|
+
if px_instance.first_party.is_first_party_request(req)
|
26
|
+
render_first_party_response(req, px_instance)
|
27
|
+
return true
|
28
|
+
end
|
29
|
+
|
30
|
+
# verify request
|
31
|
+
px_ctx = px_instance.verify(req)
|
22
32
|
px_config = px_instance.px_config
|
23
33
|
|
24
34
|
msg_title = 'PxModule[px_verify_request]'
|
@@ -46,12 +56,21 @@ module PxModule
|
|
46
56
|
end
|
47
57
|
|
48
58
|
is_mobile = px_ctx.context[:cookie_origin] == 'header' ? '1' : '0'
|
49
|
-
action = px_ctx.context[:block_action][0,1]
|
59
|
+
action = px_ctx.context[:block_action][0,1]
|
50
60
|
|
51
|
-
|
61
|
+
if px_config[:first_party_enabled]
|
62
|
+
px_template_object = {
|
63
|
+
js_client_src: "/#{px_config[:app_id][2..-1]}/init.js",
|
64
|
+
block_script: "/#{px_config[:app_id][2..-1]}/captcha/#{px_config[:app_id]}/captcha.js?a=#{action}&u=#{px_ctx.context[:uuid]}&v=#{px_ctx.context[:vid]}&m=#{is_mobile}",
|
65
|
+
host_url: "/#{px_config[:app_id][2..-1]}/xhr"
|
66
|
+
}
|
67
|
+
else
|
68
|
+
px_template_object = {
|
69
|
+
js_client_src: "//#{PxModule::CLIENT_HOST}/#{px_config[:app_id]}/main.min.js",
|
52
70
|
block_script: "//#{PxModule::CAPTCHA_HOST}/#{px_config[:app_id]}/captcha.js?a=#{action}&u=#{px_ctx.context[:uuid]}&v=#{px_ctx.context[:vid]}&m=#{is_mobile}",
|
53
|
-
|
54
|
-
|
71
|
+
host_url: "https://collector-#{px_config[:app_id]}.perimeterx.net"
|
72
|
+
}
|
73
|
+
end
|
55
74
|
|
56
75
|
html = PxTemplateFactory.get_template(px_ctx, px_config, px_template_object)
|
57
76
|
|
@@ -68,7 +87,7 @@ module PxModule
|
|
68
87
|
hash_json = {
|
69
88
|
:appId => px_config[:app_id],
|
70
89
|
:jsClientSrc => px_template_object[:js_client_src],
|
71
|
-
:firstPartyEnabled =>
|
90
|
+
:firstPartyEnabled => px_ctx.context[:first_party_enabled],
|
72
91
|
:uuid => px_ctx.context[:uuid],
|
73
92
|
:vid => px_ctx.context[:vid],
|
74
93
|
:hostUrl => "https://collector-#{px_config[:app_id]}.perimeterx.net",
|
@@ -110,6 +129,29 @@ module PxModule
|
|
110
129
|
end
|
111
130
|
end
|
112
131
|
|
132
|
+
def render_first_party_response(req, px_instance)
|
133
|
+
fp = px_instance.first_party
|
134
|
+
px_config = px_instance.px_config
|
135
|
+
|
136
|
+
if px_config[:first_party_enabled]
|
137
|
+
# first party enabled - proxy response
|
138
|
+
fp_response = fp.send_first_party_request(req)
|
139
|
+
response.status = fp_response.code
|
140
|
+
fp_response.to_hash.each do |header_name, header_value_arr|
|
141
|
+
if header_name!="content-length"
|
142
|
+
response.headers[header_name] = header_value_arr[0]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
res_type = fp.get_response_content_type(req)
|
146
|
+
render res_type => fp_response.body
|
147
|
+
else
|
148
|
+
# first party disabled - return empty response
|
149
|
+
response.status = 200
|
150
|
+
res_type = fp.get_response_content_type(req)
|
151
|
+
render res_type => ""
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
113
155
|
def self.configure(basic_config)
|
114
156
|
PerimeterX.set_basic_config(basic_config)
|
115
157
|
end
|
@@ -119,6 +161,7 @@ module PxModule
|
|
119
161
|
class PerimeterX
|
120
162
|
|
121
163
|
attr_reader :px_config
|
164
|
+
attr_reader :first_party
|
122
165
|
attr_accessor :px_http_client
|
123
166
|
attr_accessor :px_activity_client
|
124
167
|
|
@@ -128,7 +171,7 @@ module PxModule
|
|
128
171
|
end
|
129
172
|
|
130
173
|
#Instance Methods
|
131
|
-
def verify(
|
174
|
+
def verify(req)
|
132
175
|
begin
|
133
176
|
|
134
177
|
# check module_enabled
|
@@ -137,13 +180,11 @@ module PxModule
|
|
137
180
|
@logger.warn('Module is disabled')
|
138
181
|
return nil
|
139
182
|
end
|
140
|
-
|
141
|
-
req = ActionDispatch::Request.new(env)
|
142
183
|
|
143
184
|
# filter whitelist routes
|
144
185
|
url_path = URI.parse(req.original_url).path
|
145
186
|
if url_path && !url_path.empty?
|
146
|
-
if check_whitelist_routes(px_config[:whitelist_routes], url_path)
|
187
|
+
if check_whitelist_routes(px_config[:whitelist_routes], url_path)
|
147
188
|
@logger.debug("PerimeterX[pxVerify]: whitelist route: #{url_path}")
|
148
189
|
return nil
|
149
190
|
end
|
@@ -176,6 +217,7 @@ module PxModule
|
|
176
217
|
@px_http_client = PxHttpClient.new(@px_config)
|
177
218
|
|
178
219
|
@px_activity_client = PerimeterxActivitiesClient.new(@px_config, @px_http_client)
|
220
|
+
@first_party = FirstPartyManager.new(@px_config, @px_http_client, @logger)
|
179
221
|
|
180
222
|
@px_cookie_validator = PerimeterxCookieValidator.new(@px_config)
|
181
223
|
@px_s2s_validator = PerimeterxS2SValidator.new(@px_config, @px_http_client)
|
@@ -30,7 +30,8 @@ module PxModule
|
|
30
30
|
:ip_headers => [],
|
31
31
|
:ip_header_function => nil,
|
32
32
|
:bypass_monitor_header => nil,
|
33
|
-
:risk_cookie_max_iterations => 5000
|
33
|
+
:risk_cookie_max_iterations => 5000,
|
34
|
+
:first_party_enabled => true
|
34
35
|
}
|
35
36
|
|
36
37
|
CONFIG_SCHEMA = {
|
@@ -60,7 +61,9 @@ module PxModule
|
|
60
61
|
:custom_logo => {types: [String], required: false},
|
61
62
|
:css_ref => {types: [String], required: false},
|
62
63
|
:js_ref => {types: [String], required: false},
|
63
|
-
:custom_uri => {types: [Proc], required: false}
|
64
|
+
:custom_uri => {types: [Proc], required: false},
|
65
|
+
:first_party_enabled => {types: [FalseClass, TrueClass], required: false}
|
66
|
+
|
64
67
|
}
|
65
68
|
|
66
69
|
def self.set_basic_config(basic_config)
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'perimeterx/internal/perimeter_x_context'
|
2
|
+
module PxModule
|
3
|
+
class FirstPartyManager
|
4
|
+
def initialize(px_config, px_http_client, logger)
|
5
|
+
@px_config = px_config
|
6
|
+
@app_id = px_config[:app_id]
|
7
|
+
@px_http_client = px_http_client
|
8
|
+
@logger = logger
|
9
|
+
@from = [
|
10
|
+
"/#{@app_id[2..-1]}/init.js",
|
11
|
+
"/#{@app_id[2..-1]}/captcha",
|
12
|
+
"/#{@app_id[2..-1]}/xhr"
|
13
|
+
]
|
14
|
+
end
|
15
|
+
|
16
|
+
def send_first_party_request(req)
|
17
|
+
uri = URI.parse(req.original_url)
|
18
|
+
url_path = uri.path
|
19
|
+
|
20
|
+
headers = extract_headers(req)
|
21
|
+
headers["x-px-first-party"] = "1"
|
22
|
+
headers["x-px-enforcer-true-ip"] = PerimeterXContext.extract_ip(req, @px_config)
|
23
|
+
|
24
|
+
if url_path.start_with?(@from[0])
|
25
|
+
return get_client(req, uri, headers)
|
26
|
+
elsif url_path.start_with?(@from[1])
|
27
|
+
return get_captcha(req, uri, headers)
|
28
|
+
elsif url_path.start_with?(@from[2])
|
29
|
+
return send_xhr(req, uri, headers)
|
30
|
+
else
|
31
|
+
return nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_client(req, uri, headers)
|
36
|
+
@logger.debug("FirstPartyManager[get_client]")
|
37
|
+
|
38
|
+
# define host
|
39
|
+
headers["host"] = PxModule::CLIENT_HOST
|
40
|
+
|
41
|
+
# define request url
|
42
|
+
url = "#{uri.scheme}://#{PxModule::CLIENT_HOST}/#{@app_id}/main.min.js"
|
43
|
+
|
44
|
+
# send request
|
45
|
+
return @px_http_client.get(url, headers)
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_captcha(req, uri, headers)
|
49
|
+
@logger.debug("FirstPartyManager[get_captcha]")
|
50
|
+
|
51
|
+
# define host
|
52
|
+
headers["host"] = PxModule::CAPTCHA_HOST
|
53
|
+
|
54
|
+
# define request url
|
55
|
+
path_and_query = uri.request_uri
|
56
|
+
uri_suffix = path_and_query.sub "/#{@app_id[2..-1]}/captcha", ""
|
57
|
+
url = "#{uri.scheme}://#{PxModule::CAPTCHA_HOST}#{uri_suffix}"
|
58
|
+
|
59
|
+
# send request
|
60
|
+
return @px_http_client.get(url, headers)
|
61
|
+
end
|
62
|
+
|
63
|
+
def send_xhr(req, uri, headers)
|
64
|
+
@logger.debug("FirstPartyManager[send_xhr]")
|
65
|
+
|
66
|
+
# handle vid cookies
|
67
|
+
if !req.cookies.nil?
|
68
|
+
if req.cookies.key?("_pxvid")
|
69
|
+
vid = PerimeterXContext.force_utf8(req.cookies["_pxvid"])
|
70
|
+
if headers.key?('cookie')
|
71
|
+
headers['cookie'] += "; pxvid=#{vid}";
|
72
|
+
else
|
73
|
+
headers['cookie'] = "pxvid=#{vid}";
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# define host
|
79
|
+
headers["host"] = "collector-#{@app_id.downcase}.perimeterx.net"
|
80
|
+
|
81
|
+
# define request url
|
82
|
+
path_and_query = uri.request_uri
|
83
|
+
path_suffix = path_and_query.sub "/#{@app_id[2..-1]}/xhr", ""
|
84
|
+
url = "#{uri.scheme}://collector-#{@app_id.downcase}.perimeterx.net#{path_suffix}"
|
85
|
+
|
86
|
+
# send request
|
87
|
+
return @px_http_client.post_xhr(url, req.body.string, headers)
|
88
|
+
end
|
89
|
+
|
90
|
+
def extract_headers(req)
|
91
|
+
headers = Hash.new
|
92
|
+
req.headers.each do |k, v|
|
93
|
+
if (k.start_with? 'HTTP_') && (!@px_config[:sensitive_headers].include? k)
|
94
|
+
header = k.to_s.gsub('HTTP_', '')
|
95
|
+
header = header.gsub('_', '-').downcase
|
96
|
+
headers[header] = PerimeterXContext.force_utf8(v)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
return headers
|
100
|
+
end
|
101
|
+
|
102
|
+
# -1 - not first party request
|
103
|
+
# 0 - /init.js
|
104
|
+
# 1 - /captcha
|
105
|
+
# 2 - /xhr
|
106
|
+
def get_first_party_request_type(req)
|
107
|
+
url_path = URI.parse(req.original_url).path
|
108
|
+
@from.each_with_index do |val,index|
|
109
|
+
if url_path.start_with?(val)
|
110
|
+
return index
|
111
|
+
end
|
112
|
+
end
|
113
|
+
return -1
|
114
|
+
end
|
115
|
+
|
116
|
+
def is_first_party_request(req)
|
117
|
+
return get_first_party_request_type(req) != -1
|
118
|
+
end
|
119
|
+
|
120
|
+
def get_response_content_type(req)
|
121
|
+
return get_first_party_request_type(req) == 2 ? :json : :js
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -6,6 +6,28 @@ module PxModule
|
|
6
6
|
|
7
7
|
attr_accessor :context
|
8
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
|
9
31
|
|
10
32
|
def initialize(px_config, req)
|
11
33
|
@logger = px_config[:logger]
|
@@ -16,33 +38,22 @@ module PxModule
|
|
16
38
|
@context[:headers] = Hash.new
|
17
39
|
@context[:cookie_origin] = 'cookie'
|
18
40
|
@context[:made_s2s_risk_api_call] = false
|
41
|
+
@context[:first_party_enabled] = px_config[:first_party_enabled]
|
42
|
+
|
19
43
|
cookies = req.cookies
|
20
44
|
|
21
|
-
|
22
|
-
if px_config[:ip_headers].length() > 0
|
23
|
-
px_config[:ip_headers].each do |ip_header|
|
24
|
-
if req.headers[ip_header]
|
25
|
-
@context[:ip] = force_utf8(req.headers[ip_header])
|
26
|
-
end
|
27
|
-
end
|
28
|
-
elsif px_config[:ip_header_function] != nil
|
29
|
-
@context[:ip] = px_config[:ip_header_function].call(req)
|
30
|
-
end
|
31
|
-
|
32
|
-
if @context[:ip] == nil
|
33
|
-
@context[:ip] = req.ip
|
34
|
-
end
|
45
|
+
@context[:ip] = PerimeterXContext.extract_ip(req, px_config)
|
35
46
|
|
36
47
|
# Get token from header
|
37
48
|
if req.headers[PxModule::TOKEN_HEADER]
|
38
49
|
@context[:cookie_origin] = 'header'
|
39
|
-
token = force_utf8(req.headers[PxModule::TOKEN_HEADER])
|
50
|
+
token = PerimeterXContext.force_utf8(req.headers[PxModule::TOKEN_HEADER])
|
40
51
|
if token.match(PxModule::MOBILE_TOKEN_V3_REGEX)
|
41
52
|
@context[:px_cookie][:v3] = token[2..-1]
|
42
53
|
elsif token.match(PxModule::MOBILE_ERROR_REGEX)
|
43
54
|
@context[:mobile_error] = token
|
44
55
|
if req.headers[PxModule::ORIGINAL_TOKEN_HEADER]
|
45
|
-
token = force_utf8(req.headers[PxModule::ORIGINAL_TOKEN_HEADER])
|
56
|
+
token = PerimeterXContext.force_utf8(req.headers[PxModule::ORIGINAL_TOKEN_HEADER])
|
46
57
|
if token.match(PxModule::MOBILE_TOKEN_V3_REGEX)
|
47
58
|
@context[:px_cookie][:v3] = token[2..-1]
|
48
59
|
end
|
@@ -53,13 +64,13 @@ module PxModule
|
|
53
64
|
cookies.each do |k, v|
|
54
65
|
case k.to_s
|
55
66
|
when '_px3'
|
56
|
-
@context[:px_cookie][:v3] = force_utf8(v)
|
67
|
+
@context[:px_cookie][:v3] = PerimeterXContext.force_utf8(v)
|
57
68
|
when '_px'
|
58
|
-
@context[:px_cookie][:v1] = force_utf8(v)
|
69
|
+
@context[:px_cookie][:v1] = PerimeterXContext.force_utf8(v)
|
59
70
|
when '_pxvid'
|
60
71
|
if v.is_a?(String) && v.match(PxModule::VID_REGEX)
|
61
72
|
@context[:vid_source] = "vid_cookie"
|
62
|
-
@context[:vid] = force_utf8(v)
|
73
|
+
@context[:vid] = PerimeterXContext.force_utf8(v)
|
63
74
|
end
|
64
75
|
end
|
65
76
|
end #end case
|
@@ -69,10 +80,10 @@ module PxModule
|
|
69
80
|
if (k.start_with? 'HTTP_')
|
70
81
|
header = k.to_s.gsub('HTTP_', '')
|
71
82
|
header = header.gsub('_', '-').downcase
|
72
|
-
@context[:headers][header.to_sym] = force_utf8(v)
|
83
|
+
@context[:headers][header.to_sym] = PerimeterXContext.force_utf8(v)
|
73
84
|
end
|
74
85
|
end #end headers foreach
|
75
|
-
|
86
|
+
|
76
87
|
@context[:hostname]= req.server_name
|
77
88
|
@context[:user_agent] = req.user_agent ? req.user_agent : ''
|
78
89
|
@context[:uri] = px_config[:custom_uri] ? px_config[:custom_uri].call(req) : req.fullpath
|
@@ -97,10 +108,6 @@ module PxModule
|
|
97
108
|
false
|
98
109
|
end
|
99
110
|
|
100
|
-
def force_utf8(str)
|
101
|
-
return str.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
|
102
|
-
end
|
103
|
-
|
104
111
|
def set_block_action_type(action)
|
105
112
|
@context[:block_action] = case action
|
106
113
|
when 'c'
|
@@ -46,8 +46,8 @@ module PxModule
|
|
46
46
|
PROP_FIRST_PARTY_ENABLED = :firstPartyEnabled
|
47
47
|
|
48
48
|
# Hosts
|
49
|
-
CLIENT_HOST = 'client.
|
50
|
-
CAPTCHA_HOST = 'captcha.px-
|
49
|
+
CLIENT_HOST = 'client.perimeterx.net'
|
50
|
+
CAPTCHA_HOST = 'captcha.px-cdn.net'
|
51
51
|
|
52
52
|
VISIBLE = 'visible'
|
53
53
|
HIDDEN = 'hidden'
|
@@ -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
|
@@ -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
|
@@ -29,11 +29,11 @@ module PxModule
|
|
29
29
|
view[PxModule::PROP_CUSTOM_LOGO] = px_config[:custom_logo]
|
30
30
|
view[PxModule::PROP_CSS_REF] = px_config[:css_ref]
|
31
31
|
view[PxModule::PROP_JS_REF] = px_config[:js_ref]
|
32
|
-
view[PxModule::PROP_HOST_URL] =
|
32
|
+
view[PxModule::PROP_HOST_URL] = px_template_object[:host_url]
|
33
33
|
view[PxModule::PROP_LOGO_VISIBILITY] = px_config[:custom_logo] ? PxModule::VISIBLE : PxModule::HIDDEN
|
34
34
|
view[PxModule::PROP_BLOCK_SCRIPT] = px_template_object[:block_script]
|
35
35
|
view[PxModule::PROP_JS_CLIENT_SRC] = px_template_object[:js_client_src]
|
36
|
-
view[PxModule::PROP_FIRST_PARTY_ENABLED] =
|
36
|
+
view[PxModule::PROP_FIRST_PARTY_ENABLED] = px_ctx.context[:first_party_enabled]
|
37
37
|
|
38
38
|
return view.render.html_safe
|
39
39
|
end
|
data/lib/perimeterx/version.rb
CHANGED
data/readme.md
CHANGED
@@ -31,6 +31,7 @@ Table of Contents
|
|
31
31
|
* [Debug Mode](#debug-mode)
|
32
32
|
* [Whitelist Routes](#whitelist-routes)
|
33
33
|
* [Update Configuration on Runtime](#update-config)
|
34
|
+
* [First Party](#first-party)
|
34
35
|
|
35
36
|
**[Contributing](#contributing)**
|
36
37
|
|
@@ -347,6 +348,27 @@ class HomeController < ApplicationController
|
|
347
348
|
end
|
348
349
|
```
|
349
350
|
|
351
|
+
<a name="first-party"></a>**First Party**
|
352
|
+
To enable first party on your enforcer, add the following routes to your `config/routes.rb` file:
|
353
|
+
|
354
|
+
```ruby
|
355
|
+
get '/:appid_postfix/init.js', to: 'home#index', constraints: { appid_postfix: /XXXXXXXX/ }
|
356
|
+
get '/:appid_postfix/captcha/:all', to: 'home#index', constraints: { appid_postfix: /XXXXXXXX/, all:/.*/ }
|
357
|
+
post '/:appid_postfix/xhr/:all', to: 'home#index', constraints: { appid_postfix: /XXXXXXXX/, all:/.*/ }
|
358
|
+
```
|
359
|
+
|
360
|
+
Notice that all occurences of `XXXXXXXX` should be replaced with your px_app_id without the "PX" prefix. For example, if your px_app_id is `PX2H4seK9L`, reeplace `XXXXXXXX` with `2H4seK9L`.
|
361
|
+
In case you are using more than one px_app_id, provide all of them with a `|` sign between them. For example: 2H4seK9L|9bMs6K94|Lc5kPMNx
|
362
|
+
|
363
|
+
|
364
|
+
First Party configuration:
|
365
|
+
Default: true
|
366
|
+
|
367
|
+
```ruby
|
368
|
+
params[:first_party_enabled] = false
|
369
|
+
```
|
370
|
+
|
371
|
+
|
350
372
|
<a name="contributing"></a># Contributing #
|
351
373
|
------------------------------
|
352
374
|
The following steps are welcome when contributing to our project.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: perimeter_x
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nitzan Goldfeder
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-09-
|
11
|
+
date: 2020-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -173,6 +173,7 @@ files:
|
|
173
173
|
- lib/perimeterx/internal/clients/perimeter_x_risk_client.rb
|
174
174
|
- lib/perimeterx/internal/exceptions/px_config_exception.rb
|
175
175
|
- lib/perimeterx/internal/exceptions/px_cookie_decryption_exception.rb
|
176
|
+
- lib/perimeterx/internal/first_party/px_first_party.rb
|
176
177
|
- lib/perimeterx/internal/payload/perimeter_x_cookie_v1.rb
|
177
178
|
- lib/perimeterx/internal/payload/perimeter_x_cookie_v3.rb
|
178
179
|
- lib/perimeterx/internal/payload/perimeter_x_payload.rb
|