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.
Files changed (34) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.travis.yml +3 -0
  4. data/Dockerfile +12 -7
  5. data/Gemfile.lock +36 -30
  6. data/Rakefile +1 -0
  7. data/changelog.md +58 -0
  8. data/examples/app/controllers/home_controller.rb +1 -1
  9. data/lib/perimeter_x.rb +195 -71
  10. data/lib/perimeterx/configuration.rb +74 -22
  11. data/lib/perimeterx/internal/clients/perimeter_x_activity_client.rb +32 -6
  12. data/lib/perimeterx/internal/exceptions/px_config_exception.rb +6 -0
  13. data/lib/perimeterx/internal/first_party/px_first_party.rb +124 -0
  14. data/lib/perimeterx/internal/{perimeter_x_cookie_v1.rb → payload/perimeter_x_cookie_v1.rb} +1 -1
  15. data/lib/perimeterx/internal/{perimeter_x_cookie_v3.rb → payload/perimeter_x_cookie_v3.rb} +1 -1
  16. data/lib/perimeterx/internal/{perimeter_x_cookie.rb → payload/perimeter_x_payload.rb} +12 -4
  17. data/lib/perimeterx/internal/payload/perimeter_x_token_v1.rb +38 -0
  18. data/lib/perimeterx/internal/payload/perimeter_x_token_v3.rb +36 -0
  19. data/lib/perimeterx/internal/perimeter_x_context.rb +74 -32
  20. data/lib/perimeterx/internal/validators/hash_schema_validator.rb +26 -0
  21. data/lib/perimeterx/internal/validators/perimeter_x_cookie_validator.rb +29 -21
  22. data/lib/perimeterx/internal/validators/perimeter_x_s2s_validator.rb +33 -9
  23. data/lib/perimeterx/utils/px_constants.rb +35 -17
  24. data/lib/perimeterx/utils/px_http_client.rb +60 -3
  25. data/lib/perimeterx/utils/px_template_factory.rb +18 -8
  26. data/lib/perimeterx/utils/templates/block_template.mustache +175 -0
  27. data/lib/perimeterx/utils/templates/ratelimit.mustache +9 -0
  28. data/lib/perimeterx/version.rb +1 -1
  29. data/perimeter_x.gemspec +3 -3
  30. data/readme.md +115 -31
  31. metadata +24 -20
  32. data/lib/perimeterx/internal/validators/perimeter_x_captcha_validator.rb +0 -65
  33. data/lib/perimeterx/utils/templates/block.mustache +0 -146
  34. data/lib/perimeterx/utils/templates/captcha.mustache +0 -185
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 52e3418c30763e225706ca5ee7a3a88958c4a210
4
- data.tar.gz: 4671a1eb52edc4cfdb9ba4e85932c2dcb7e33dbb
2
+ SHA256:
3
+ metadata.gz: 475e2577bfe9b12bb7edbe3286fb4f1861a9c508791f38b0196dea0f493f355e
4
+ data.tar.gz: b0c61698741743a62ad0a7c9fb67dc6d5ed9f9b78c01d08b764cb1297ee37c98
5
5
  SHA512:
6
- metadata.gz: 13ca73c6ac3c22ff0d9d93d42cab42049a06e458f9596538cd2225a07dd1ea9e20db8bf4c6921519ed29c349e717eb929643051ef1510337b1414bf6ea8f6c01
7
- data.tar.gz: 2bc1a8fe0845f3899537bb34151c545ea7c6a5343b271c7bceb4d221a9551d74dec174042e30b02e7e29d533d7e0453235163ee0635d2275576c75ed4758efd5
6
+ metadata.gz: 3bae8b3e45c8ee8aba86a56ed977158adec12bccfa2542e1a4e54344b6b6fb0503182585816c1b55640bd49ea4d6323831e93ad6c8d3335703e33d695df362ba
7
+ data.tar.gz: d7a64faa2f03fd4bc467cdea545a2f530001431f37281c2a9561dd83c28c00006fe827e8cd510560fbbbd1a69d382993ae513edd214a18a277bcca57dd561fdc
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  *.rbc
2
+ *.iml
2
3
  capybara-*.html
3
4
  .rspec
4
5
  /log
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.7.1
data/Dockerfile CHANGED
@@ -1,21 +1,26 @@
1
1
  # Based on manual compile instructions at http://wiki.nginx.org/HttpLuaModule#Installation
2
- FROM ruby:2.3.0
2
+ FROM ruby:2.7.1
3
3
 
4
- RUN apt-get update && apt-get --force-yes -qq -y install \
5
- nodejs
6
- ENV RAILS_VERSION 4.2.0
4
+ RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg -o /root/yarn-pubkey.gpg && apt-key add /root/yarn-pubkey.gpg
5
+ RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list
6
+ RUN apt-get update && apt-get install -y --no-install-recommends nodejs yarn vim
7
+
8
+ ENV RAILS_VERSION 6.0.3.2
7
9
  RUN gem install rails --version "$RAILS_VERSION"
8
10
  RUN gem install bundler
9
11
  RUN mkdir -p /tmp/ruby_sandbox
10
12
  WORKDIR /tmp/ruby_sandbox
11
- RUN git clone https://github.com/PerimeterX/perimeterx-ruby-sdk.git
13
+ COPY lib /tmp/ruby_sandbox/lib
14
+ COPY Gemfile /tmp/ruby_sandbox/
15
+ COPY perimeter_x.gemspec /tmp/ruby_sandbox/
16
+ COPY Rakefile /tmp/ruby_sandbox/
12
17
  RUN rails new webapp
13
18
  WORKDIR /tmp/ruby_sandbox/webapp
14
19
 
15
20
  RUN rails generate controller home index
16
21
  WORKDIR /tmp/ruby_sandbox/webapp
17
22
  EXPOSE 3000
18
- RUN sed -i '2i gem "perimeter_x", :path => "/tmp/ruby_sandbox/perimeterx-ruby-sdk"' /tmp/ruby_sandbox/webapp/Gemfile
23
+ RUN sed -i '2i gem "perimeter_x", :path => "/tmp/ruby_sandbox"' /tmp/ruby_sandbox/webapp/Gemfile
19
24
  RUN bundler update
20
- COPY ./examples/ /tmp/ruby_sandbox/webapp
25
+ COPY ./dev/site/ /tmp/ruby_sandbox/webapp
21
26
  CMD ["rails","server","-b","0.0.0.0"]
@@ -1,55 +1,61 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- perimeter_x (1.0.5)
5
- activesupport (>= 4.2.0)
6
- httpclient (= 2.8.2.4)
4
+ perimeter_x (2.0.0)
5
+ activesupport (>= 5.2.4.3)
6
+ concurrent-ruby (~> 1.0, >= 1.0.5)
7
7
  mustache (~> 1.0, >= 1.0.3)
8
+ typhoeus (~> 1.1, >= 1.1.2)
8
9
 
9
10
  GEM
10
11
  remote: https://rubygems.org/
11
12
  specs:
12
- activesupport (5.0.2)
13
+ activesupport (6.0.3.2)
13
14
  concurrent-ruby (~> 1.0, >= 1.0.2)
14
- i18n (~> 0.7)
15
+ i18n (>= 0.7, < 2)
15
16
  minitest (~> 5.1)
16
17
  tzinfo (~> 1.1)
17
- concurrent-ruby (1.0.5)
18
- diff-lcs (1.3)
19
- httpclient (2.8.2.4)
20
- i18n (0.8.1)
21
- metaclass (0.0.4)
22
- minitest (5.10.1)
23
- mocha (1.2.1)
24
- metaclass (~> 0.0.1)
25
- mustache (1.0.4)
26
- rake (10.4.2)
27
- rspec (3.5.0)
28
- rspec-core (~> 3.5.0)
29
- rspec-expectations (~> 3.5.0)
30
- rspec-mocks (~> 3.5.0)
31
- rspec-core (3.5.4)
32
- rspec-support (~> 3.5.0)
33
- rspec-expectations (3.5.0)
18
+ zeitwerk (~> 2.2, >= 2.2.2)
19
+ concurrent-ruby (1.1.6)
20
+ diff-lcs (1.4.4)
21
+ ethon (0.12.0)
22
+ ffi (>= 1.3.0)
23
+ ffi (1.13.1)
24
+ i18n (1.8.3)
25
+ concurrent-ruby (~> 1.0)
26
+ minitest (5.14.1)
27
+ mocha (1.11.2)
28
+ mustache (1.1.1)
29
+ rake (13.0.1)
30
+ rspec (3.9.0)
31
+ rspec-core (~> 3.9.0)
32
+ rspec-expectations (~> 3.9.0)
33
+ rspec-mocks (~> 3.9.0)
34
+ rspec-core (3.9.2)
35
+ rspec-support (~> 3.9.3)
36
+ rspec-expectations (3.9.2)
34
37
  diff-lcs (>= 1.2.0, < 2.0)
35
- rspec-support (~> 3.5.0)
36
- rspec-mocks (3.5.0)
38
+ rspec-support (~> 3.9.0)
39
+ rspec-mocks (3.9.1)
37
40
  diff-lcs (>= 1.2.0, < 2.0)
38
- rspec-support (~> 3.5.0)
39
- rspec-support (3.5.0)
41
+ rspec-support (~> 3.9.0)
42
+ rspec-support (3.9.3)
40
43
  thread_safe (0.3.6)
41
- tzinfo (1.2.3)
44
+ typhoeus (1.4.0)
45
+ ethon (>= 0.9.0)
46
+ tzinfo (1.2.7)
42
47
  thread_safe (~> 0.1)
48
+ zeitwerk (2.3.1)
43
49
 
44
50
  PLATFORMS
45
51
  ruby
46
52
 
47
53
  DEPENDENCIES
48
- bundler (~> 1.14)
54
+ bundler (>= 2.1)
49
55
  mocha (~> 1.2, >= 1.2.1)
50
56
  perimeter_x!
51
- rake (~> 10.0)
57
+ rake (>= 12.3)
52
58
  rspec (~> 3.0)
53
59
 
54
60
  BUNDLED WITH
55
- 1.14.6
61
+ 2.1.4
data/Rakefile CHANGED
@@ -3,6 +3,7 @@ begin
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
+ task :default => :spec
6
7
  task :test => :spec
7
8
  rescue LoadError
8
9
  # no rspec available
@@ -5,6 +5,63 @@ 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
+
12
+ ## [2.1.0] - 2020-09-01
13
+ ### Added
14
+ - Added option to set a different px configuration on each request
15
+ - Added types validation on configuration fields
16
+
17
+ ### Fixed
18
+ - New cookie logic for mobile requests
19
+ - Renamed api_connect_timeout to api_timeout_conncection on default configuration
20
+ - Removed unsapported configuration fields: max_buffer_len and local_proxy
21
+ - Send cookie_origin only if there is a cookie
22
+
23
+ ## [2.0.0] - 2020-07-24
24
+ ### Added
25
+ - Added fields to Block Activity: simulated_block, http_version, http_method, risk_rtt, px_orig_cookie
26
+ - Added fields to page_requested activity: pass_reason, risk_rtt, px_orig_cookie
27
+ - Added px_orig_cookie field to risk_api in case of cookie_decryption_failed
28
+ - Added support for captcha v2
29
+ - Added support for Advanced Blocking Response
30
+ - Added support for whitelise routes
31
+ - Added support for bypass monitor header
32
+ - Added support for extracting vid from _pxvid cookie
33
+ - Added support for rate limit
34
+ - Added risk_cookie_max_iterations configuration
35
+
36
+ ### Fixed
37
+ - Updated dependencies
38
+ - Updated sample site dockerfile
39
+ - Fixed monitor mode
40
+ - Fixed send_page_activities and send_block_activities configurations
41
+ - Updated risk to v3
42
+ - Refactored ip header extraction
43
+ - Renamed block_uuid field to client_uuid
44
+ - Renamed perimeterx_server_host configuration to backend_url
45
+ - Updated risk_response handling: pass the request if risk_response.status is -1
46
+ - Forcing http header values to be utf8
47
+
48
+ ## [1.4.0] - 2018-03-18
49
+ ### Fixed
50
+ - Incorrect assigment for s2s_call_reason
51
+ - Fixed empty token result correct s2s reason
52
+
53
+ ### Added
54
+ - Added support to captcha api v2
55
+ - Mobile sdk support for special tokens 1/2/3
56
+
57
+
58
+ ## [1.3.0] - 2017-07-27
59
+ ### Added
60
+ - Sending client_uuid on page_requested activities
61
+ - Supporting mobile sdk
62
+ ### Fixed
63
+ - Using `request.env` instead of `env`
64
+
8
65
  ## [1.2.0] - 2017-06-04
9
66
  ### Fixed
10
67
  - Default timeouts for post api requests
@@ -27,3 +84,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
27
84
  - Constants on px_constants
28
85
  - Cookie Validation flow when cookie score was over the configured threshold
29
86
  - Using symbols instead of strings for requests body
87
+
@@ -1,7 +1,7 @@
1
1
  class HomeController < ApplicationController
2
2
  include PxModule
3
3
 
4
- before_filter :px_verify_request
4
+ before_action :px_verify_request
5
5
 
6
6
  def index
7
7
  end
@@ -1,3 +1,7 @@
1
+ require 'concurrent'
2
+ require 'json'
3
+ require 'base64'
4
+ require 'uri'
1
5
  require 'perimeterx/configuration'
2
6
  require 'perimeterx/utils/px_logger'
3
7
  require 'perimeterx/utils/px_constants'
@@ -7,139 +11,259 @@ require 'perimeterx/internal/perimeter_x_context'
7
11
  require 'perimeterx/internal/clients/perimeter_x_activity_client'
8
12
  require 'perimeterx/internal/validators/perimeter_x_s2s_validator'
9
13
  require 'perimeterx/internal/validators/perimeter_x_cookie_validator'
10
- require 'perimeterx/internal/validators/perimeter_x_captcha_validator'
14
+ require 'perimeterx/internal/exceptions/px_config_exception'
15
+ require 'perimeterx/internal/first_party/px_first_party'
11
16
 
12
17
  module PxModule
13
-
14
18
  # Module expose API
15
- def px_verify_request
16
- verified, px_ctx = PerimeterX.instance.verify(env)
17
-
18
- # Invalidate _pxCaptcha, can be done only on the controller level
19
- cookies[:_pxCaptcha] = { value: "", expires: -1.minutes.from_now }
20
-
21
- if (!verified)
22
- # In case custon block handler exists
23
- if (PerimeterX.instance.px_config.key?(:custom_block_handler))
24
- PerimeterX.instance.px_config[:logger].debug("PxModule[px_verify_request]: custom_block_handler triggered")
25
- return instance_exec(px_ctx, &PerimeterX.instance.px_config[:custom_block_handler])
26
- else
27
- # Generate template
28
- PerimeterX.instance.px_config[:logger].debug("PxModule[px_verify_request]: sending default block page")
29
- html = PxTemplateFactory.get_template(px_ctx, PerimeterX.instance.px_config)
30
- response.headers["Content-Type"] = "text/html"
31
- response.status = 403
32
- render :html => html
19
+ def px_verify_request(request_config={})
20
+ begin
21
+ px_instance = PerimeterX.new(request_config)
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)
32
+ px_config = px_instance.px_config
33
+
34
+ msg_title = 'PxModule[px_verify_request]'
35
+
36
+ # In case custom verification handler is in use
37
+ if px_config.key?(:custom_verification_handler)
38
+ px_config[:logger].debug("#{msg_title}: custom_verification_handler triggered")
39
+ return instance_exec(px_ctx, &px_config[:custom_verification_handler])
33
40
  end
41
+
42
+ unless px_ctx.nil? || px_ctx.context[:verified] || (px_config[:module_mode] == PxModule::MONITOR_MODE && !px_ctx.context[:should_bypass_monitor])
43
+ # In case custom block handler exists (soon to be deprecated)
44
+ if px_config.key?(:custom_block_handler)
45
+ px_config[:logger].debug("#{msg_title}: custom_block_handler triggered")
46
+ px_config[:logger].debug(
47
+ "#{msg_title}: Please note that custom_block_handler is deprecated. Use custom_verification_handler instead.")
48
+ return instance_exec(px_ctx, &px_config[:custom_block_handler])
49
+ else
50
+ if px_ctx.context[:block_action]== 'rate_limit'
51
+ px_config[:logger].debug("#{msg_title}: sending rate limit page")
52
+ response.status = 429
53
+ else
54
+ px_config[:logger].debug("#{msg_title}: sending default block page")
55
+ response.status = 403
56
+ end
57
+
58
+ is_mobile = px_ctx.context[:cookie_origin] == 'header' ? '1' : '0'
59
+ action = px_ctx.context[:block_action][0,1]
60
+
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",
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}",
71
+ host_url: "https://collector-#{px_config[:app_id]}.perimeterx.net"
72
+ }
73
+ end
74
+
75
+ html = PxTemplateFactory.get_template(px_ctx, px_config, px_template_object)
76
+
77
+ # Web handler
78
+ if px_ctx.context[:cookie_origin] == 'cookie'
79
+
80
+ accept_header_value = request.headers['accept'] || request.headers['content-type'];
81
+ is_json_response = px_ctx.context[:block_action] != 'rate_limit' && accept_header_value && accept_header_value.split(',').select {|e| e.downcase.include? 'application/json'}.length > 0;
82
+
83
+ if (is_json_response)
84
+ px_config[:logger].debug("#{msg_title}: advanced blocking response response")
85
+ response.headers['Content-Type'] = 'application/json'
86
+
87
+ hash_json = {
88
+ :appId => px_config[:app_id],
89
+ :jsClientSrc => px_template_object[:js_client_src],
90
+ :firstPartyEnabled => px_ctx.context[:first_party_enabled],
91
+ :uuid => px_ctx.context[:uuid],
92
+ :vid => px_ctx.context[:vid],
93
+ :hostUrl => "https://collector-#{px_config[:app_id]}.perimeterx.net",
94
+ :blockScript => px_template_object[:block_script],
95
+ }
96
+
97
+ render :json => hash_json
98
+ else
99
+ px_config[:logger].debug('#{msg_title}: web block')
100
+ response.headers['Content-Type'] = 'text/html'
101
+ render :html => html
102
+ end
103
+ else # Mobile SDK
104
+ px_config[:logger].debug("#{msg_title}: mobile sdk block")
105
+ response.headers['Content-Type'] = 'application/json'
106
+ hash_json = {
107
+ :action => px_ctx.context[:block_action],
108
+ :uuid => px_ctx.context[:uuid],
109
+ :vid => px_ctx.context[:vid],
110
+ :appId => px_config[:app_id],
111
+ :page => Base64.strict_encode64(html),
112
+ :collectorUrl => "https://collector-#{px_config[:app_id]}.perimeterx.net"
113
+ }
114
+ render :json => hash_json
115
+ end
116
+ end
117
+ end
118
+
119
+ # Request was verified
120
+ return px_ctx.nil? ? true : px_ctx.context[:verified]
121
+
122
+ rescue PxConfigurationException
123
+ raise
124
+ rescue Exception => e
125
+ error_logger = PxLogger.new(true)
126
+ error_logger.error("#{e.backtrace.first}: #{e.message} (#{e.class})")
127
+ e.backtrace.drop(1).map {|s| error_logger.error("\t#{s}")}
128
+ return nil
34
129
  end
130
+ end
35
131
 
36
- return verified
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
37
153
  end
38
154
 
39
- def self.configure(params)
40
- @px_instance = PerimeterX.configure(params)
155
+ def self.configure(basic_config)
156
+ PerimeterX.set_basic_config(basic_config)
41
157
  end
42
158
 
43
159
 
44
- # PerimtereX Module
160
+ # PerimeterX Module
45
161
  class PerimeterX
46
- @@__instance = nil
47
- @@mutex = Mutex.new
48
162
 
49
163
  attr_reader :px_config
164
+ attr_reader :first_party
50
165
  attr_accessor :px_http_client
51
166
  attr_accessor :px_activity_client
52
167
 
53
168
  #Static methods
54
- def self.configure(params)
55
- return true if @@__instance
56
- @@mutex.synchronize {
57
- return @@__instance if @@__instance
58
- @@__instance = new(params)
59
- }
60
- return true
61
- end
62
-
63
- def self.instance
64
- return @@__instance if !@@__instance.nil?
65
- raise Exception.new("Please initialize perimeter x first")
169
+ def self.set_basic_config(basic_config)
170
+ Configuration.set_basic_config(basic_config)
66
171
  end
67
172
 
68
-
69
173
  #Instance Methods
70
- def verify(env)
174
+ def verify(req)
71
175
  begin
72
- @logger.debug("PerimeterX[pxVerify]")
73
- req = ActionDispatch::Request.new(env)
74
- if (!@px_config[:module_enabled])
75
- @logger.warn("Module is disabled")
76
- return true
77
- end
78
- px_ctx = PerimeterXContext.new(@px_config, req)
79
176
 
80
- # Captcha phase
81
- captcha_verified, px_ctx = @px_captcha_validator.verify(px_ctx)
82
- if (captcha_verified)
83
- return handle_verification(px_ctx)
177
+ # check module_enabled
178
+ @logger.debug('PerimeterX[pxVerify]')
179
+ if !@px_config[:module_enabled]
180
+ @logger.warn('Module is disabled')
181
+ return nil
182
+ end
183
+
184
+ # filter whitelist routes
185
+ url_path = URI.parse(req.original_url).path
186
+ if url_path && !url_path.empty?
187
+ if check_whitelist_routes(px_config[:whitelist_routes], url_path)
188
+ @logger.debug("PerimeterX[pxVerify]: whitelist route: #{url_path}")
189
+ return nil
190
+ end
84
191
  end
192
+
193
+ # create context
194
+ px_ctx = PerimeterXContext.new(@px_config, req)
85
195
 
86
196
  # Cookie phase
87
197
  cookie_verified, px_ctx = @px_cookie_validator.verify(px_ctx)
88
- if (!cookie_verified)
198
+ if !cookie_verified
199
+ if !px_ctx.context[:mobile_error].nil?
200
+ px_ctx.context[:s2s_call_reason] = "mobile_error_#{px_ctx.context[:mobile_error]}"
201
+ end
89
202
  @px_s2s_validator.verify(px_ctx)
90
203
  end
91
204
 
92
- if (@px_config.key?(:custom_verification_handler))
93
- return @px_config[:custom_verification_handler].call(px_ctx.context)
94
- else
95
- return handle_verification(px_ctx)
96
- end
205
+ return handle_verification(px_ctx)
97
206
  rescue Exception => e
98
207
  @logger.error("#{e.backtrace.first}: #{e.message} (#{e.class})")
99
- e.backtrace.drop(1).map { |s| @logger.error("\t#{s}") }
100
- return true
208
+ e.backtrace.drop(1).map {|s| @logger.error("\t#{s}")}
209
+ return nil
101
210
  end
102
211
  end
103
212
 
104
- private def initialize(params)
105
- @px_config = Configuration.new(params).configuration
213
+ def initialize(request_config)
214
+
215
+ @px_config = Configuration.new(request_config).configuration
106
216
  @logger = @px_config[:logger]
107
217
  @px_http_client = PxHttpClient.new(@px_config)
108
218
 
109
219
  @px_activity_client = PerimeterxActivitiesClient.new(@px_config, @px_http_client)
220
+ @first_party = FirstPartyManager.new(@px_config, @px_http_client, @logger)
110
221
 
111
222
  @px_cookie_validator = PerimeterxCookieValidator.new(@px_config)
112
223
  @px_s2s_validator = PerimeterxS2SValidator.new(@px_config, @px_http_client)
113
- @px_captcha_validator = PerimeterxCaptchaValidator.new(@px_config, @px_http_client)
114
- @logger.debug("PerimeterX[initialize]")
224
+ @logger.debug('PerimeterX[initialize]')
115
225
  end
116
226
 
117
227
  private def handle_verification(px_ctx)
118
- @logger.debug("PerimeterX[handle_verification]")
228
+ @logger.debug('PerimeterX[handle_verification]')
119
229
  @logger.debug("PerimeterX[handle_verification]: processing ended - score:#{px_ctx.context[:score]}, uuid:#{px_ctx.context[:uuid]}")
120
230
 
121
231
  score = px_ctx.context[:score]
232
+ px_ctx.context[:should_bypass_monitor] = @px_config[:bypass_monitor_header] && px_ctx.context[:headers][@px_config[:bypass_monitor_header].to_sym] == '1';
233
+
234
+ px_ctx.context[:verified] = score < @px_config[:blocking_score]
122
235
  # Case PASS request
123
- if (score < @px_config[:blocking_score])
236
+ if px_ctx.context[:verified]
124
237
  @logger.debug("PerimeterX[handle_verification]: score:#{score} < blocking score, passing request")
125
238
  @px_activity_client.send_page_requested_activity(px_ctx)
126
- return true
239
+ return px_ctx
127
240
  end
128
241
 
129
242
  # Case blocking activity
130
243
  @px_activity_client.send_block_activity(px_ctx)
131
244
 
132
245
  # In case were in monitor mode, end here
133
- if(@px_config[:module_mode] == PxModule::MONITOR_MODE)
246
+ if @px_config[:module_mode] == PxModule::MONITOR_MODE && !px_ctx.context[:should_bypass_monitor]
134
247
  @logger.debug("PerimeterX[handle_verification]: monitor mode is on, passing request")
135
- return true
248
+ return px_ctx
136
249
  end
137
250
 
138
- @logger.debug("PerimeterX[handle_verification]: verification ended, the request should be blocked")
251
+ @logger.debug('PerimeterX[handle_verification]: verification ended, the request should be blocked')
252
+
253
+ return px_ctx
254
+ end
139
255
 
140
- return false, px_ctx
256
+ private def check_whitelist_routes(whitelist_routes, path)
257
+ whitelist_routes.each do |whitelist_route|
258
+ if whitelist_route.is_a?(Regexp) && path.match(whitelist_route)
259
+ return true
260
+ end
261
+ if whitelist_route.is_a?(String) && path.start_with?(whitelist_route)
262
+ return true
263
+ end
264
+ end
265
+ false
141
266
  end
142
267
 
143
- private_class_method :new
144
268
  end
145
269
  end