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.
- checksums.yaml +7 -0
- data/lib/paycertify.rb +6 -0
- data/lib/paycertify/three_ds.rb +80 -0
- data/lib/paycertify/three_ds/client.rb +60 -0
- data/lib/paycertify/three_ds/form.rb +124 -0
- data/lib/paycertify/three_ds/payment_authentication.rb +51 -0
- metadata +76 -0
checksums.yaml
ADDED
@@ -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
|
data/lib/paycertify.rb
ADDED
@@ -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: []
|