perimeter_x 1.0.1

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 +7 -0
  2. data/.gitignore +47 -0
  3. data/Dockerfile +50 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +55 -0
  6. data/LICENSE.txt +18 -0
  7. data/Rakefile +9 -0
  8. data/changelog.md +0 -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/examples/config/routes.rb +62 -0
  13. data/lib/perimeter_x.rb +149 -0
  14. data/lib/perimeterx/configuration.rb +37 -0
  15. data/lib/perimeterx/internal/clients/perimeter_x_activity_client.rb +92 -0
  16. data/lib/perimeterx/internal/clients/perimeter_x_risk_client.rb +28 -0
  17. data/lib/perimeterx/internal/exceptions/px_cookie_decryption_exception.rb +5 -0
  18. data/lib/perimeterx/internal/perimeter_x_context.rb +82 -0
  19. data/lib/perimeterx/internal/perimeter_x_cookie.rb +140 -0
  20. data/lib/perimeterx/internal/perimeter_x_cookie_v1.rb +42 -0
  21. data/lib/perimeterx/internal/perimeter_x_cookie_v3.rb +37 -0
  22. data/lib/perimeterx/internal/validators/perimeter_x_captcha_validator.rb +65 -0
  23. data/lib/perimeterx/internal/validators/perimeter_x_cookie_validator.rb +69 -0
  24. data/lib/perimeterx/internal/validators/perimeter_x_s2s_validator.rb +110 -0
  25. data/lib/perimeterx/utils/px_constants.rb +42 -0
  26. data/lib/perimeterx/utils/px_http_client.rb +55 -0
  27. data/lib/perimeterx/utils/px_logger.rb +17 -0
  28. data/lib/perimeterx/utils/px_template_factory.rb +31 -0
  29. data/lib/perimeterx/utils/templates/block.mustache +146 -0
  30. data/lib/perimeterx/utils/templates/captcha.mustache +185 -0
  31. data/lib/perimeterx/version.rb +3 -0
  32. data/perimeter_x.gemspec +39 -0
  33. data/readme.md +294 -0
  34. metadata +192 -0
@@ -0,0 +1,82 @@
1
+ require 'perimeterx/utils/px_logger'
2
+
3
+ module PxModule
4
+ class PerimeterXContext
5
+
6
+ attr_accessor :context
7
+ attr_accessor :px_config
8
+
9
+ def initialize(px_config, req)
10
+ @logger = px_config[:logger];
11
+ @logger.debug("PerimeterXContext[initialize] ")
12
+ @context = Hash.new
13
+
14
+ @context[:px_cookie] = Hash.new
15
+ @context[:headers] = Hash.new
16
+ cookies = req.cookies
17
+ if (!cookies.empty?)
18
+ # Prepare hashed cookies
19
+ cookies.each do |k, v|
20
+ case k.to_s
21
+ when "_px3"
22
+ @context[:px_cookie][:v3] = v
23
+ when "_px"
24
+ @context[:px_cookie][:v1] = v
25
+ when "_pxCaptcha"
26
+ @context[:px_captcha] = v
27
+ end
28
+ end #end case
29
+ end #end empty cookies
30
+
31
+ req.headers.each do |k, v|
32
+ if (k.start_with? "HTTP_")
33
+ header = k.to_s.gsub("HTTP_", "")
34
+ header = header.gsub("_", "-").downcase
35
+ @context[:headers][header.to_sym] = v
36
+ end
37
+ end #end headers foreach
38
+
39
+ @context[:hostname]= req.server_name
40
+ @context[:user_agent] = req.user_agent ? req.user_agent : ''
41
+ @context[:uri] = px_config[:custom_uri] ? px_config[:custom_uri].call(req) : req.headers['REQUEST_URI']
42
+ @context[:full_url] = req.original_url
43
+ @context[:score] = 0
44
+
45
+ if px_config.key?(:custom_user_ip)
46
+ @context[:ip] = req.headers[px_config[:custom_user_ip]]
47
+ elsif px_config.key?(:px_custom_user_ip_method)
48
+ @context[:ip] = px_config[:px_custom_user_ip_method].call(req)
49
+ else
50
+ @context[:ip] = req.ip
51
+ end
52
+
53
+ if req.server_protocol
54
+ httpVer = req.server_protocol.split("/")
55
+ if httpVer.size > 0
56
+ @context[:http_version] = httpVer[1];
57
+ end
58
+ end
59
+ @context[:http_method] = req.method
60
+
61
+ end #end init
62
+
63
+ def set_block_action_type(action)
64
+ @context[:block_action] = case action
65
+ when "c"
66
+ "captcha"
67
+ when "b"
68
+ return "block"
69
+ when "j"
70
+ return "challenge"
71
+ else
72
+ return "captcha"
73
+ end
74
+ end
75
+
76
+ def get_px_cookie
77
+ cookie = @context[:px_cookie].key?(:v3) ? @context[:px_cookie][:v3] : @context[:px_cookie][:v1]
78
+ return cookie.tr(' ','+') if !cookie.nil?
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,140 @@
1
+ require 'active_support/security_utils'
2
+ require 'base64'
3
+ require 'openssl'
4
+ require 'perimeterx/internal/exceptions/px_cookie_decryption_exception'
5
+
6
+ module PxModule
7
+ class PerimeterxCookie
8
+ attr_accessor :px_cookie, :px_config, :px_ctx, :cookie_secret, :decoded_cookie
9
+
10
+ def initialize(px_config)
11
+ @px_config = px_config
12
+ @logger = px_config[:logger]
13
+ end
14
+
15
+ def self.px_cookie_factory(px_ctx, px_config)
16
+ if (px_ctx.context[:px_cookie].key?(:v3))
17
+ return PerimeterxCookieV3.new(px_config, px_ctx)
18
+ end
19
+ return PerimeterxCookieV1.new(px_config, px_ctx)
20
+ end
21
+
22
+ def cookie_score
23
+ #abstract, must be implemented
24
+ raise Exception.new("Unimplemented method")
25
+ end
26
+
27
+ def cookie_hmac
28
+ #abstract, must be implemented
29
+ raise Exception.new("Unimplemented method")
30
+ end
31
+
32
+ def valid_format?(cookie)
33
+ #abstract, must be implemented
34
+ raise Exception.new("Unimplemented method")
35
+ end
36
+
37
+ def cookie_block_action
38
+ #abstract, must be implemented
39
+ raise Exception.new("Unimplemented method")
40
+ end
41
+
42
+ def secured?
43
+ #abstract, must be implemented
44
+ raise Exception.new("Unimplemented method")
45
+ end
46
+
47
+ def is_valid?
48
+ return deserialize && !expired? && secured?
49
+ end
50
+
51
+ def cookie_time
52
+ return @decoded_cookie[:t]
53
+ end
54
+
55
+ def cookie_uuid
56
+ return @decoded_cookie[:u]
57
+ end
58
+
59
+ def cookie_vid
60
+ return @decoded_cookie[:v]
61
+ end
62
+
63
+ def high_score?
64
+ return cookie_score >= @px_config[:blocking_score]
65
+ end
66
+
67
+ def expired?
68
+ return cookie_time < (Time.now.to_f*1000).floor
69
+ end
70
+
71
+
72
+ def deserialize
73
+ if (!@decoded_cookie.nil?)
74
+ return true
75
+ end
76
+
77
+ # Decode or decrypt, depends on configuration
78
+ if (@px_config[:encryption_enabled])
79
+ cookie = decrypt(@px_cookie)
80
+ else
81
+ cookie = decode(@px_cookie)
82
+ end
83
+
84
+ if (cookie.nil?)
85
+ return false
86
+ end
87
+
88
+ if (!valid_format?(cookie))
89
+ return false
90
+ end
91
+
92
+ @decoded_cookie = cookie
93
+
94
+ return true
95
+ end
96
+
97
+
98
+ def decrypt(px_cookie)
99
+ begin
100
+ if (px_cookie.nil?)
101
+ return
102
+ end
103
+ px_cookie = px_cookie.gsub(' ', '+')
104
+ salt, iterations, cipher_text = px_cookie.split(':')
105
+ iterations = iterations.to_i
106
+ salt = Base64.decode64(salt)
107
+ cipher_text = Base64.decode64(cipher_text)
108
+ digest = OpenSSL::Digest::SHA256.new
109
+ value = OpenSSL::PKCS5.pbkdf2_hmac(@px_config[:cookie_key], salt, iterations, 48, digest)
110
+ key = value[0..31]
111
+ iv = value[32..-1]
112
+ cipher = OpenSSL::Cipher::AES256.new(:CBC)
113
+ cipher.decrypt
114
+ cipher.key = key
115
+ cipher.iv = iv
116
+ plaintext = cipher.update(cipher_text) + cipher.final
117
+
118
+ return eval(plaintext)
119
+ rescue Exception => e
120
+ @logger.debug("PerimeterxCookie[decrypt]: Cookie decrypt fail #{e.message}")
121
+ raise PxCookieDecryptionException.new("Cookie decrypt fail => #{e.message}");
122
+ end
123
+ end
124
+
125
+ def decode(px_cookie)
126
+ return eval(Base64.decode64(px_cookie))
127
+ end
128
+
129
+
130
+ def hmac_valid?(hmac_str, cookie_hmac)
131
+ hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, @cookie_secret, hmac_str)
132
+ # ref: https://thisdata.com/blog/timing-attacks-against-string-comparison/
133
+ password_correct = ActiveSupport::SecurityUtils.secure_compare(
134
+ ::Digest::SHA256.hexdigest(cookie_hmac),
135
+ ::Digest::SHA256.hexdigest(hmac)
136
+ )
137
+
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,42 @@
1
+ module PxModule
2
+ class PerimeterxCookieV1 < PerimeterxCookie
3
+
4
+ attr_accessor :px_config, :px_ctx
5
+
6
+ def initialize(px_config, px_ctx)
7
+ super(px_config)
8
+ @px_ctx = px_ctx
9
+ @px_cookie = px_ctx.get_px_cookie
10
+ @cookie_secret = px_config[:cookie_key]
11
+ @logger.debug("PerimeterxCookieV1[initialize]")
12
+ end
13
+
14
+ def cookie_score
15
+ return @decoded_cookie[:s][:b]
16
+ end
17
+
18
+ def cookie_hmac
19
+ return @decoded_cookie[:h]
20
+ end
21
+
22
+ def valid_format?(cookie)
23
+ return cookie.key?(:t) && cookie.key?(:s) && cookie[:s].key?(:b) && cookie.key?(:s) && cookie.key?(:v) && cookie.key?(:h)
24
+ end
25
+
26
+ def cookie_block_action
27
+ return 'c'
28
+ end
29
+
30
+ def secured?
31
+ base_hmac_str = "#{cookie_time}#{@decoded_cookie[:s][:a]}#{cookie_score}#{cookie_uuid}#{cookie_vid}"
32
+
33
+ hmac_str_withip = "#{base_hmac_str}#{@px_ctx.context[:ip]}#{@px_ctx.context[:user_agent]}"
34
+
35
+ hmac_str_withoutip = "#{base_hmac_str}#{@px_ctx.context[:user_agent]}"
36
+
37
+ return (hmac_valid?(hmac_str_withoutip, cookie_hmac) || hmac_valid?(hmac_str_withip, cookie_hmac))
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,37 @@
1
+ module PxModule
2
+ class PerimeterxCookieV3 < PerimeterxCookie
3
+
4
+ attr_accessor :px_config, :px_ctx, :cookie_hash
5
+
6
+ def initialize(px_config, px_ctx)
7
+ super(px_config)
8
+ hash, cookie = px_ctx.get_px_cookie().split(':', 2)
9
+ @px_cookie = cookie
10
+ @cookie_hash = hash
11
+ @px_ctx = px_ctx
12
+ @cookie_secret = px_config[:cookie_key]
13
+ @logger.debug("PerimeterxCookieV3[initialize]")
14
+ end
15
+
16
+ def cookie_score
17
+ return @decoded_cookie[:s]
18
+ end
19
+
20
+ def cookie_hmac
21
+ return @cookie_hash
22
+ end
23
+
24
+ def valid_format?(cookie)
25
+ return cookie.key?(:t) && cookie.key?(:s) && cookie.key?(:u) && cookie.key?(:u) && cookie.key?(:a)
26
+ end
27
+
28
+ def cookie_block_action
29
+ @decoded_cookie[:a]
30
+ end
31
+
32
+ def secured?
33
+ hmac_string = "#{@px_cookie}#{@px_ctx.context[:user_agent]}"
34
+ return hmac_valid?(hmac_string, cookie_hmac)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,65 @@
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
@@ -0,0 +1,69 @@
1
+ require 'perimeterx/utils/px_constants'
2
+ require 'perimeterx/internal/perimeter_x_cookie'
3
+ require 'perimeterx/internal/perimeter_x_cookie_v1'
4
+ require 'perimeterx/internal/perimeter_x_cookie_v3'
5
+
6
+ module PxModule
7
+ class PerimeterxCookieValidator
8
+
9
+ attr_accessor :px_config
10
+
11
+ def initialize(px_config)
12
+ @px_config = px_config
13
+ @logger = px_config[:logger]
14
+ end
15
+
16
+
17
+ def verify(px_ctx)
18
+ begin
19
+ # Case no cookie
20
+ if px_ctx.context[:px_cookie].empty?
21
+ @logger.warn("PerimeterxCookieValidator:[verify]: cookie not found")
22
+ px_ctx.context[:s2s_call_reason] = PxModule::NO_COOKIE
23
+ return false, px_ctx
24
+ end
25
+
26
+ # Deserialize cookie start
27
+ cookie = PerimeterxCookie.px_cookie_factory(px_ctx, @px_config)
28
+ if (!cookie.deserialize())
29
+ @logger.warn("PerimeterxCookieValidator:[verify]: invalid cookie")
30
+ px_ctx.context[:s2s_call_reason] = PxModule::NO_COOKIE
31
+ return false, px_ctx
32
+ end
33
+ px_ctx.context[:decoded_cookie] = cookie.decoded_cookie
34
+ px_ctx.context[:score] = cookie.cookie_score()
35
+ px_ctx.context[:uuid] = cookie.decoded_cookie[:u]
36
+ px_ctx.context[:vid] = cookie.decoded_cookie[:v]
37
+ px_ctx.context[:block_action] = px_ctx.set_block_action_type(cookie.cookie_block_action())
38
+ px_ctx.context[:cookie_hmac] = cookie.cookie_hmac()
39
+
40
+ if (cookie.expired?)
41
+ @logger.warn("PerimeterxCookieValidator:[verify]: cookie expired")
42
+ px_ctx.context[:s2s_call_reason] = PxModule::EXPIRED_COOKIE
43
+ return false, px_ctx
44
+ end
45
+
46
+ if (cookie.high_score?)
47
+ @logger.warn("PerimeterxCookieValidator:[verify]: cookie high score")
48
+ px_ctx.context[:s2s_call_reason] = PxModule::COOKIE_HIGH_SCORE
49
+ return false, px_ctx
50
+ end
51
+
52
+ if (!cookie.secured?)
53
+ @logger.warn("PerimeterxCookieValidator:[verify]: cookie invalid hmac")
54
+ px_ctx.context[:s2s_call_reason] = PxModule::COOKIE_VALIDATION_FAILED
55
+ return false, px_ctx
56
+ end
57
+
58
+ @logger.debug("PerimeterxCookieValidator:[verify]: cookie validation passed succesfully")
59
+
60
+ return true, px_ctx
61
+ rescue Exception => e
62
+ @logger.error("PerimeterxCookieValidator:[verify]: exception while verifying cookie => #{e.message}")
63
+ px_ctx.context[:s2s_call_reason] = PxModule::COOKIE_DECRYPTION_FAILED
64
+ return false, px_ctx
65
+ end
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,110 @@
1
+ require 'perimeterx/internal/clients/perimeter_x_risk_client'
2
+
3
+ module PxModule
4
+ class PerimeterxS2SValidator < PerimeterxRiskClient
5
+
6
+ def initialize(px_config, http_client)
7
+ super(px_config, http_client)
8
+ @logger.debug("PerimeterxS2SValidator[initialize]")
9
+ end
10
+
11
+ def send_risk_request(px_ctx)
12
+ @logger.debug("PerimeterxS2SValidator[send_risk_request]: send_risk_request")
13
+
14
+ risk_mode = PxModule::RISK_MODE_ACTIVE
15
+ if @px_config[:module_mode] == PxModule::MONITOR_MODE
16
+ risk_mode = PxModule::RISK_MODE_MONITOR
17
+ end
18
+
19
+ request_body = {
20
+ 'request' => {
21
+ 'ip' => px_ctx.context[:ip],
22
+ 'headers' => format_headers(px_ctx),
23
+ 'uri' => px_ctx.context[:uri],
24
+ 'url' => px_ctx.context[:full_url]
25
+ },
26
+ 'additional' => {
27
+ 's2s_call_reason' => px_ctx.context[:s2s_call_reason],
28
+ 'module_version' => @px_config[:sdk_name],
29
+ 'http_method' => px_ctx.context[:http_method],
30
+ 'http_version' => px_ctx.context[:http_version],
31
+ 'risk_mode' => risk_mode
32
+ }
33
+ }
34
+ #Check for hmac
35
+ if px_ctx.context.key?(:cookie_hmac)
36
+ request_body[:additional][:px_cookie_hmac] = px_ctx.context[:cookie_hmac]
37
+ end
38
+
39
+
40
+ #Check for VID
41
+ if px_ctx.context.key?(:vid)
42
+ request_body[:vid] = px_ctx.context[:vid]
43
+ end
44
+
45
+ #Check for uuid
46
+ if px_ctx.context.key?(:uuid)
47
+ request_body[:uuid] = px_ctx.context[:uuid]
48
+ end
49
+
50
+ #S2S Call reason
51
+ decode_cookie_reasons = ['cookie_expired', 'cookie_validation_failed']
52
+ if decode_cookie_reasons.include? (px_ctx.context[:s2s_call_reason])
53
+ if (px_ctx.context.key?(:decoded_cookie))
54
+ request_body[:additional][:px_cookie] = px_ctx.context[:decoded_cookie]
55
+ end
56
+ end
57
+
58
+ # Prepare request
59
+ headers = {
60
+ "Authorization" => "Bearer #{@px_config[:auth_token]}" ,
61
+ "Content-Type" => "application/json"
62
+ };
63
+
64
+ # Custom risk handler
65
+ if (risk_mode == PxModule::ACTIVE_MODE && @px_config.key?(:custom_risk_handler))
66
+ response = @px_config[:custom_risk_handler].call(PxModule::API_V2_RISK, request_body, headers, @px_config[:api_timeout])
67
+ else
68
+ response = @http_client.post(PxModule::API_V2_RISK , request_body, headers)
69
+ end
70
+ return response
71
+ end
72
+
73
+ def verify(px_ctx)
74
+ @logger.debug("PerimeterxS2SValidator[verify]")
75
+ response = send_risk_request(px_ctx)
76
+ if (!response)
77
+ return px_ctx
78
+ end
79
+ px_ctx.context[:made_s2s_risk_api_call] = true
80
+
81
+ # From here response should be valid, if success or error
82
+ response_body = eval(response.content);
83
+ # When success
84
+ if (response.status == 200 && response_body.key?(:score) && response_body.key?(:action))
85
+ @logger.debug("PerimeterxS2SValidator[verify]: response ok")
86
+ score = response_body[:score]
87
+ px_ctx.context[:score] = score
88
+ px_ctx.context[:uuid] = response_body[:uuid]
89
+ px_ctx.context[:block_action] = px_ctx.set_block_action_type(response_body[:action])
90
+ if (response_body[:action] == 'j' && response_body.key?(:action_data) && response_body[:action_data].key?(:body))
91
+ px_ctx.context[:block_action_data] = response_body[:action_data][:body]
92
+ px_ctx.context[:blocking_reason] = 'challenge'
93
+ elsif (score >= @px_config[:blocking_score])
94
+ px_ctx.context[:blocking_reason] = 's2s_high_score'
95
+ end #end challange or blocking score
96
+ end #end success response
97
+
98
+ # When error
99
+ if(response.status != 200)
100
+ @logger.warn("PerimeterxS2SValidator[verify]: bad response, return code #{response.code}")
101
+ px_ctx.context[:uuid] = ""
102
+ px_ctx.context[:s2s_error_msg] = response_body[:message]
103
+ end
104
+
105
+ @logger.debug("PerimeterxS2SValidator[verify]: done")
106
+ return px_ctx
107
+ end #end method
108
+
109
+ end
110
+ end
@@ -0,0 +1,42 @@
1
+ module PxModule
2
+ # Misc
3
+ MONITOR_MODE = 1
4
+ ACTIVE_MODE = 2
5
+ RISK_MODE_ACTIVE = "active_blocking"
6
+ RISK_MODE_MONITOR = "monitor"
7
+ SDK_NAME = "RUBY SDK v#{PxModule::VERSION}"
8
+
9
+ # Routes
10
+ API_V1_S2S = "/api/v1/collector/s2s"
11
+ API_V1_CAPTCHA = "/api/v1/risk/captcha"
12
+ API_V2_RISK = "/api/v2/risk"
13
+
14
+ # Activity Types
15
+ BLOCK_ACTIVITY = "block"
16
+ PAGE_REQUESTED_ACTIVITY = "page_requested"
17
+
18
+ # PxContext
19
+ NO_COOKIE = "no_cookie"
20
+ INVALID_COOKIE = "invalid cookie"
21
+ EXPIRED_COOKIE = "cookie_expired"
22
+ COOKIE_HIGH_SCORE = "cookie_high_score"
23
+ COOKIE_VALIDATION_FAILED = "cookie_validation_failed"
24
+ COOKIE_DECRYPTION_FAILED = "cookie_decryption_failed"
25
+
26
+ # Templates
27
+ BLOCK_TEMPLATE = "block.mustache"
28
+ CAPTCHA_TEMPLATE = "captcha.mustache"
29
+
30
+ # Tempalte Props
31
+ PROP_REF_ID = :refId
32
+ PROP_APP_ID = :appId
33
+ PROP_VID = :vid
34
+ PROP_UUID = :uuid
35
+ PROP_LOGO_VISIBILITY = :logoVisibility
36
+ PROP_CUSTOM_LOGO = :customLogo
37
+ PROP_CSS_REF = :cssRef
38
+ PROP_JS_REF = :jsRef
39
+
40
+ VISIBLE = 'visible'
41
+ HIDDEN = 'hidden'
42
+ end
@@ -0,0 +1,55 @@
1
+ require "perimeterx/utils/px_logger"
2
+ require "httpclient"
3
+
4
+ module PxModule
5
+ class PxHttpClient
6
+ attr_accessor :px_config
7
+ attr_accessor :BASE_URL
8
+ attr_accessor :http_client
9
+
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
16
+
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
33
+ end
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
55
+ end
@@ -0,0 +1,17 @@
1
+ require 'logger'
2
+ module PxModule
3
+
4
+ class PxLogger < Logger
5
+
6
+ def initialize(debug)
7
+ if debug
8
+ super(STDOUT)
9
+ else
10
+ super(nil)
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+
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