paycertify 0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1beefa8f5e0710dae9817343ef7507386a6e0c84
4
+ data.tar.gz: a5c8deae72634009b23bd4ace0f3e4849befbb47
5
+ SHA512:
6
+ metadata.gz: f16664472922d267eacf82c898784f720178b89ebc8f7dd7cb006f09c78078b00cbbd94b00d28b058bd0c39763271dce9a078040577a3fb6a787198a69b02702
7
+ data.tar.gz: 9d826c45ac17c4a8288ffabafdeb4136200668cbce8f16c3a14ec86f0b282b848a5ff1319bf97db6cb71c4290c825951866929ebe6852adbfe6effa06ecb9fb1
@@ -0,0 +1,6 @@
1
+ require 'active_support/rails'
2
+ require 'active_support/core_ext'
3
+
4
+ require 'paycertify/three_ds'
5
+
6
+ module PayCertify; end
@@ -0,0 +1,80 @@
1
+ require_relative './three_ds/client'
2
+ require_relative './three_ds/form'
3
+ require_relative './three_ds/payment_authentication'
4
+
5
+ require 'json'
6
+ require 'faraday'
7
+
8
+ module PayCertify
9
+ class ThreeDS
10
+
11
+ class NoCredentialsError < StandardError; end
12
+
13
+ attr_accessor :type, :client, :settings, :authentication
14
+ attr_accessor :card_number, :expiration_month, :expiration_year, :amount, :transaction_id, :message_id, :return_url
15
+
16
+ delegate :api_key, to: :class
17
+ delegate :api_secret, to: :class
18
+
19
+ def initialize(options)
20
+ raise NoCredentialsError, 'No api_key provided.' unless api_key.present?
21
+ raise NoCredentialsError, 'No api_secret provided.' unless api_secret.present?
22
+
23
+ self.type = options[:type].to_sym.in?([:default, :frictionless]) ? options[:type].to_sym : :default
24
+
25
+ self.card_number = options[:card_number]
26
+ self.expiration_month = options[:expiration_month]
27
+ self.expiration_year = options[:expiration_year]
28
+ self.amount = options[:amount]
29
+ self.transaction_id = options[:transaction_id]
30
+ self.message_id = options[:message_id]
31
+ self.return_url = options[:return_url]
32
+
33
+ self.client = PayCertify::ThreeDS::Client.new(api_key: api_key, api_secret: api_secret)
34
+ end
35
+
36
+ def settings
37
+ @settings ||= {
38
+ pan: card_number,
39
+ card_exp_month: expiration_month,
40
+ card_exp_year: expiration_year,
41
+ amount: amount,
42
+ transaction_id: transaction_id,
43
+ message_id: message_id,
44
+ return_url: return_url
45
+ }
46
+ end
47
+
48
+ def payment_authentication
49
+ @payment_authentication ||= PayCertify::ThreeDS::PaymentAuthentication.new(client, settings)
50
+ end
51
+
52
+ def card_enrolled?
53
+ @card_enrolled ||= payment_authentication.card_enrolled?
54
+ end
55
+
56
+ def start!
57
+ self.authentication = payment_authentication.prepare!
58
+ end
59
+
60
+ def render!
61
+ PayCertify::ThreeDS::Form.new(authentication).render_html_for(settings, type)
62
+ end
63
+
64
+ class << self
65
+ cattr_accessor :api_key, :api_secret
66
+
67
+ def configure(&block)
68
+ yield self if block_given?
69
+ end
70
+
71
+ def authenticate!(settings:, callback_params:)
72
+ raise NoCredentialsError, 'No api_key provided.' unless api_key.present?
73
+ raise NoCredentialsError, 'No api_secret provided.' unless api_secret.present?
74
+
75
+ client = PayCertify::ThreeDS::Client.new(api_key: api_key, api_secret: api_secret)
76
+ PayCertify::ThreeDS::PaymentAuthentication.new(client, settings).authenticate!(callback_params)
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,60 @@
1
+ require 'faraday'
2
+
3
+ module PayCertify
4
+ class ThreeDS
5
+ class Client
6
+
7
+ BASE_URL = 'https://mpi.3dsintegrator.com'
8
+
9
+ class InvalidRequestError < StandardError; end
10
+
11
+ attr_accessor :api_key, :api_secret
12
+
13
+ def initialize(api_key:, api_secret:)
14
+ self.api_key = api_key
15
+ self.api_secret = api_secret
16
+ end
17
+
18
+ def post(path:, data:)
19
+ sorted_data = JSON.generate(data.sort.to_h)
20
+
21
+ response = connection.post do |request|
22
+ request.url path
23
+ request.headers['Content-Type'] = 'application/json'
24
+ request.headers['x-mpi-api-key'] = api_key
25
+ request.headers['x-mpi-signature'] = signature(path, sorted_data)
26
+ request.body = sorted_data
27
+ end
28
+
29
+ respond_with response
30
+ end
31
+
32
+ private
33
+ def connection
34
+ @connection ||= Faraday.new(url: BASE_URL, ssl: {verify: false}) do |faraday|
35
+ faraday.request :url_encoded
36
+ faraday.response :logger
37
+ faraday.adapter Faraday.default_adapter
38
+ end
39
+ end
40
+
41
+ def signature(path, data)
42
+ Digest::SHA256.hexdigest "#{api_key}#{BASE_URL}#{path}#{data}#{api_secret}"
43
+ end
44
+
45
+ def respond_with(response)
46
+ 3.times{puts}
47
+ puts 'Response -----'
48
+ p response.body
49
+ 10.times{puts}
50
+
51
+ if response.status < 400
52
+ JSON.parse(response.body)
53
+ else
54
+ error = JSON.parse(response.body)['error']
55
+ raise InvalidRequestError, "API responded with #{response.status} and error: #{error}"
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,124 @@
1
+ module PayCertify
2
+ class ThreeDS
3
+ class Form
4
+
5
+ class UnauthenticatedPaymentError < StandardError; end
6
+
7
+ attr_accessor :authentication, :settings
8
+
9
+ def initialize(authentication)
10
+ check_authentication!(authentication)
11
+
12
+ self.authentication = authentication
13
+ end
14
+
15
+ def acs_url
16
+ @acs_url ||= authentication['AcsUrl']
17
+ end
18
+
19
+ def pareq
20
+ @pareq ||= authentication['PaReq']
21
+ end
22
+
23
+ def md
24
+ @md ||= authentication['MD']
25
+ end
26
+
27
+ def term_url
28
+ @term_url ||= authentication['TermUrl']
29
+ end
30
+
31
+ def render_html_for(settings, type)
32
+ self.settings = settings
33
+ send(type)
34
+ rescue NoMethodError
35
+ raise UndefinedTypeError, 'Type is not supported: '+ type
36
+ end
37
+
38
+ def default
39
+ <<-HTML.squish
40
+ #{form}
41
+
42
+ <script>
43
+ window.onload = function() {
44
+ document.form3ds.submit();
45
+ }
46
+ </script>
47
+ HTML
48
+ end
49
+
50
+ def frictionless
51
+ <<-HTML.squish
52
+
53
+ <iframe id="3ds-frame" src="about:blank"></iframe>
54
+
55
+ <form id="callback-form" action="#{term_url}" method="post">
56
+ <input type="hidden" id="pares" name="pares" />
57
+ </form>
58
+
59
+ <script>
60
+ (function(){
61
+ var frame = document.getElementById('3ds-frame');
62
+ var form = document.getElementById('callback-form');
63
+ var submitForm = false;
64
+ var saveBeforeUnload = false;
65
+
66
+ setInterval(function() {
67
+ if (saveBeforeUnload) {
68
+ saveBeforeUnload = false;
69
+ console.log('SAVE!');
70
+ window.onbeforeunload = null;
71
+ document.createElement('form').submit.call(form);
72
+ }
73
+ }, 500);
74
+
75
+
76
+ var exitPoll = function() {
77
+ if (submitForm == false) {
78
+ saveBeforeUnload = true;
79
+ return "Transaction is still processing";
80
+ }
81
+ };
82
+
83
+ window.onbeforeunload = exitPoll;
84
+
85
+ frame.contentDocument.write('#{form}');
86
+ frame.contentDocument.form3ds.submit();
87
+
88
+
89
+ window.onmessage = function(e){
90
+ debugger;
91
+ if (e.data.PaRes != '') {
92
+ j = e.data;
93
+ var pinput = document.getElementById('pares');
94
+ pinput.value = j;
95
+ submitForm = true;
96
+ document.createElement('form').submit.call(form);
97
+ console.log('response received');
98
+ clearInterval(tid);
99
+ }
100
+ };
101
+ })();
102
+ </script>
103
+ HTML
104
+ end
105
+
106
+ private
107
+ def form
108
+ <<-HTML
109
+ <form name="form3ds" action="#{acs_url}" method="post"/>
110
+ <input name="PaReq" type="hidden" value="#{pareq}"/>
111
+ <input name="MD" type="hidden" value="#{md}"/>
112
+ <input name="TermUrl" type="hidden" value="#{term_url}"/>
113
+ </form>
114
+ HTML
115
+ end
116
+
117
+ def check_authentication!(authentication)
118
+ unless authentication.present?
119
+ raise UnauthenticatedPaymentError, 'Please authenticate (run #start!) before rendering html.'
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,51 @@
1
+ module PayCertify
2
+ class ThreeDS
3
+ class PaymentAuthentication
4
+
5
+ ENROLLED_STATUS_PATH = '/index_demo.php/enrolled-status'
6
+ PAREQ_PATH = '/index_demo.php/auth-request'
7
+ PARES_PATH = '/index_demo.php/auth-response'
8
+
9
+ FIELDS = %w(pan card_exp_month card_exp_year amount transaction_id return_url)
10
+
11
+ class FieldNotProvidedError < StandardError; end
12
+
13
+ attr_accessor :client, :params
14
+
15
+ def initialize(client, params)
16
+ self.client = client
17
+ self.params = params
18
+ end
19
+
20
+ def card_enrolled?
21
+ validate!(:pan)
22
+
23
+ response = client.post(path: ENROLLED_STATUS_PATH, data: params.slice(:pan))
24
+
25
+ return response['enrollment_status'] == 'Y'
26
+ end
27
+
28
+ def prepare!
29
+ validate!
30
+ client.post(path: PAREQ_PATH, data: params)
31
+ end
32
+
33
+ def authenticate!(callback_params)
34
+ validate!
35
+ self.params = params.merge(pares: callback_params['PaRes'])
36
+
37
+ client.post(path: PARES_PATH, data: params)
38
+ end
39
+
40
+ private
41
+ def validate!(*settings)
42
+ fields = settings.presence || FIELDS
43
+ fields.each { |field| raise_error_if_field_not_present(params, field.to_sym) }
44
+ end
45
+
46
+ def raise_error_if_field_not_present(settings, field)
47
+ raise FieldNotProvidedError, "no #{field} provided" unless settings[field].present?
48
+ end
49
+ end
50
+ end
51
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: paycertify
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - PayCertify Engineering Team
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: actionpack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Interact with the Gateway, 3DS, Kount, and FraudPortal
42
+ email: engineering@paycertify.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - lib/paycertify.rb
48
+ - lib/paycertify/three_ds.rb
49
+ - lib/paycertify/three_ds/client.rb
50
+ - lib/paycertify/three_ds/form.rb
51
+ - lib/paycertify/three_ds/payment_authentication.rb
52
+ homepage: http://github.com/paycertify/wrappers/ruby
53
+ licenses:
54
+ - MIT
55
+ metadata: {}
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubyforge_project:
72
+ rubygems_version: 2.5.1
73
+ signing_key:
74
+ specification_version: 4
75
+ summary: PayCertify wrapper for Ruby language
76
+ test_files: []