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,34 +1,55 @@
1
1
  require "perimeterx/utils/px_logger"
2
2
  require "httpclient"
3
3
 
4
- class PxHttpClient
5
- L = PxLogger.instance
6
- attr_accessor :px_config
7
- attr_accessor :BASE_URL
8
- attr_accessor :http_client
4
+ module PxModule
5
+ class PxHttpClient
6
+ attr_accessor :px_config
7
+ attr_accessor :BASE_URL
8
+ attr_accessor :http_client
9
9
 
10
- def initialize(px_config)
11
- L.info("PxHttpClient[initialize]: HTTP client is being initilized with base_uri: #{px_config['perimeterx_server_host']}")
12
- @px_config = px_config
13
- @http_client = HTTPClient.new(:base_url => px_config['perimeterx_server_host'])
14
- end
10
+ def initialize(px_config)
11
+ @px_config = px_config
12
+ @http_client = HTTPClient.new(:base_url => px_config[:perimeterx_server_host])
13
+ @logger = px_config[:logger]
14
+ @logger.debug("PxHttpClient[initialize]: HTTP client is being initilized with base_uri: #{px_config[:perimeterx_server_host]}")
15
+ end
15
16
 
16
- def post(path, body, headers, connection_timeout = 0, timeoute = 0)
17
- s = Time.now
18
- begin
19
- L.info("PxHttpClient[post]: posting to #{path} headers {#{headers.to_json()}} body: {#{body.to_json()}} ")
20
- response = @http_client.post(path,
21
- :header => headers,
22
- :body => body.to_json(),
23
- :timeout => @px_config['api_timeout']
24
- )
25
- rescue Net::OpenTimeout, Net::ReadTimeout => error
26
- L.warn("PerimeterxS2SValidator[verify]: request timedout")
27
- return false
17
+ def post(path, body, headers, api_timeout = 0, timeoute = 0)
18
+ s = Time.now
19
+ begin
20
+ @logger.debug("PxHttpClient[post]: posting to #{path} headers {#{headers.to_json()}} body: {#{body.to_json()}} ")
21
+ response = @http_client.post(path,
22
+ :header => headers,
23
+ :body => body.to_json(),
24
+ :timeout => api_timeout
25
+ )
26
+ rescue Net::OpenTimeout, Net::ReadTimeout => error
27
+ @logger.warn("PerimeterxS2SValidator[verify]: request timedout")
28
+ return false
29
+ end
30
+ e = Time.now
31
+ @logger.debug("PxHttpClient[post]: runtime: #{e-s}")
32
+ return response
28
33
  end
29
- e = Time.now
30
- L.info("PxHttpClient[post]: runtime: #{e-s}")
31
- return response
32
- end
33
34
 
35
+ def async_post(path, body, headers, api_timeout = 0, timeoute = 0)
36
+ @logger.debug("PxHttpClient[async_post]: posting to #{path} headers {#{headers.to_json()}} body: {#{body.to_json()}} ")
37
+ s = Time.now
38
+ begin
39
+ @logger.debug("PxHttpClient[post]: posting to #{path} headers {#{headers.to_json()}} body: {#{body.to_json()}} ")
40
+ response = @http_client.post_async(path,
41
+ :header => headers,
42
+ :body => body.to_json(),
43
+ :timeout => api_timeout
44
+ )
45
+ rescue Net::OpenTimeout, Net::ReadTimeout => error
46
+ @logger.warn("PerimeterxS2SValidator[verify]: request timedout")
47
+ return false
48
+ end
49
+ e = Time.now
50
+ @logger.debug("PxHttpClient[post]: runtime: #{e-s}")
51
+ return response
52
+ end
53
+
54
+ end
34
55
  end
@@ -1,11 +1,17 @@
1
1
  require 'logger'
2
+ module PxModule
2
3
 
3
- class PxLogger
4
- @@instance = Logger.new(STDOUT)
4
+ class PxLogger < Logger
5
5
 
6
- def self.instance
7
- return @@instance
8
- end
6
+ def initialize(debug)
7
+ if debug
8
+ super(STDOUT)
9
+ else
10
+ super(nil)
11
+ end
12
+
13
+ end
9
14
 
10
- private_class_method :new
15
+ end
16
+
11
17
  end
@@ -0,0 +1,31 @@
1
+ require 'mustache'
2
+ require 'perimeterx/utils/px_constants'
3
+ module PxModule
4
+ module PxTemplateFactory
5
+
6
+ def self.get_template(px_ctx, px_config)
7
+ logger = px_config[:logger]
8
+ if (px_config[:challenge_enabled] && px_ctx.context[:block_action] == "challenge")
9
+ logger.debug("PxTemplateFactory[get_template]: px challange triggered")
10
+ return px_ctx.context[:block_action_data].html_safe
11
+ end
12
+
13
+ logger.debug("PxTemplateFactory[get_template]: rendering template")
14
+ template_type = px_config[:captcha_enabled] ? PxModule::CAPTCHA_TEMPLATE : BLOCK_TEMPLATE
15
+
16
+ Mustache.template_file = "#{File.dirname(__FILE__) }/templates/#{template_type}"
17
+ view = Mustache.new
18
+
19
+ view[PxModule::PROP_APP_ID] = px_config[:app_id]
20
+ view[PxModule::PROP_REF_ID] = px_ctx.context[:uuid]
21
+ view[PxModule::PROP_VID] = px_ctx.context[:vid]
22
+ view[PxModule::PROP_UUID] = px_ctx.context[:uuid]
23
+ view[PxModule::PROP_CUSTOM_LOGO] = px_config[:custom_logo]
24
+ view[PxModule::PROP_CSS_REF] = px_config[:css_ref]
25
+ view[PxModule::PROP_JS_REF] = px_config[:js_ref]
26
+ view[PxModule::PROP_LOGO_VISIBILITY] = px_config[:custom_logo] ? PxModule::VISIBLE : PxModule::HIDDEN
27
+
28
+ return view.render.html_safe
29
+ end
30
+ end #end class
31
+ end #end module
@@ -0,0 +1,146 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Access to this page has been denied.</title>
7
+ <link href="https://fonts.googleapis.com/css?family=Open+Sans:300" rel="stylesheet">
8
+ <style>
9
+ html,body{
10
+ margin: 0;
11
+ padding: 0;
12
+ font-family: 'Open Sans', sans-serif;
13
+ color: #000;
14
+ }
15
+
16
+ a{
17
+ color: #c5c5c5;
18
+ text-decoration: none;
19
+ }
20
+
21
+ .container{
22
+ align-items: center;
23
+ display: flex;
24
+ flex: 1;
25
+ justify-content: space-between;
26
+ flex-direction: column;
27
+ height: 100%;
28
+ }
29
+
30
+ .container > div {
31
+ width: 100%;
32
+ display: flex;
33
+ justify-content:center;
34
+ }
35
+
36
+ .container > div > div {
37
+ display: flex;
38
+ width: 80%;
39
+ }
40
+
41
+ .customer-logo-wrapper{
42
+ padding-top: 2rem;
43
+ flex-grow: 0;
44
+ background-color: #fff;
45
+ visibility: {{logoVisibility}};
46
+ }
47
+
48
+ .customer-logo{
49
+ border-bottom: 1px solid #000;
50
+ }
51
+
52
+ .customer-logo > img{
53
+ padding-bottom: 1rem;
54
+ max-height: 50px;
55
+ max-width: auto;
56
+ }
57
+
58
+ .page-title-wrapper{
59
+ flex-grow: 2;
60
+ }
61
+ .page-title {
62
+ flex-direction: column-reverse;
63
+ }
64
+
65
+ .content-wrapper{
66
+ flex-grow: 5;
67
+ }
68
+ .content{
69
+ flex-direction: column;
70
+ }
71
+
72
+ .page-footer-wrapper{
73
+ align-items: center;
74
+ flex-grow: 0.2;
75
+ background-color: #000;
76
+ color: #c5c5c5;
77
+ font-size: 70%;
78
+ }
79
+ @media (min-width:768px){
80
+ html,body{
81
+ height: 100%;
82
+ }
83
+ }
84
+ </style>
85
+ <!-- Custom CSS -->
86
+ {{# cssRef }}
87
+ <link rel="stylesheet" type="text/css" href="{{cssRef}}" />
88
+ {{/ cssRef }}
89
+ </head>
90
+ <body>
91
+ <section class="container">
92
+ <div class="customer-logo-wrapper">
93
+ <div class="customer-logo">
94
+ <img src="{{customLogo}}" alt="Logo"/>
95
+ </div>
96
+ </div>
97
+ <div class="page-title-wrapper">
98
+ <div class="page-title">
99
+ <h1>Access to this page has been denied.</h1>
100
+ </div>
101
+ </div>
102
+ <div class="content-wrapper">
103
+ <div class="content">
104
+ <p>
105
+ You have been blocked because we believe you are using automation tools to browse the website.
106
+ </p>
107
+ <p>
108
+ Please note that Javascript and Cookies must be enabled on your browser to access the website.
109
+ </p>
110
+ <p>
111
+ If you think you have been blocked by mistake, please contact the website administrator with the reference ID below.
112
+ </p>
113
+ <p>
114
+ Reference ID: #{{refId}}
115
+ </p>
116
+ </div>
117
+ </div>
118
+ <div class="page-footer-wrapper">
119
+ <div class="page-footer">
120
+ <p>
121
+ Powered by
122
+ <a href="https://www.perimeterx.com">PerimeterX</a>
123
+ , Inc.
124
+ </p>
125
+ </div>
126
+ </div>
127
+ </section>
128
+ <!-- Px -->
129
+ <script>
130
+ (
131
+ function (){
132
+ window._pxAppId = '{{appId}}';
133
+ var p = document.getElementsByTagName("script")[0], s = document.createElement("script");
134
+
135
+ s.async = 1;
136
+ s.src = '//client.perimeterx.net/{{appId}}/main.min.js';
137
+ p.parentNode.insertBefore(s, p);
138
+ } ()
139
+ );
140
+ </script>
141
+ <!-- Custom Script -->
142
+ {{# jsRef }}
143
+ <script src="{{jsRef}}"></script>
144
+ {{/ jsRef }}
145
+ </body>
146
+ </html>
@@ -0,0 +1,185 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Access to this page has been denied.</title>
7
+ <link href="https://fonts.googleapis.com/css?family=Open+Sans:300" rel="stylesheet">
8
+ <style>
9
+ html,body{
10
+ margin: 0;
11
+ padding: 0;
12
+ font-family: 'Open Sans', sans-serif;
13
+ color: #000;
14
+ }
15
+
16
+ a{
17
+ color: #c5c5c5;
18
+ text-decoration: none;
19
+ }
20
+
21
+ .container{
22
+ align-items: center;
23
+ display: flex;
24
+ flex: 1;
25
+ justify-content: space-between;
26
+ flex-direction: column;
27
+ height: 100%;
28
+ }
29
+
30
+ .container > div {
31
+ width: 100%;
32
+ display: flex;
33
+ justify-content:center;
34
+ }
35
+
36
+ .container > div > div {
37
+ display: flex;
38
+ width: 80%;
39
+ }
40
+
41
+ .customer-logo-wrapper{
42
+ padding-top: 2rem;
43
+ flex-grow: 0;
44
+ background-color: #fff;
45
+ visibility: {{logoVisibility}};
46
+ }
47
+
48
+ .customer-logo{
49
+ border-bottom: 1px solid #000;
50
+ }
51
+
52
+ .customer-logo > img{
53
+ padding-bottom: 1rem;
54
+ max-height: 50px;
55
+ max-width: auto;
56
+ }
57
+
58
+ .page-title-wrapper{
59
+ flex-grow: 2;
60
+ }
61
+ .page-title {
62
+ flex-direction: column-reverse;
63
+ }
64
+
65
+ .content-wrapper{
66
+ flex-grow: 5;
67
+ }
68
+ .content{
69
+ flex-direction: column;
70
+ }
71
+
72
+ .page-footer-wrapper{
73
+ align-items: center;
74
+ flex-grow: 0.2;
75
+ background-color: #000;
76
+ color: #c5c5c5;
77
+ font-size: 70%;
78
+ }
79
+
80
+ @media (min-width:768px){
81
+ html,body{
82
+ height: 100%;
83
+ }
84
+ }
85
+ </style>
86
+ <!-- Custom CSS -->
87
+ {{#cssRef}}
88
+ <link rel="stylesheet" type="text/css" href="{{cssRef}}" />
89
+ {{/cssRef}}
90
+ <script src="https://www.google.com/recaptcha/api.js" async defer></script>
91
+ </head>
92
+
93
+ <body>
94
+ <section class="container">
95
+ <div class="customer-logo-wrapper">
96
+ <div class="customer-logo">
97
+ <img src="{{customLogo}}" alt="Logo"/>
98
+ </div>
99
+ </div>
100
+ <div class="page-title-wrapper">
101
+ <div class="page-title">
102
+ <h1>Please verify you are a human</h1>
103
+ </div>
104
+ </div>
105
+ <div class="content-wrapper">
106
+ <div class="content">
107
+ <p>
108
+ Please click "I am not a robot" to continue
109
+ </p>
110
+ <div class="g-recaptcha" data-sitekey="6Lcj-R8TAAAAABs3FrRPuQhLMbp5QrHsHufzLf7b" data-callback="handleCaptcha" data-theme="dark">
111
+ </div>
112
+ <p>
113
+ Access to this page has been denied because we believe you are using automation tools to browse the website.
114
+ </p>
115
+ <p>
116
+ This may happen as a result of the following:
117
+ </p>
118
+ <ul>
119
+ <li>
120
+ Javascript is disabled or blocked by an extension (ad blockers for example)
121
+ </li>
122
+ <li>
123
+ Your browser does not support cookies
124
+ </li>
125
+ </ul>
126
+ <p>
127
+ Please make sure that Javascript and cookies are enabled on your browser and that you are not blocking them from loading.
128
+ </p>
129
+ <p>
130
+ Reference ID: #{{refId}}
131
+ </p>
132
+ </div>
133
+ </div>
134
+ <div class="page-footer-wrapper">
135
+ <div class="page-footer">
136
+ <p>
137
+ Powered by
138
+ <a href="https://www.perimeterx.com">PerimeterX</a>
139
+ , Inc.
140
+ </p>
141
+ </div>
142
+ </div>
143
+ </section>
144
+ <!-- Px -->
145
+ <script>
146
+ (
147
+ function (){
148
+ window._pxAppId = '{{appId}}';
149
+ var p = document.getElementsByTagName("script")[0], s = document.createElement("script");
150
+
151
+ s.async = 1;
152
+ s.src = '//client.perimeterx.net/{{appId}}/main.min.js';
153
+ p.parentNode.insertBefore(s, p);
154
+ } ()
155
+ );
156
+ </script>
157
+ <!-- Captcha -->
158
+ <script>
159
+ window.px_vid = '{{vid}}';
160
+ function handleCaptcha(response){
161
+ var vid = '{{vid}}';
162
+ var uuid = '{{uuid}}';
163
+ var name = "_pxCaptcha";
164
+
165
+ var expiryUtc = new Date(Date.now()+1000*10).toUTCString();
166
+
167
+ var cookieParts = [
168
+ name,
169
+ "=",
170
+ response+":"+vid+":"+uuid,
171
+ "; expires=",
172
+ expiryUtc,
173
+ "; path=/"
174
+ ];
175
+
176
+ document.cookie = cookieParts.join("");
177
+ location.reload();
178
+ }
179
+ </script>
180
+ <!-- Custom Script -->
181
+ {{#jsRef}}
182
+ <script src="{{jsRef}}"></script>
183
+ {{/jsRef}}
184
+ </body>
185
+ </html>
@@ -1,3 +1,3 @@
1
- module PerimeterX
2
- VERSION = '1.0.4-alpha'
1
+ module PxModule
2
+ VERSION = '1.0.4'
3
3
  end
data/perimeter_x.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |gem|
9
9
  gem.description = "PerimeterX ruby module to monitor and block traffic according to PerimeterX risk score"
10
10
  gem.licenses = ['MIT']
11
11
  gem.homepage = "https://www.perimeterx.com"
12
- gem.version = PerimeterX::VERSION
12
+ gem.version = PxModule::VERSION
13
13
 
14
14
  gem.authors = ["Nitzan Goldfeder"]
15
15
  gem.email = "nitzan@perimeterx.com"
@@ -31,4 +31,9 @@ Gem::Specification.new do |gem|
31
31
  gem.required_ruby_version = '>= 2.3'
32
32
 
33
33
  gem.add_dependency('httpclient', '2.8.2.4')
34
+ gem.add_dependency('mustache', '~> 1.0', '>= 1.0.3')
35
+ gem.add_dependency('activesupport', '>= 4.2.0')
36
+
37
+ gem.add_development_dependency 'rspec', '~> 3.0'
38
+ gem.add_development_dependency 'mocha', '~> 1.2', '>= 1.2.1'
34
39
  end