perimeter_x 1.0.6.pre.alpha → 2.0.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 +6 -3
- data/.travis.yml +3 -0
- data/Dockerfile +19 -41
- data/Gemfile +1 -1
- data/Gemfile.lock +51 -3
- data/LICENSE.txt +9 -12
- data/Rakefile +10 -2
- data/changelog.md +72 -0
- data/examples/app/controllers/home_controller.rb +9 -0
- data/examples/app/views/home/index.html.erb.dist +20 -0
- data/examples/config/initializers/perimeterx.rb.dist +8 -0
- data/examples/{routes.rb → config/routes.rb} +0 -0
- data/lib/perimeter_x.rb +192 -37
- data/lib/perimeterx/configuration.rb +30 -18
- data/lib/perimeterx/internal/clients/perimeter_x_activity_client.rb +110 -0
- data/lib/perimeterx/internal/clients/perimeter_x_risk_client.rb +28 -0
- data/lib/perimeterx/internal/exceptions/px_cookie_decryption_exception.rb +5 -0
- data/lib/perimeterx/internal/payload/perimeter_x_cookie_v1.rb +42 -0
- data/lib/perimeterx/internal/payload/perimeter_x_cookie_v3.rb +37 -0
- data/lib/perimeterx/internal/payload/perimeter_x_payload.rb +148 -0
- 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 +112 -53
- data/lib/perimeterx/internal/validators/perimeter_x_cookie_validator.rb +103 -0
- data/lib/perimeterx/internal/validators/perimeter_x_s2s_validator.rb +128 -0
- data/lib/perimeterx/utils/px_constants.rb +62 -0
- data/lib/perimeterx/utils/px_http_client.rb +43 -28
- data/lib/perimeterx/utils/px_logger.rb +12 -6
- data/lib/perimeterx/utils/px_template_factory.rb +41 -0
- data/lib/perimeterx/utils/templates/block_template.mustache +175 -0
- data/lib/perimeterx/utils/templates/ratelimit.mustache +9 -0
- data/lib/perimeterx/version.rb +2 -2
- data/perimeter_x.gemspec +10 -4
- data/readme.md +258 -42
- metadata +130 -24
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/examples/home_controller.rb.dist +0 -23
- data/lib/perimeterx/internal/perimeter_x_risk_client.rb +0 -29
- data/lib/perimeterx/internal/perimeter_x_s2s_validator.rb +0 -67
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a06a83f955ae265238a23df8471c062428cf82ba37612160a439c52af3568e79
|
4
|
+
data.tar.gz: 0eaeb8c8b424a219d155f933494c0baec382b96e707cb7af22e676ea83a1fd4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c615587bc9e1203636e0a74284aa9faadd3027dc50056929b4bb8fc2cdd6a86bdc0df10c94f3e262f0f313e518fc0397ac2b0b76669fe3e1b5afc85ad589567d
|
7
|
+
data.tar.gz: 22faae3132f9fce873829a0feec4b8f9bfcda420960a380d40a5101b4dae793969b8225a5376f2937954519a8c8cb1c20eb252fca096af77bff7980d5c223f71
|
data/.gitignore
CHANGED
@@ -1,20 +1,23 @@
|
|
1
1
|
*.rbc
|
2
|
+
*.iml
|
2
3
|
capybara-*.html
|
3
4
|
.rspec
|
4
5
|
/log
|
5
6
|
/tmp
|
7
|
+
/bin
|
6
8
|
/dev
|
7
9
|
/db/*.sqlite3
|
8
10
|
/db/*.sqlite3-journal
|
9
11
|
/public/system
|
10
12
|
/coverage/
|
11
13
|
/spec/tmp
|
12
|
-
examples/
|
14
|
+
examples/config/initializers/perimeterx.rb
|
15
|
+
examples/app/views/home/index.html.erb
|
13
16
|
**.orig
|
14
17
|
*.gem
|
15
18
|
rerun.txt
|
16
19
|
pickle-email-*.html
|
17
|
-
|
20
|
+
|
18
21
|
# TODO Comment out these rules if you are OK with secrets being uploaded to the repo
|
19
22
|
config/initializers/secret_token.rb
|
20
23
|
config/secrets.yml
|
@@ -22,7 +25,7 @@ config/secrets.yml
|
|
22
25
|
# dotenv
|
23
26
|
# TODO Comment out this rule if environment variables can be committed
|
24
27
|
.env
|
25
|
-
|
28
|
+
|
26
29
|
## Environment normalization:
|
27
30
|
/.bundle
|
28
31
|
/vendor/bundle
|
data/.travis.yml
ADDED
data/Dockerfile
CHANGED
@@ -1,48 +1,26 @@
|
|
1
1
|
# Based on manual compile instructions at http://wiki.nginx.org/HttpLuaModule#Installation
|
2
|
-
FROM
|
3
|
-
RUN apt-get update && apt-get --force-yes -qq -y install \
|
4
|
-
build-essential \
|
5
|
-
ca-certificates \
|
6
|
-
curl \
|
7
|
-
git \
|
8
|
-
libpcre3 \
|
9
|
-
libpcre3-dev \
|
10
|
-
libssl-dev \
|
11
|
-
libreadline-dev \
|
12
|
-
libyaml-dev \
|
13
|
-
libgdbm-dev \
|
14
|
-
libtool \
|
15
|
-
automake \
|
16
|
-
bison \
|
17
|
-
lua-cjson \
|
18
|
-
libncurses5-dev \
|
19
|
-
m4 \
|
20
|
-
libsqlite3-dev \
|
21
|
-
rsyslog \
|
22
|
-
sqlite3 \
|
23
|
-
libxml2-dev \
|
24
|
-
libxslt1-dev \
|
25
|
-
libcurl4-openssl-dev \
|
26
|
-
python-software-properties \
|
27
|
-
libffi-dev \
|
28
|
-
nodejs \
|
29
|
-
wget \
|
30
|
-
zlib1g-dev
|
2
|
+
FROM ruby:2.7.1
|
31
3
|
|
32
|
-
RUN
|
33
|
-
RUN /
|
34
|
-
RUN
|
35
|
-
|
36
|
-
|
37
|
-
RUN
|
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
|
9
|
+
RUN gem install rails --version "$RAILS_VERSION"
|
10
|
+
RUN gem install bundler
|
38
11
|
RUN mkdir -p /tmp/ruby_sandbox
|
39
12
|
WORKDIR /tmp/ruby_sandbox
|
40
|
-
|
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/
|
17
|
+
RUN rails new webapp
|
41
18
|
WORKDIR /tmp/ruby_sandbox/webapp
|
42
|
-
|
19
|
+
|
20
|
+
RUN rails generate controller home index
|
43
21
|
WORKDIR /tmp/ruby_sandbox/webapp
|
44
22
|
EXPOSE 3000
|
45
|
-
RUN sed -i
|
46
|
-
RUN
|
47
|
-
|
48
|
-
CMD ["
|
23
|
+
RUN sed -i '2i gem "perimeter_x", :path => "/tmp/ruby_sandbox"' /tmp/ruby_sandbox/webapp/Gemfile
|
24
|
+
RUN bundler update
|
25
|
+
COPY ./dev/site/ /tmp/ruby_sandbox/webapp
|
26
|
+
CMD ["rails","server","-b","0.0.0.0"]
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,13 +1,61 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
perimeter_x (2.0.0)
|
5
|
+
activesupport (>= 5.2.4.3)
|
6
|
+
concurrent-ruby (~> 1.0, >= 1.0.5)
|
7
|
+
mustache (~> 1.0, >= 1.0.3)
|
8
|
+
typhoeus (~> 1.1, >= 1.1.2)
|
9
|
+
|
1
10
|
GEM
|
2
11
|
remote: https://rubygems.org/
|
3
12
|
specs:
|
4
|
-
|
13
|
+
activesupport (6.0.3.2)
|
14
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
15
|
+
i18n (>= 0.7, < 2)
|
16
|
+
minitest (~> 5.1)
|
17
|
+
tzinfo (~> 1.1)
|
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)
|
37
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
38
|
+
rspec-support (~> 3.9.0)
|
39
|
+
rspec-mocks (3.9.1)
|
40
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
41
|
+
rspec-support (~> 3.9.0)
|
42
|
+
rspec-support (3.9.3)
|
43
|
+
thread_safe (0.3.6)
|
44
|
+
typhoeus (1.4.0)
|
45
|
+
ethon (>= 0.9.0)
|
46
|
+
tzinfo (1.2.7)
|
47
|
+
thread_safe (~> 0.1)
|
48
|
+
zeitwerk (2.3.1)
|
5
49
|
|
6
50
|
PLATFORMS
|
7
51
|
ruby
|
8
52
|
|
9
53
|
DEPENDENCIES
|
10
|
-
|
54
|
+
bundler (>= 2.1)
|
55
|
+
mocha (~> 1.2, >= 1.2.1)
|
56
|
+
perimeter_x!
|
57
|
+
rake (>= 12.3)
|
58
|
+
rspec (~> 3.0)
|
11
59
|
|
12
60
|
BUNDLED WITH
|
13
|
-
1.
|
61
|
+
2.1.4
|
data/LICENSE.txt
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
Copyright (c) 2017 nitzanpx
|
1
|
+
Copyright © 2016 PerimeterX, Inc.
|
4
2
|
|
5
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
4
|
of this software and associated documentation files (the "Software"), to deal
|
@@ -9,13 +7,12 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
7
|
copies of the Software, and to permit persons to whom the Software is
|
10
8
|
furnished to do so, subject to the following conditions:
|
11
9
|
|
12
|
-
The above copyright notice and this permission notice shall be included in
|
13
|
-
all copies or substantial portions of the Software.
|
10
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
14
11
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
21
|
-
THE SOFTWARE.
|
12
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
13
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
14
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
15
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
16
|
+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
17
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
18
|
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
CHANGED
data/changelog.md
CHANGED
@@ -0,0 +1,72 @@
|
|
1
|
+
# Change Log
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
6
|
+
and this project adheres to [Semantic Versioning](http://semver.org/).
|
7
|
+
|
8
|
+
## [2.0.0] - 2020-07-24
|
9
|
+
### Added
|
10
|
+
- Added fields to Block Activity: simulated_block, http_version, http_method, risk_rtt, px_orig_cookie
|
11
|
+
- Added fields to page_requested activity: pass_reason, risk_rtt, px_orig_cookie
|
12
|
+
- Added px_orig_cookie field to risk_api in case of cookie_decryption_failed
|
13
|
+
- Added support for captcha v2
|
14
|
+
- Added support for Advanced Blocking Response
|
15
|
+
- Added support for whitelise routes
|
16
|
+
- Added support for bypass monitor header
|
17
|
+
- Added support for extracting vid from _pxvid cookie
|
18
|
+
- Added support for rate limit
|
19
|
+
- Added risk_cookie_max_iterations configuration
|
20
|
+
|
21
|
+
### Fixed
|
22
|
+
- Updated dependencies
|
23
|
+
- Updated sample site dockerfile
|
24
|
+
- Fixed monitor mode
|
25
|
+
- Fixed send_page_activities and send_block_activities configurations
|
26
|
+
- Updated risk to v3
|
27
|
+
- Refactored ip header extraction
|
28
|
+
- Renamed block_uuid field to client_uuid
|
29
|
+
- Renamed perimeterx_server_host configuration to backend_url
|
30
|
+
- Updated risk_response handling: pass the request if risk_response.status is -1
|
31
|
+
- Forcing http header values to be utf8
|
32
|
+
|
33
|
+
## [1.4.0] - 2018-03-18
|
34
|
+
### Fixed
|
35
|
+
- Incorrect assigment for s2s_call_reason
|
36
|
+
- Fixed empty token result correct s2s reason
|
37
|
+
|
38
|
+
### Added
|
39
|
+
- Added support to captcha api v2
|
40
|
+
- Mobile sdk support for special tokens 1/2/3
|
41
|
+
|
42
|
+
|
43
|
+
## [1.3.0] - 2017-07-27
|
44
|
+
### Added
|
45
|
+
- Sending client_uuid on page_requested activities
|
46
|
+
- Supporting mobile sdk
|
47
|
+
### Fixed
|
48
|
+
- Using `request.env` instead of `env`
|
49
|
+
|
50
|
+
## [1.2.0] - 2017-06-04
|
51
|
+
### Fixed
|
52
|
+
- Default timeouts for post api requests
|
53
|
+
- Fixed Dockerfile
|
54
|
+
### Changed
|
55
|
+
- Removed httpclient and instead using typheous
|
56
|
+
### Added
|
57
|
+
- Using concurrent-ruby for async post requests
|
58
|
+
|
59
|
+
## [1.1.0] - 2017-06-04
|
60
|
+
### Added
|
61
|
+
- Added support for sensitive routes
|
62
|
+
|
63
|
+
## [1.0.5] - 2017-05-07
|
64
|
+
### Fixed
|
65
|
+
- Added request format into context for custom callbacks
|
66
|
+
|
67
|
+
## [1.0.4] - 2017-04-27
|
68
|
+
### Fixed
|
69
|
+
- Constants on px_constants
|
70
|
+
- Cookie Validation flow when cookie score was over the configured threshold
|
71
|
+
- Using symbols instead of strings for requests body
|
72
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<h1>Home#index</h1>
|
2
|
+
<p>Find me in app/views/home/index.html.erb</p>
|
3
|
+
|
4
|
+
<script type="text/javascript">
|
5
|
+
(function(){
|
6
|
+
window._pxAppId ='APP_ID';
|
7
|
+
// Custom parameters
|
8
|
+
// window._pxParam1 = "<param1>";
|
9
|
+
var p = document.getElementsByTagName('script')[0],
|
10
|
+
s = document.createElement('script');
|
11
|
+
s.async = 1;
|
12
|
+
s.src = '//client.perimeterx.net/APP_ID/main.min.js';
|
13
|
+
p.parentNode.insertBefore(s,p);
|
14
|
+
}());
|
15
|
+
</script>
|
16
|
+
<noscript>
|
17
|
+
<div style="position:fixed; top:0; left:0; display:none" width="1" height="1">
|
18
|
+
<img src="//collector-APP_ID.perimeterx.net/api/v1/collector/noScript.gif?appId=APP_ID">
|
19
|
+
</div>
|
20
|
+
</noscript>
|
File without changes
|
data/lib/perimeter_x.rb
CHANGED
@@ -1,69 +1,224 @@
|
|
1
|
+
require 'concurrent'
|
2
|
+
require 'json'
|
3
|
+
require 'base64'
|
4
|
+
require 'uri'
|
1
5
|
require 'perimeterx/configuration'
|
2
6
|
require 'perimeterx/utils/px_logger'
|
7
|
+
require 'perimeterx/utils/px_constants'
|
3
8
|
require 'perimeterx/utils/px_http_client'
|
9
|
+
require 'perimeterx/utils/px_template_factory'
|
4
10
|
require 'perimeterx/internal/perimeter_x_context'
|
5
|
-
require 'perimeterx/internal/
|
11
|
+
require 'perimeterx/internal/clients/perimeter_x_activity_client'
|
12
|
+
require 'perimeterx/internal/validators/perimeter_x_s2s_validator'
|
13
|
+
require 'perimeterx/internal/validators/perimeter_x_cookie_validator'
|
6
14
|
|
7
|
-
module
|
8
|
-
|
9
|
-
|
15
|
+
module PxModule
|
16
|
+
# Module expose API
|
17
|
+
def px_verify_request
|
18
|
+
px_ctx = PerimeterX.instance.verify(request.env)
|
19
|
+
px_config = PerimeterX.instance.px_config
|
20
|
+
msg_title = 'PxModule[px_verify_request]'
|
10
21
|
|
11
|
-
|
12
|
-
|
22
|
+
# In case custom verification handler is in use
|
23
|
+
if px_config.key?(:custom_verification_handler)
|
24
|
+
px_config[:logger].debug("#{msg_title}: custom_verification_handler triggered")
|
25
|
+
return instance_exec(px_ctx, &px_config[:custom_verification_handler])
|
26
|
+
end
|
27
|
+
|
28
|
+
unless px_ctx.nil? || px_ctx.context[:verified] || (px_config[:module_mode] == PxModule::MONITOR_MODE && !px_ctx.context[:should_bypass_monitor])
|
29
|
+
# In case custom block handler exists (soon to be deprecated)
|
30
|
+
if px_config.key?(:custom_block_handler)
|
31
|
+
px_config[:logger].debug("#{msg_title}: custom_block_handler triggered")
|
32
|
+
px_config[:logger].debug(
|
33
|
+
"#{msg_title}: Please note that custom_block_handler is deprecated. Use custom_verification_handler instead.")
|
34
|
+
return instance_exec(px_ctx, &px_config[:custom_block_handler])
|
35
|
+
else
|
36
|
+
if px_ctx.context[:block_action]== 'rate_limit'
|
37
|
+
px_config[:logger].debug("#{msg_title}: sending rate limit page")
|
38
|
+
response.status = 429
|
39
|
+
else
|
40
|
+
px_config[:logger].debug("#{msg_title}: sending default block page")
|
41
|
+
response.status = 403
|
42
|
+
end
|
43
|
+
|
44
|
+
is_mobile = px_ctx.context[:cookie_origin] == 'header' ? '1' : '0'
|
45
|
+
action = px_ctx.context[:block_action][0,1]
|
46
|
+
|
47
|
+
px_template_object = {
|
48
|
+
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}",
|
49
|
+
js_client_src: "//#{PxModule::CLIENT_HOST}/#{px_config[:app_id]}/main.min.js"
|
50
|
+
}
|
51
|
+
|
52
|
+
html = PxTemplateFactory.get_template(px_ctx, px_config, px_template_object)
|
53
|
+
|
54
|
+
# Web handler
|
55
|
+
if px_ctx.context[:cookie_origin] == 'cookie'
|
56
|
+
|
57
|
+
accept_header_value = request.headers['accept'] || request.headers['content-type'];
|
58
|
+
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;
|
59
|
+
|
60
|
+
if (is_json_response)
|
61
|
+
px_config[:logger].debug("#{msg_title}: advanced blocking response response")
|
62
|
+
response.headers['Content-Type'] = 'application/json'
|
63
|
+
|
64
|
+
hash_json = {
|
65
|
+
:appId => px_config[:app_id],
|
66
|
+
:jsClientSrc => px_template_object[:js_client_src],
|
67
|
+
:firstPartyEnabled => false,
|
68
|
+
:uuid => px_ctx.context[:uuid],
|
69
|
+
:vid => px_ctx.context[:vid],
|
70
|
+
:hostUrl => "https://collector-#{px_config[:app_id]}.perimeterx.net",
|
71
|
+
:blockScript => px_template_object[:block_script],
|
72
|
+
}
|
73
|
+
|
74
|
+
render :json => hash_json
|
75
|
+
else
|
76
|
+
px_config[:logger].debug('#{msg_title}: web block')
|
77
|
+
response.headers['Content-Type'] = 'text/html'
|
78
|
+
render :html => html
|
79
|
+
end
|
80
|
+
else # Mobile SDK
|
81
|
+
px_config[:logger].debug("#{msg_title}: mobile sdk block")
|
82
|
+
response.headers['Content-Type'] = 'application/json'
|
83
|
+
hash_json = {
|
84
|
+
:action => px_ctx.context[:block_action],
|
85
|
+
:uuid => px_ctx.context[:uuid],
|
86
|
+
:vid => px_ctx.context[:vid],
|
87
|
+
:appId => px_config[:app_id],
|
88
|
+
:page => Base64.strict_encode64(html),
|
89
|
+
:collectorUrl => "https://collector-#{px_config[:app_id]}.perimeterx.net"
|
90
|
+
}
|
91
|
+
render :json => hash_json
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Request was verified
|
97
|
+
return px_ctx.nil? ? true : px_ctx.context[:verified]
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.configure(params)
|
101
|
+
@px_instance = PerimeterX.configure(params)
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
# PerimeterX Module
|
106
|
+
class PerimeterX
|
107
|
+
@@__instance = nil
|
108
|
+
@@mutex = Mutex.new
|
13
109
|
|
14
110
|
attr_reader :px_config
|
15
111
|
attr_accessor :px_http_client
|
112
|
+
attr_accessor :px_activity_client
|
16
113
|
|
17
|
-
|
18
|
-
|
19
|
-
@@
|
20
|
-
|
21
|
-
@@
|
114
|
+
#Static methods
|
115
|
+
def self.configure(params)
|
116
|
+
return true if @@__instance
|
117
|
+
@@mutex.synchronize {
|
118
|
+
return @@__instance if @@__instance
|
119
|
+
@@__instance = new(params)
|
22
120
|
}
|
23
|
-
|
121
|
+
return true
|
24
122
|
end
|
25
123
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@px_config = Configuration.new(params).configuration
|
30
|
-
@px_http_client = PxHttpClient.new(@px_config)
|
124
|
+
def self.instance
|
125
|
+
return @@__instance if !@@__instance.nil?
|
126
|
+
raise Exception.new('Please initialize perimeter x first')
|
31
127
|
end
|
32
128
|
|
33
|
-
|
129
|
+
|
130
|
+
#Instance Methods
|
131
|
+
def verify(env)
|
34
132
|
begin
|
35
|
-
L.info("PerimeterX[pxVerify]")
|
36
|
-
req = ActionDispatch::Request.new(env)
|
37
133
|
|
38
|
-
|
39
|
-
|
40
|
-
|
134
|
+
# check module_enabled
|
135
|
+
@logger.debug('PerimeterX[pxVerify]')
|
136
|
+
if !@px_config[:module_enabled]
|
137
|
+
@logger.warn('Module is disabled')
|
138
|
+
return nil
|
41
139
|
end
|
42
140
|
|
141
|
+
req = ActionDispatch::Request.new(env)
|
142
|
+
|
143
|
+
# filter whitelist routes
|
144
|
+
url_path = URI.parse(req.original_url).path
|
145
|
+
if url_path && !url_path.empty?
|
146
|
+
if check_whitelist_routes(px_config[:whitelist_routes], url_path)
|
147
|
+
@logger.debug("PerimeterX[pxVerify]: whitelist route: #{url_path}")
|
148
|
+
return nil
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# create context
|
43
153
|
px_ctx = PerimeterXContext.new(@px_config, req)
|
44
|
-
px_ctx.context[:s2s_call_reason] = "no_cookie"
|
45
154
|
|
46
|
-
|
47
|
-
px_ctx =
|
48
|
-
|
49
|
-
|
50
|
-
return px_config['custom_verification_handler'].call(px_ctx.context)
|
51
|
-
else
|
52
|
-
return handle_verification(px_ctx)
|
155
|
+
# Cookie phase
|
156
|
+
cookie_verified, px_ctx = @px_cookie_validator.verify(px_ctx)
|
157
|
+
if !cookie_verified
|
158
|
+
@px_s2s_validator.verify(px_ctx)
|
53
159
|
end
|
160
|
+
|
161
|
+
return handle_verification(px_ctx)
|
54
162
|
rescue Exception => e
|
55
|
-
|
56
|
-
|
163
|
+
@logger.error("#{e.backtrace.first}: #{e.message} (#{e.class})")
|
164
|
+
e.backtrace.drop(1).map {|s| @logger.error("\t#{s}")}
|
165
|
+
return nil
|
57
166
|
end
|
58
167
|
end
|
59
168
|
|
60
|
-
|
169
|
+
private def initialize(params)
|
170
|
+
@px_config = Configuration.new(params).configuration
|
171
|
+
@logger = @px_config[:logger]
|
172
|
+
@px_http_client = PxHttpClient.new(@px_config)
|
173
|
+
|
174
|
+
@px_activity_client = PerimeterxActivitiesClient.new(@px_config, @px_http_client)
|
175
|
+
|
176
|
+
@px_cookie_validator = PerimeterxCookieValidator.new(@px_config)
|
177
|
+
@px_s2s_validator = PerimeterxS2SValidator.new(@px_config, @px_http_client)
|
178
|
+
@logger.debug('PerimeterX[initialize]')
|
179
|
+
end
|
180
|
+
|
61
181
|
private def handle_verification(px_ctx)
|
62
|
-
|
63
|
-
|
182
|
+
@logger.debug('PerimeterX[handle_verification]')
|
183
|
+
@logger.debug("PerimeterX[handle_verification]: processing ended - score:#{px_ctx.context[:score]}, uuid:#{px_ctx.context[:uuid]}")
|
184
|
+
|
185
|
+
score = px_ctx.context[:score]
|
186
|
+
px_ctx.context[:should_bypass_monitor] = @px_config[:bypass_monitor_header] && px_ctx.context[:headers][@px_config[:bypass_monitor_header].to_sym] == '1';
|
187
|
+
|
188
|
+
px_ctx.context[:verified] = score < @px_config[:blocking_score]
|
189
|
+
# Case PASS request
|
190
|
+
if px_ctx.context[:verified]
|
191
|
+
@logger.debug("PerimeterX[handle_verification]: score:#{score} < blocking score, passing request")
|
192
|
+
@px_activity_client.send_page_requested_activity(px_ctx)
|
193
|
+
return px_ctx
|
194
|
+
end
|
195
|
+
|
196
|
+
# Case blocking activity
|
197
|
+
@px_activity_client.send_block_activity(px_ctx)
|
198
|
+
|
199
|
+
# In case were in monitor mode, end here
|
200
|
+
if @px_config[:module_mode] == PxModule::MONITOR_MODE && !px_ctx.context[:should_bypass_monitor]
|
201
|
+
@logger.debug("PerimeterX[handle_verification]: monitor mode is on, passing request")
|
202
|
+
return px_ctx
|
203
|
+
end
|
204
|
+
|
205
|
+
@logger.debug('PerimeterX[handle_verification]: verification ended, the request should be blocked')
|
206
|
+
|
207
|
+
return px_ctx
|
208
|
+
end
|
209
|
+
|
210
|
+
private def check_whitelist_routes(whitelist_routes, path)
|
211
|
+
whitelist_routes.each do |whitelist_route|
|
212
|
+
if whitelist_route.is_a?(Regexp) && path.match(whitelist_route)
|
213
|
+
return true
|
214
|
+
end
|
215
|
+
if whitelist_route.is_a?(String) && path.start_with?(whitelist_route)
|
216
|
+
return true
|
217
|
+
end
|
218
|
+
end
|
219
|
+
false
|
64
220
|
end
|
65
221
|
|
66
222
|
private_class_method :new
|
67
223
|
end
|
68
|
-
|
69
224
|
end
|