perimeter_x 1.1.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.travis.yml +3 -0
  4. data/Dockerfile +19 -43
  5. data/Gemfile.lock +36 -30
  6. data/Rakefile +1 -0
  7. data/changelog.md +63 -0
  8. data/examples/app/controllers/home_controller.rb +1 -1
  9. data/lib/perimeter_x.rb +152 -70
  10. data/lib/perimeterx/configuration.rb +71 -22
  11. data/lib/perimeterx/internal/clients/perimeter_x_activity_client.rb +36 -15
  12. data/lib/perimeterx/internal/exceptions/px_config_exception.rb +6 -0
  13. data/lib/perimeterx/internal/{perimeter_x_cookie_v1.rb → payload/perimeter_x_cookie_v1.rb} +1 -1
  14. data/lib/perimeterx/internal/{perimeter_x_cookie_v3.rb → payload/perimeter_x_cookie_v3.rb} +1 -1
  15. data/lib/perimeterx/internal/{perimeter_x_cookie.rb → payload/perimeter_x_payload.rb} +12 -4
  16. data/lib/perimeterx/internal/payload/perimeter_x_token_v1.rb +38 -0
  17. data/lib/perimeterx/internal/payload/perimeter_x_token_v3.rb +36 -0
  18. data/lib/perimeterx/internal/perimeter_x_context.rb +66 -31
  19. data/lib/perimeterx/internal/validators/hash_schema_validator.rb +26 -0
  20. data/lib/perimeterx/internal/validators/perimeter_x_cookie_validator.rb +29 -21
  21. data/lib/perimeterx/internal/validators/perimeter_x_s2s_validator.rb +34 -10
  22. data/lib/perimeterx/utils/px_constants.rb +35 -17
  23. data/lib/perimeterx/utils/px_http_client.rb +29 -35
  24. data/lib/perimeterx/utils/px_template_factory.rb +18 -8
  25. data/lib/perimeterx/utils/templates/block_template.mustache +175 -0
  26. data/lib/perimeterx/utils/templates/ratelimit.mustache +9 -0
  27. data/lib/perimeterx/version.rb +1 -1
  28. data/perimeter_x.gemspec +5 -4
  29. data/readme.md +95 -32
  30. metadata +53 -24
  31. data/lib/perimeterx/internal/validators/perimeter_x_captcha_validator.rb +0 -65
  32. data/lib/perimeterx/utils/templates/block.mustache +0 -146
  33. data/lib/perimeterx/utils/templates/captcha.mustache +0 -185
@@ -0,0 +1,9 @@
1
+ <html>
2
+ <head>
3
+ <title>Too Many Requests</title>
4
+ </head>
5
+ <body>
6
+ <h1>Too Many Requests</h1>
7
+ <p>Reached maximum requests limitation, try again soon.</p>
8
+ </body>
9
+ </html>
@@ -1,3 +1,3 @@
1
1
  module PxModule
2
- VERSION = '1.1.0'
2
+ VERSION = '2.1.0'
3
3
  end
@@ -22,17 +22,18 @@ Gem::Specification.new do |gem|
22
22
  gem.bindir = "exe"
23
23
  gem.executables = gem.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
24
  gem.require_paths = ["lib"]
25
- gem.add_development_dependency "bundler", "~> 1.14"
26
- gem.add_development_dependency "rake", "~> 10.0"
25
+ gem.add_development_dependency "bundler", ">= 2.1"
26
+ gem.add_development_dependency "rake", ">= 12.3"
27
27
 
28
28
  gem.extra_rdoc_files = ["readme.md", "changelog.md"]
29
29
  gem.rdoc_options = ["--line-numbers", "--inline-source", "--title", "PerimeterX"]
30
30
 
31
31
  gem.required_ruby_version = '>= 2.3'
32
32
 
33
- gem.add_dependency('httpclient', '2.8.2.4')
33
+ gem.add_dependency('concurrent-ruby', '~> 1.0', '>= 1.0.5')
34
+ gem.add_dependency('typhoeus', '~> 1.1', '>= 1.1.2')
34
35
  gem.add_dependency('mustache', '~> 1.0', '>= 1.0.3')
35
- gem.add_dependency('activesupport', '>= 4.2.0')
36
+ gem.add_dependency('activesupport', '>= 5.2.4.3')
36
37
 
37
38
  gem.add_development_dependency 'rspec', '~> 3.0'
38
39
  gem.add_development_dependency 'mocha', '~> 1.2', '>= 1.2.1'
data/readme.md CHANGED
@@ -1,20 +1,26 @@
1
- ![image](http://media.marketwire.com/attachments/201604/34215_PerimeterX_logo.jpg)
1
+ [![Build Status](https://travis-ci.org/PerimeterX/perimeterx-ruby-sdk.svg?branch=master)](https://travis-ci.org/PerimeterX/perimeterx-ruby-sdk)
2
+
3
+ ![image](https://storage.googleapis.com/perimeterx-logos/primary_logo_red_cropped.png)
2
4
  #
3
5
  [PerimeterX](http://www.perimeterx.com) Ruby SDK
4
6
  =============================================================
5
7
 
8
+ > Latest stable version: [v2.1.0](https://rubygems.org/gems/perimeter_x)
9
+
6
10
  Table of Contents
7
11
  -----------------
8
- - [Usage](#usage)
12
+ **[Usage](#usage)**
9
13
  * [Dependencies](#dependencies)
10
14
  * [Installation](#installation)
11
15
  * [Basic Usage Example](#basic-usage)
12
- - [Configuration](#configuration)
16
+
17
+ **[Configuration](#configuration)**
13
18
  * [Configuring Required Parameters](#requireied-params)
14
19
  * [Blocking Score](#blocking-score)
20
+ * [Custom Verification Action](#custom-verification-action)
15
21
  * [Custom Block Page](#custom-block-page)
16
- * [Custom Block Action](#custom-block-action)
17
22
  * [Enable/Disable Captcha](#captcha-support)
23
+ * [Select Captcha Provider](#captcha-provider)
18
24
  * [Extracting Real IP Address](#real-ip)
19
25
  * [Custom URI](#custom-uri)
20
26
  * [Filter Sensitive Headers](#sensitive-headers)
@@ -23,7 +29,10 @@ Table of Contents
23
29
  * [Additional Page Activity Handler](#additional-page-activity-handler)
24
30
  * [Monitor Only](#logging)
25
31
  * [Debug Mode](#debug-mode)
26
- - [Contributing](#contributing)
32
+ * [Whitelist Routes](#whitelist-routes)
33
+ * [Update Configuration on Runtime](#update-config)
34
+
35
+ **[Contributing](#contributing)**
27
36
 
28
37
  <a name="Usage"></a>
29
38
  <a name="dependencies"></a> Dependencies
@@ -31,7 +40,8 @@ Table of Contents
31
40
 
32
41
  - Ruby version 2.3+
33
42
  - Rails version 4.2
34
- - [httpclient](https://rubygems.org/gems/httpclient/versions/2.8.3)
43
+ - [concurrent-ruby](https://github.com/ruby-concurrency/concurrent-ruby)
44
+ - [typhoeus](https://github.com/typhoeus/typhoeus)
35
45
  - [mustache](https://rubygems.org/gems/mustache)
36
46
 
37
47
  <a name="installation"></a> Installation
@@ -60,7 +70,7 @@ On the Rails controller include the PerimeterX SDK via the before_action and cal
60
70
  class HomeController < ApplicationController
61
71
  include PxModule
62
72
 
63
- before_filter :px_verify_request
73
+ before_action :px_verify_request
64
74
  ...
65
75
  ...
66
76
  end
@@ -79,7 +89,7 @@ All parameters are obtainable via the PerimeterX Portal. (Applications and Polic
79
89
 
80
90
  <a name="blocking-score"></a>**Changing the Minimum Score for Blocking**
81
91
 
82
- >Note: Default blocking value: 70
92
+ >Note: Default blocking value: 100
83
93
 
84
94
  ```ruby
85
95
  params = {
@@ -89,69 +99,71 @@ params = {
89
99
  }
90
100
  ```
91
101
 
102
+ <a name="custom-verification-action"></a>**Custom Verification Handler**
92
103
 
104
+ > Note: This handler replaces the now deprecated `custom_block_handler`.
93
105
 
94
- <a name="custom-block-action"></a>**Custom Verification Handler**
95
-
96
- A custom verification handler is being executed inside ``px_verify_request`` instead of the the default behavior and allows a user to use a custom action based on the risk score returned by PerimeterX.
106
+ A custom verification handler is being executed inside `px_verify_request` instead of the the default behavior and allows a user to use a custom action based on the risk score returned by PerimeterX.
97
107
 
98
- When implemented, this method receives a hash variable as input which represents data from the PerimeterX context of the request (px_ctx).
108
+ When implemented, this method receives a hash variable as input which represents data from the PerimeterX context of the request (px_ctx).
99
109
 
100
- - `px_ctx[:score] ` contains the risk score
101
- - `px_ctx[:uuid] ` contains the request UUID
110
+ - `px_ctx.context[:score]` - contains the risk score
111
+ - `px_ctx.context[:uuid]` - contains the request UUID
112
+ - `px_ctx.context[:verified]` - contains indication whether the request passed verification or was blocked (inspect `px_ctx.context[:block_reason]` for block reason)
102
113
 
103
- >> Note: to determine whether to return a captcha/block page (HTML) or block JSON payload a reference key on the context will be available: ```px_ctx.context[:format]```
114
+ > Note: to determine whether to return a captcha/block page (HTML) or block JSON payload a reference key on the context will be available: ```px_ctx.context[:format]```
104
115
 
105
116
  To replace the default verification behavior, add the configuration a lambda member as shown in the example below.
106
117
 
107
- The method must return boolen value.
108
-
109
118
  ```ruby
110
119
  params = {
111
120
  :app_id => <APP_ID>,
112
121
  :auth_token => <AUTH_TOKEN>,
113
- :custom_block_handler => -> (px_ctx) {
122
+ :custom_verification_handler => -> (px_ctx) {
114
123
  if px_ctx.context[:score] >= 60
115
- # take your action and retun a message or JSON with a status code of 403 and option UUID of the request. Can return false and include action in the px_middleware method.
124
+ # take your action and render an html page or JSON with applicable status code.
125
+ render json: { :score => px_ctx.context[:score] }
116
126
  end
117
- return true
118
127
  }
119
128
  }
120
129
  ```
121
130
 
131
+ > Note: Unlike previous versions, the method no longer needs to return a boolean value.
132
+
122
133
  **Example**
123
- ### Serving a Custom HTML Page ###
134
+ #### Serving a Custom HTML Page ####
124
135
  ```ruby
125
136
 
126
- params[:custom_block_handler] = -> (px_ctx)
127
- {
137
+ params = {
138
+ :app_id => <APP_ID>,
139
+ :auth_token => <AUTH_TOKEN>,
140
+ ...
141
+ :custom_verification_handler => -> (px_ctx) {
128
142
  block_score = px_ctx.context[:score];
129
- block_uuid = px_ctx.context[:uuid];
143
+ client_uuid = px_ctx.context[:uuid];
130
144
  full_url = px_ctx.context[:full_url];
131
145
 
132
146
  html = "<html>
133
147
  <body>
134
148
  <div>Access to #{full_url} has been blocked.</div>
135
- <div>Block reference - #{block_uuid} </div>
149
+ <div>Block reference - #{client_uuid} </div>
136
150
  <div>Block score - #{block_score} </div>
137
151
  </body>
138
152
  </html>".html_safe
139
153
  response.headers["Content-Type"] = "text/html"
140
154
  response.status = 403
141
155
  render :html => html
142
- return false
143
- };
144
-
145
- PxModule.configure(params)
156
+ }
157
+ }
146
158
  ```
147
159
 
148
- <a name="real-ip"></a>** Custom User IP **
160
+ <a name="real-ip"></a>**Custom User IP**
149
161
 
150
162
  > Note: IP extraction, according to your network setup, is very important. It is common to have a load balancer/proxy on top of your applications, in which case the PerimeterX module will send the system's internal IP as the user's. In order to properly perform processing and detection on server-to-server calls, PerimeterX module needs the real user's IP.
151
163
 
152
164
  By default the clients IP is taken from the ``REMOTE_ADDR`` header, in case the user decides to use different header or custom function that extract the header the following key should be added to the configuration
153
165
 
154
- *** Custom header ***
166
+ ***Custom header***
155
167
  ```ruby
156
168
  configuration = {
157
169
  "app_id" => <APP_ID>,
@@ -159,7 +171,7 @@ configuration = {
159
171
  "custom_user_ip" => <HTTP_HEADER_NAME>,
160
172
  ```
161
173
 
162
- *** Custom Function ***
174
+ ***Custom Function***
163
175
  > Note: the function receive as a first parameter the controller request and must return the ip at the end as string
164
176
 
165
177
  ```ruby
@@ -221,6 +233,17 @@ By enabling CAPTCHA support, a CAPTCHA will be served as part of the block page,
221
233
  params[:captcha_enabled] = false
222
234
  ```
223
235
 
236
+ <a name="captcha-provider"></a>**Select CAPTCHA Provider**
237
+
238
+ The CAPTCHA part of the block page can use one of the following:
239
+ * [reCAPTCHA](https://www.google.com/recaptcha)
240
+
241
+ Default: 'reCaptcha'
242
+
243
+ ```ruby
244
+ captchaProvider = "reCaptcha"
245
+ ```
246
+
224
247
  <a name="custom-uri"></a>**Custom URI**
225
248
 
226
249
  Default: 'REQUEST_URI'
@@ -284,6 +307,46 @@ Enables debug logging mode to STDOUT
284
307
  params[:debug] = true
285
308
  ```
286
309
 
310
+ <a name="whitelist-routes"></a>**Whitelist Routes**
311
+ Default: []
312
+
313
+ An array of route prefixes and/or regular expressions that are always whitelisted and not validated by PerimeterX.
314
+ A string value of a path will be treated as a prefix.
315
+ A regexp value of a path will be treated as is.
316
+
317
+ ```ruby
318
+ params[:whitelist_routes] = ["/example", /\A\/example\z/]
319
+ ```
320
+
321
+ <a name="update-config"></a>**Update Configuration on Runtime**
322
+
323
+ As mentioned before, PerimeterX Module should be configured in `<rails_app>/config/initializers/perimeterx.rb`.
324
+ However, it is possible to override configuration options on each request.
325
+ To do so, send the configuration options as an argument when calling to `px_verify_request` as described in the following example.
326
+ Notice that in case of an invalid argument, the module will raise an error. Therefore, when using this feature, make sure to wrap the call to `px_verify_request` with begin and rescue. It is highly recommended to log the error message to follow such errors.
327
+
328
+ ```ruby
329
+ class HomeController < ApplicationController
330
+ include PxModule
331
+
332
+
333
+ before_action do call_perimeterx_verify_request end
334
+
335
+ def call_perimeterx_verify_request
336
+ params = {
337
+ :blocking_score => 70,
338
+ :module_mode => 2
339
+ }
340
+ begin
341
+ px_verify_request(params)
342
+ rescue StandardError => e
343
+ # $stdout.write(e.message)
344
+ end
345
+ end
346
+
347
+ end
348
+ ```
349
+
287
350
  <a name="contributing"></a># Contributing #
288
351
  ------------------------------
289
352
  The following steps are welcome when contributing to our project.
metadata CHANGED
@@ -1,57 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perimeter_x
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.1.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: 2017-06-04 00:00:00.000000000 Z
11
+ date: 2020-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.14'
19
+ version: '2.1'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.14'
26
+ version: '2.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '12.3'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '12.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: concurrent-ruby
43
+ requirement: !ruby/object:Gem::Requirement
37
44
  requirements:
38
45
  - - "~>"
39
46
  - !ruby/object:Gem::Version
40
- version: '10.0'
47
+ version: '1.0'
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 1.0.5
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '1.0'
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.0.5
41
61
  - !ruby/object:Gem::Dependency
42
- name: httpclient
62
+ name: typhoeus
43
63
  requirement: !ruby/object:Gem::Requirement
44
64
  requirements:
45
- - - '='
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.1'
68
+ - - ">="
46
69
  - !ruby/object:Gem::Version
47
- version: 2.8.2.4
70
+ version: 1.1.2
48
71
  type: :runtime
49
72
  prerelease: false
50
73
  version_requirements: !ruby/object:Gem::Requirement
51
74
  requirements:
52
- - - '='
75
+ - - "~>"
76
+ - !ruby/object:Gem::Version
77
+ version: '1.1'
78
+ - - ">="
53
79
  - !ruby/object:Gem::Version
54
- version: 2.8.2.4
80
+ version: 1.1.2
55
81
  - !ruby/object:Gem::Dependency
56
82
  name: mustache
57
83
  requirement: !ruby/object:Gem::Requirement
@@ -78,14 +104,14 @@ dependencies:
78
104
  requirements:
79
105
  - - ">="
80
106
  - !ruby/object:Gem::Version
81
- version: 4.2.0
107
+ version: 5.2.4.3
82
108
  type: :runtime
83
109
  prerelease: false
84
110
  version_requirements: !ruby/object:Gem::Requirement
85
111
  requirements:
86
112
  - - ">="
87
113
  - !ruby/object:Gem::Version
88
- version: 4.2.0
114
+ version: 5.2.4.3
89
115
  - !ruby/object:Gem::Dependency
90
116
  name: rspec
91
117
  requirement: !ruby/object:Gem::Requirement
@@ -130,6 +156,7 @@ extra_rdoc_files:
130
156
  - changelog.md
131
157
  files:
132
158
  - ".gitignore"
159
+ - ".travis.yml"
133
160
  - Dockerfile
134
161
  - Gemfile
135
162
  - Gemfile.lock
@@ -144,20 +171,23 @@ files:
144
171
  - lib/perimeterx/configuration.rb
145
172
  - lib/perimeterx/internal/clients/perimeter_x_activity_client.rb
146
173
  - lib/perimeterx/internal/clients/perimeter_x_risk_client.rb
174
+ - lib/perimeterx/internal/exceptions/px_config_exception.rb
147
175
  - lib/perimeterx/internal/exceptions/px_cookie_decryption_exception.rb
176
+ - lib/perimeterx/internal/payload/perimeter_x_cookie_v1.rb
177
+ - lib/perimeterx/internal/payload/perimeter_x_cookie_v3.rb
178
+ - lib/perimeterx/internal/payload/perimeter_x_payload.rb
179
+ - lib/perimeterx/internal/payload/perimeter_x_token_v1.rb
180
+ - lib/perimeterx/internal/payload/perimeter_x_token_v3.rb
148
181
  - lib/perimeterx/internal/perimeter_x_context.rb
149
- - lib/perimeterx/internal/perimeter_x_cookie.rb
150
- - lib/perimeterx/internal/perimeter_x_cookie_v1.rb
151
- - lib/perimeterx/internal/perimeter_x_cookie_v3.rb
152
- - lib/perimeterx/internal/validators/perimeter_x_captcha_validator.rb
182
+ - lib/perimeterx/internal/validators/hash_schema_validator.rb
153
183
  - lib/perimeterx/internal/validators/perimeter_x_cookie_validator.rb
154
184
  - lib/perimeterx/internal/validators/perimeter_x_s2s_validator.rb
155
185
  - lib/perimeterx/utils/px_constants.rb
156
186
  - lib/perimeterx/utils/px_http_client.rb
157
187
  - lib/perimeterx/utils/px_logger.rb
158
188
  - lib/perimeterx/utils/px_template_factory.rb
159
- - lib/perimeterx/utils/templates/block.mustache
160
- - lib/perimeterx/utils/templates/captcha.mustache
189
+ - lib/perimeterx/utils/templates/block_template.mustache
190
+ - lib/perimeterx/utils/templates/ratelimit.mustache
161
191
  - lib/perimeterx/version.rb
162
192
  - perimeter_x.gemspec
163
193
  - readme.md
@@ -184,8 +214,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
214
  - !ruby/object:Gem::Version
185
215
  version: '0'
186
216
  requirements: []
187
- rubyforge_project:
188
- rubygems_version: 2.6.11
217
+ rubygems_version: 3.0.3
189
218
  signing_key:
190
219
  specification_version: 4
191
220
  summary: PerimeterX ruby implmentation
@@ -1,65 +0,0 @@
1
- require 'perimeterx/internal/clients/perimeter_x_risk_client'
2
-
3
- module PxModule
4
- class PerimeterxCaptchaValidator < PerimeterxRiskClient
5
-
6
- def initialize(px_config, http_client)
7
- super(px_config, http_client)
8
- end
9
-
10
- def send_captcha_request(vid, uuid, captcha, px_ctx)
11
-
12
- request_body = {
13
- :request => {
14
- :ip => px_ctx.context[:ip],
15
- :headers => format_headers(px_ctx),
16
- :uri => px_ctx.context[:uri]
17
- },
18
- :pxCaptcha => captcha,
19
- :vid => vid,
20
- :uuid => uuid,
21
- :hostname => px_ctx.context[:hostname]
22
- }
23
-
24
- # Prepare request
25
- headers = {
26
- "Authorization" => "Bearer #{@px_config[:auth_token]}" ,
27
- "Content-Type" => "application/json"
28
- };
29
-
30
- return @http_client.post(PxModule::API_V1_CAPTCHA, request_body, headers, @px_config[:api_timeout])
31
-
32
- end
33
-
34
- def verify(px_ctx)
35
- captcha_validated = false
36
- begin
37
- if(!px_ctx.context.key?(:px_captcha))
38
- return captcha_validated, px_ctx
39
- end
40
- captcha, vid, uuid = px_ctx.context[:px_captcha].split(':', 3)
41
- if captcha.nil? || vid.nil? || uuid.nil?
42
- return captcha_validated, px_ctx
43
- end
44
-
45
- px_ctx.context[:vid] = vid
46
- px_ctx.context[:uuid] = uuid
47
- response = send_captcha_request(vid, uuid, captcha, px_ctx)
48
-
49
- if (response.status_code == 200)
50
- response_body = eval(response.body)
51
- if ( response_body[:status] == 0 )
52
- captcha_validated = true
53
- end
54
- end
55
-
56
- return captcha_validated, px_ctx
57
-
58
- rescue Exception => e
59
- @logger.error("PerimeterxCaptchaValidator[verify]: failed, returning false")
60
- return captcha_validated, px_ctx
61
- end
62
- end
63
-
64
- end
65
- end