cybersourcery 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/Rakefile +6 -0
- data/lib/cybersourcery.rb +46 -0
- data/lib/cybersourcery/cart_signature_checker.rb +17 -0
- data/lib/cybersourcery/cart_signer.rb +31 -0
- data/lib/cybersourcery/configuration.rb +9 -0
- data/lib/cybersourcery/container.rb +25 -0
- data/lib/cybersourcery/cybersource_params_normalizer.rb +9 -0
- data/lib/cybersourcery/cybersource_signature_checker.rb +13 -0
- data/lib/cybersourcery/cybersource_signer.rb +79 -0
- data/lib/cybersourcery/exceptions.rb +3 -0
- data/lib/cybersourcery/merchant_data_serializer.rb +38 -0
- data/lib/cybersourcery/payment.rb +43 -0
- data/lib/cybersourcery/payments_helper.rb +404 -0
- data/lib/cybersourcery/profile.rb +54 -0
- data/lib/cybersourcery/railtie.rb +9 -0
- data/lib/cybersourcery/reason_code_checker.rb +77 -0
- data/lib/cybersourcery/signature_checker.rb +40 -0
- data/lib/cybersourcery/version.rb +3 -0
- data/lib/rails/generators/cybersourcery/config/config_generator.rb +19 -0
- data/lib/rails/generators/cybersourcery/config/templates/cybersourcery.rb +5 -0
- data/lib/rails/generators/cybersourcery/config/templates/cybersourcery_profiles.yml +14 -0
- data/lib/tasks/cybersourcery_tasks.rake +4 -0
- metadata +293 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ca8d9ed8a23a07c08e2b1186bceea38f2f9fa844
|
4
|
+
data.tar.gz: 19cbb60e854afc51e9cb69cfc56d55db502ca1e0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 274dd59a12076d27129d85209ac74bfe6d9ff42c9c884c7ac4be2ffb67cc11a82ddbb8911da1e31f1f22ef3a5d3ba544967f16c9c68081de4155f33b1527b2a8
|
7
|
+
data.tar.gz: 39ad67705491c6f6b49ac3ed257f5c2f0883bb14262e47cd3e2ca8d0b05988b3cac1ff8f93a00c4ec34f51fe9526b2de6cd5a480f4ebd4af80a2f9255dc85275
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 PromptWorks
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'cybersourcery/version'
|
2
|
+
require 'cybersourcery/configuration'
|
3
|
+
require 'cybersourcery/exceptions'
|
4
|
+
|
5
|
+
if defined? Rails
|
6
|
+
require 'cybersourcery/merchant_data_serializer'
|
7
|
+
require 'cybersourcery/profile'
|
8
|
+
require 'cybersourcery/payment'
|
9
|
+
require 'cybersourcery/railtie'
|
10
|
+
require 'cybersourcery/cybersource_signer'
|
11
|
+
require 'cybersourcery/cart_signer'
|
12
|
+
require 'cybersourcery/signature_checker'
|
13
|
+
require 'cybersourcery/cart_signature_checker'
|
14
|
+
require 'cybersourcery/cybersource_signature_checker'
|
15
|
+
require 'cybersourcery/reason_code_checker'
|
16
|
+
require 'cybersourcery/container'
|
17
|
+
require 'cybersourcery/cybersource_params_normalizer'
|
18
|
+
|
19
|
+
if Rails.env.test?
|
20
|
+
require 'slim-rails'
|
21
|
+
require 'bootstrap-sass'
|
22
|
+
require 'simple_form'
|
23
|
+
require 'sass-rails'
|
24
|
+
require 'coffee-rails'
|
25
|
+
require 'jquery-rails'
|
26
|
+
require 'dotenv-rails'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module Cybersourcery
|
31
|
+
class << self
|
32
|
+
attr_writer :configuration
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.configuration
|
36
|
+
@configuration ||= Configuration.new
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.reset
|
40
|
+
@configuration = Configuration.new
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.configure
|
44
|
+
yield(configuration)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Cybersourcery
|
2
|
+
class CartSignatureChecker < Cybersourcery::SignatureChecker
|
3
|
+
attr_reader :session
|
4
|
+
|
5
|
+
def post_initialize(args)
|
6
|
+
@session = args[:session]
|
7
|
+
end
|
8
|
+
|
9
|
+
def signed_field_names
|
10
|
+
@session[:signed_cart_fields]
|
11
|
+
end
|
12
|
+
|
13
|
+
def signature
|
14
|
+
@session[:cart_signature]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Cybersourcery
|
2
|
+
class CartSigner
|
3
|
+
attr_reader :session, :signer, :cart_fields, :signed_cart_fields
|
4
|
+
|
5
|
+
def initialize(session, signer, cart_fields)
|
6
|
+
@session = session
|
7
|
+
@signer = signer
|
8
|
+
@cart_fields = cart_fields.dup
|
9
|
+
end
|
10
|
+
|
11
|
+
def run
|
12
|
+
sign_cart_fields
|
13
|
+
reassign_signature_and_signed_fields_to_session
|
14
|
+
@signed_cart_fields
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def sign_cart_fields
|
20
|
+
@cart_fields[:signed_field_names] = @cart_fields.keys.join(',')
|
21
|
+
@signer.form_fields = @cart_fields
|
22
|
+
@signed_cart_fields = @signer.signed_fields.dup
|
23
|
+
end
|
24
|
+
|
25
|
+
def reassign_signature_and_signed_fields_to_session
|
26
|
+
@session[:signed_cart_fields] = @signed_cart_fields.delete :signed_field_names
|
27
|
+
@session[:cart_signature] = @signed_cart_fields.delete :signature
|
28
|
+
@session
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Cybersourcery
|
2
|
+
class Container
|
3
|
+
def self.get_cart_signer(profile_name, session, cart_fields)
|
4
|
+
profile = Cybersourcery::Profile.new(profile_name)
|
5
|
+
cybersource_signer = Cybersourcery::CybersourceSigner.new(profile)
|
6
|
+
Cybersourcery::CartSigner.new(session, cybersource_signer, cart_fields)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.get_cart_signature_checker(profile_name, params, session)
|
10
|
+
profile = Cybersourcery::Profile.new(profile_name)
|
11
|
+
Cybersourcery::CartSignatureChecker.new({ profile: profile, params: params, session: session})
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.get_cybersource_signature_checker(profile_name, params)
|
15
|
+
profile = Cybersourcery::Profile.new(profile_name)
|
16
|
+
Cybersourcery::CybersourceSignatureChecker.new({ profile: profile, params: params })
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.get_payment(profile_name, params, payment_class_name = 'Payment')
|
20
|
+
profile = Cybersourcery::Profile.new(profile_name)
|
21
|
+
signer = Cybersourcery::CybersourceSigner.new(profile)
|
22
|
+
payment_class_name.constantize.new(signer, profile, params)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'hmac-sha2'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module Cybersourcery
|
5
|
+
class CybersourceSigner
|
6
|
+
attr_accessor :profile, :signer
|
7
|
+
attr_writer :time
|
8
|
+
attr_writer :form_fields
|
9
|
+
attr_reader :signable_fields
|
10
|
+
|
11
|
+
IGNORE_FIELDS = %i[
|
12
|
+
commit
|
13
|
+
utf8
|
14
|
+
authenticity_token
|
15
|
+
action
|
16
|
+
controller
|
17
|
+
]
|
18
|
+
|
19
|
+
def initialize(profile, signer = Signer)
|
20
|
+
@profile = profile
|
21
|
+
@signer = signer
|
22
|
+
@signable_fields = {
|
23
|
+
access_key: @profile.access_key,
|
24
|
+
profile_id: @profile.profile_id,
|
25
|
+
payment_method: @profile.payment_method,
|
26
|
+
locale: @profile.locale,
|
27
|
+
transaction_type: @profile.transaction_type,
|
28
|
+
currency: @profile.currency
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_and_sign_fields(params)
|
33
|
+
add_signable_fields(params)
|
34
|
+
signed_fields
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_signable_fields(params)
|
38
|
+
@signable_fields.merge! params.symbolize_keys.delete_if { |k,v|
|
39
|
+
@profile.unsigned_field_names.include?(k) || IGNORE_FIELDS.include?(k)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def signed_fields
|
44
|
+
form_fields.tap do |data|
|
45
|
+
signature_keys = data[:signed_field_names].split(',').map(&:to_sym)
|
46
|
+
signature_message = self.class.signature_message(data, signature_keys)
|
47
|
+
data[:signature] = signer.signature(signature_message, profile.secret_key)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def form_fields
|
52
|
+
@form_fields ||= signable_fields.dup.merge(
|
53
|
+
unsigned_field_names: @profile.unsigned_field_names.join(','),
|
54
|
+
transaction_uuid: SecureRandom.hex(16),
|
55
|
+
reference_number: SecureRandom.hex(16),
|
56
|
+
signed_date_time: time,
|
57
|
+
signed_field_names: nil # make sure it's in data.keys
|
58
|
+
).tap do |data|
|
59
|
+
data[:signed_field_names] = data.keys.join(',')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def time
|
64
|
+
@time ||= Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.signature_message(hash, keys)
|
68
|
+
keys.map {|key| "#{key}=#{hash.fetch(key)}" }.join(',')
|
69
|
+
end
|
70
|
+
|
71
|
+
class Signer
|
72
|
+
def self.signature(message, secret_key)
|
73
|
+
mac = HMAC::SHA256.new(secret_key)
|
74
|
+
mac.update message
|
75
|
+
Base64.strict_encode64(mac.digest)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Cybersourcery
|
2
|
+
class MerchantDataSerializer
|
3
|
+
attr_reader :start_count
|
4
|
+
|
5
|
+
def initialize(start_count = 1)
|
6
|
+
@start_count = start_count
|
7
|
+
end
|
8
|
+
|
9
|
+
def serialize(merchant_data)
|
10
|
+
scanned_data = merchant_data.to_json.scan(/.{1,100}/)
|
11
|
+
serialized_data = {}
|
12
|
+
|
13
|
+
scanned_data.each_with_index do |item, index|
|
14
|
+
count = index + @start_count
|
15
|
+
|
16
|
+
if count < 1 || count > 100
|
17
|
+
raise Cybersourcery::CybersourceryError, "The supported merchant_defined_data range is 1 to 100. #{count} is out of range."
|
18
|
+
end
|
19
|
+
|
20
|
+
serialized_data["merchant_defined_data#{count}".to_sym] = item
|
21
|
+
end
|
22
|
+
|
23
|
+
serialized_data
|
24
|
+
end
|
25
|
+
|
26
|
+
def deserialize(params)
|
27
|
+
merchant_data = params.select { |k,v| k =~ /^merchant_defined_data/ }.symbolize_keys
|
28
|
+
merchant_data_string = ''
|
29
|
+
|
30
|
+
# it's important to reassemble the data in the right order!
|
31
|
+
merchant_data.length.times do |i|
|
32
|
+
merchant_data_string << merchant_data["merchant_defined_data#{i+1}".to_sym]
|
33
|
+
end
|
34
|
+
|
35
|
+
JSON.parse(merchant_data_string).symbolize_keys
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Cybersourcery
|
2
|
+
class Payment
|
3
|
+
# These are dependencies for ActiveModel::Errors in the initialize method
|
4
|
+
extend ActiveModel::Naming
|
5
|
+
extend ActiveModel::Translation
|
6
|
+
include ActiveModel::Validations
|
7
|
+
|
8
|
+
# So we can use form_for in a view
|
9
|
+
include ActiveModel::Conversion
|
10
|
+
|
11
|
+
attr_reader :signer, :profile, :params, :errors
|
12
|
+
attr_accessor :bill_to_forename, :bill_to_surname, :card_number, :card_expiry_date,
|
13
|
+
:card_expiry_month, :card_expiry_year, :card_type,
|
14
|
+
:bill_to_email, :bill_to_address_line1, :bill_to_address_line2,
|
15
|
+
:bill_to_address_city, :bill_to_address_state, :bill_to_address_postal_code
|
16
|
+
validates_presence_of :bill_to_forename, :bill_to_surname, :card_number, :card_expiry_date,
|
17
|
+
:card_expiry_month, :card_expiry_year, :card_type, :bill_to_email,
|
18
|
+
:bill_to_address_line1, :bill_to_address_city, :bill_to_address_state,
|
19
|
+
:bill_to_address_postal_code
|
20
|
+
|
21
|
+
# To keep ActiveModel::Conversion happy
|
22
|
+
def persisted?
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(signer, profile, params)
|
27
|
+
@signer = signer
|
28
|
+
@profile = profile
|
29
|
+
@params = params
|
30
|
+
# I'm not doing dependency injection for ActiveModel dependencies.
|
31
|
+
# Given we're extending ActiveModel::Naming above, we're already tightly bound...
|
32
|
+
@errors = ActiveModel::Errors.new(self)
|
33
|
+
end
|
34
|
+
|
35
|
+
def form_action_url
|
36
|
+
@profile.transaction_url
|
37
|
+
end
|
38
|
+
|
39
|
+
def signed_fields
|
40
|
+
@signer.add_and_sign_fields(@params)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,404 @@
|
|
1
|
+
module Cybersourcery
|
2
|
+
module PaymentsHelper
|
3
|
+
def add_signed_fields(payment, form)
|
4
|
+
signed_fields = ''
|
5
|
+
|
6
|
+
payment.signed_fields.each do |field, value|
|
7
|
+
signed_fields << hidden_input(form, field, value)
|
8
|
+
end
|
9
|
+
|
10
|
+
signed_fields
|
11
|
+
end
|
12
|
+
|
13
|
+
def simple_form_input(form, field, value = nil)
|
14
|
+
form.input field, label: field_label(field), input_html: {
|
15
|
+
name: field.to_s,
|
16
|
+
value: value,
|
17
|
+
pattern: field_pattern(field),
|
18
|
+
title: field_validation_message(field)
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def simple_form_select(form, field, collection, selected = nil, prompt = nil)
|
23
|
+
form.input(
|
24
|
+
field,
|
25
|
+
label: field_label(field),
|
26
|
+
collection: collection,
|
27
|
+
selected: selected,
|
28
|
+
prompt: prompt,
|
29
|
+
input_html: { name: field.to_s }
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def field_label(field)
|
34
|
+
labels = {
|
35
|
+
bill_to_forename: 'First Name',
|
36
|
+
bill_to_surname: 'Last Name',
|
37
|
+
card_number: 'Card Number',
|
38
|
+
card_cvn: 'Security Code',
|
39
|
+
card_expiry_dummy: 'Expiration',
|
40
|
+
bill_to_email: 'Email',
|
41
|
+
bill_to_address_line1: 'Street Address (line 1)',
|
42
|
+
bill_to_address_line2: 'Street Address (line 2)',
|
43
|
+
bill_to_address_city: 'City',
|
44
|
+
bill_to_address_state: 'State (Province)',
|
45
|
+
bill_to_address_postal_code: 'Zip (Postal Code)'
|
46
|
+
}
|
47
|
+
labels[field]
|
48
|
+
end
|
49
|
+
|
50
|
+
def field_pattern(field)
|
51
|
+
patterns = {
|
52
|
+
card_number: "^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$"
|
53
|
+
}
|
54
|
+
patterns[field]
|
55
|
+
end
|
56
|
+
|
57
|
+
def field_validation_message(field)
|
58
|
+
patterns = {
|
59
|
+
card_number: 'Please enter a valid credit card number'
|
60
|
+
}
|
61
|
+
patterns[field]
|
62
|
+
end
|
63
|
+
|
64
|
+
def hidden_input(form, field, value = nil)
|
65
|
+
form.hidden_field field, value: value, name: field.to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
def add_expiry_date_fields(form, classes = 'select required form-control card-expiry')
|
69
|
+
date_fields = hidden_input form, :card_expiry_date
|
70
|
+
date_fields << form.input(:card_expiry_dummy, label: field_label(:card_expiry_dummy)) do
|
71
|
+
form.date_select(:card_expiry_dummy,
|
72
|
+
{
|
73
|
+
discard_day: true,
|
74
|
+
order: [:month, :year],
|
75
|
+
start_year: Date.today.year,
|
76
|
+
end_year: (Date.today.year + 19),
|
77
|
+
use_two_digit_numbers: true,
|
78
|
+
date_separator: ' / ',
|
79
|
+
prompt: true
|
80
|
+
},
|
81
|
+
{ class: classes }
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def countries
|
87
|
+
{
|
88
|
+
"Afghanistan" => "AF",
|
89
|
+
"Aland Islands" => "AX",
|
90
|
+
"Albania" => "AL",
|
91
|
+
"Algeria" => "DZ",
|
92
|
+
"American Samoa (US)" => "AS",
|
93
|
+
"Andorra" => "AD",
|
94
|
+
"Angola" => "AO",
|
95
|
+
"Anguilla (UK)" => "AI",
|
96
|
+
"Antarctica" => "AQ",
|
97
|
+
"Antigua and Barbuda" => "AG",
|
98
|
+
"Argentina" => "AR",
|
99
|
+
"Armenia" => "AM",
|
100
|
+
"Aruba" => "AW",
|
101
|
+
"Australia" => "AU",
|
102
|
+
"Austria" => "AT",
|
103
|
+
"Azerbaijan" => "AZ",
|
104
|
+
"Bahamas" => "BS",
|
105
|
+
"Bahrain" => "BH",
|
106
|
+
"Bangladesh" => "BD",
|
107
|
+
"Barbados" => "BB",
|
108
|
+
"Belarus" => "BY",
|
109
|
+
"Belgium" => "BE",
|
110
|
+
"Belize" => "BZ",
|
111
|
+
"Benin" => "BJ",
|
112
|
+
"Bermuda (UK)" => "BM",
|
113
|
+
"Bhutan" => "BT",
|
114
|
+
"Bolivia" => "BO",
|
115
|
+
"Bonaire, Sint Eustatius and Saba" => "BQ",
|
116
|
+
"Bosnia and Herzegovina" => "BA",
|
117
|
+
"Botswana" => "BW",
|
118
|
+
"Brazil" => "BR",
|
119
|
+
"British Indian Ocean Territory" => "IO",
|
120
|
+
"British Virgin Islands (UK)" => "VG",
|
121
|
+
"Brunei Darussalam" => "BN",
|
122
|
+
"Bulgaria" => "BG",
|
123
|
+
"Burkina Faso" => "BF",
|
124
|
+
"Burundi" => "BI",
|
125
|
+
"Cambodia" => "KH",
|
126
|
+
"Cameroon" => "CM",
|
127
|
+
"Canada" => "CA",
|
128
|
+
"Cape Verde" => "CV",
|
129
|
+
"Cayman Islands (UK)" => "KY",
|
130
|
+
"Central African Republic" => "CF",
|
131
|
+
"Chad" => "TD",
|
132
|
+
"Chile" => "CL",
|
133
|
+
"China" => "CN",
|
134
|
+
"Christmas Island (AU)" => "CX",
|
135
|
+
"Cocos (Keeling) Islands (AU)" => "CC",
|
136
|
+
"Colombia" => "CO",
|
137
|
+
"Comoros" => "KM",
|
138
|
+
"Congo, Democratic Republic of the" => "CD",
|
139
|
+
"Congo, Republic of the" => "CG",
|
140
|
+
"Cook Islands (NZ)" => "CK",
|
141
|
+
"Costa Rica" => "CR",
|
142
|
+
"Côte D'Ivoire" => "CI",
|
143
|
+
"Croatia" => "HR",
|
144
|
+
"Cuba" => "CU",
|
145
|
+
"Curaçao" => "CW",
|
146
|
+
"Cyprus" => "CY",
|
147
|
+
"Czech Republic" => "CZ",
|
148
|
+
"Denmark" => "DK",
|
149
|
+
"Djibouti" => "DJ",
|
150
|
+
"Dominica" => "DM",
|
151
|
+
"Dominican Republic" => "DO",
|
152
|
+
"Ecuador" => "EC",
|
153
|
+
"Egypt" => "EG",
|
154
|
+
"El Salvador" => "SV",
|
155
|
+
"Equatorial Guinea" => "GQ",
|
156
|
+
"Eritrea" => "ER",
|
157
|
+
"Estonia" => "EE",
|
158
|
+
"Ethiopia" => "ET",
|
159
|
+
"Falkland Islands (UK)" => "FK",
|
160
|
+
"Faroe Islands (DK)" => "FO",
|
161
|
+
"Fiji" => "FJ",
|
162
|
+
"Finland" => "FI",
|
163
|
+
"France" => "FR",
|
164
|
+
"French Guiana (FR)" => "GF",
|
165
|
+
"French Polynesia (FR)" => "PF",
|
166
|
+
"French Southern Territories" => "TF",
|
167
|
+
"Gabon" => "GA",
|
168
|
+
"Gambia" => "GM",
|
169
|
+
"Georgia" => "GE",
|
170
|
+
"Germany" => "DE",
|
171
|
+
"Ghana" => "GH",
|
172
|
+
"Gibraltar (UK)" => "GI",
|
173
|
+
"Greece" => "GR",
|
174
|
+
"Greenland (DK)" => "GL",
|
175
|
+
"Grenada" => "GD",
|
176
|
+
"Guadeloupe (FR)" => "GP",
|
177
|
+
"Guam (US)" => "GU",
|
178
|
+
"Guatemala" => "GT",
|
179
|
+
"Guernsey" => "GG",
|
180
|
+
"Guinea" => "GN",
|
181
|
+
"Guinea-Bissau" => "GW",
|
182
|
+
"Guyana" => "GY",
|
183
|
+
"Haiti" => "HT",
|
184
|
+
"Heard Island and McDonald Islands" => "HM",
|
185
|
+
"Holy See (Vatican City)" => "VA",
|
186
|
+
"Honduras" => "HN",
|
187
|
+
"Hong Kong (CN)" => "HK",
|
188
|
+
"Hungary" => "HU",
|
189
|
+
"Iceland" => "IS",
|
190
|
+
"India" => "IN",
|
191
|
+
"Indonesia" => "ID",
|
192
|
+
"Iran" => "IR",
|
193
|
+
"Iraq" => "IQ",
|
194
|
+
"Ireland" => "IE",
|
195
|
+
"Isle of Man" => "IM",
|
196
|
+
"Israel" => "IL",
|
197
|
+
"Italy" => "IT",
|
198
|
+
"Jamaica" => "JM",
|
199
|
+
"Japan" => "JP",
|
200
|
+
"Jersey" => "JE",
|
201
|
+
"Jordan" => "JO",
|
202
|
+
"Kazakhstan" => "KZ",
|
203
|
+
"Kenya" => "KE",
|
204
|
+
"Kiribati" => "KI",
|
205
|
+
"Korea, Democratic People's Republic (North)" => "KP",
|
206
|
+
"Korea, Republic of (South)" => "KR",
|
207
|
+
"Kuwait" => "KW",
|
208
|
+
"Kyrgyzstan" => "KG",
|
209
|
+
"Laos" => "LA",
|
210
|
+
"Latvia" => "LV",
|
211
|
+
"Lebanon" => "LB",
|
212
|
+
"Lesotho" => "LS",
|
213
|
+
"Liberia" => "LR",
|
214
|
+
"Libya" => "LY",
|
215
|
+
"Liechtenstein" => "LI",
|
216
|
+
"Lithuania" => "LT",
|
217
|
+
"Luxembourg" => "LU",
|
218
|
+
"Macau (CN)" => "MO",
|
219
|
+
"Macedonia" => "MK",
|
220
|
+
"Madagascar" => "MG",
|
221
|
+
"Malawi" => "MW",
|
222
|
+
"Malaysia" => "MY",
|
223
|
+
"Maldives" => "MV",
|
224
|
+
"Mali" => "ML",
|
225
|
+
"Malta" => "MT",
|
226
|
+
"Marshall Islands" => "MH",
|
227
|
+
"Martinique (FR)" => "MQ",
|
228
|
+
"Mauritania" => "MR",
|
229
|
+
"Mauritius" => "MU",
|
230
|
+
"Mayotte (FR)" => "YT",
|
231
|
+
"Mexico" => "MX",
|
232
|
+
"Micronesia, Federated States of" => "FM",
|
233
|
+
"Moldova Republic of" => "MD",
|
234
|
+
"Monaco" => "MC",
|
235
|
+
"Mongolia" => "MN",
|
236
|
+
"Montenegro" => "ME",
|
237
|
+
"Montserrat (UK)" => "MS",
|
238
|
+
"Morocco" => "MA",
|
239
|
+
"Mozambique" => "MZ",
|
240
|
+
"Myanmar" => "MM",
|
241
|
+
"Namibia" => "NA",
|
242
|
+
"Nauru" => "NR",
|
243
|
+
"Nepal" => "NP",
|
244
|
+
"Netherlands" => "NL",
|
245
|
+
"Netherlands Antilles (NL)" => "AN",
|
246
|
+
"New Caledonia (FR)" => "NC",
|
247
|
+
"New Zealand" => "NZ",
|
248
|
+
"Nicaragua" => "NI",
|
249
|
+
"Niger" => "NE",
|
250
|
+
"Nigeria" => "NG",
|
251
|
+
"Niue" => "NU",
|
252
|
+
"Norfolk Island (AU)" => "NF",
|
253
|
+
"Northern Mariana Islands (US)" => "MP",
|
254
|
+
"Norway" => "NO",
|
255
|
+
"Oman" => "OM",
|
256
|
+
"Pakistan" => "PK",
|
257
|
+
"Palau" => "PW",
|
258
|
+
"Palestinian Territories" => "PS",
|
259
|
+
"Panama" => "PA",
|
260
|
+
"Papua New Guinea" => "PG",
|
261
|
+
"Paraguay" => "PY",
|
262
|
+
"Peru" => "PE",
|
263
|
+
"Philippines" => "PH",
|
264
|
+
"Pitcairn Islands (UK)" => "PN",
|
265
|
+
"Poland" => "PL",
|
266
|
+
"Portugal" => "PT",
|
267
|
+
"Puerto Rico (US)" => "PR",
|
268
|
+
"Qatar" => "QA",
|
269
|
+
"Reunion (FR)" => "RE",
|
270
|
+
"Romania" => "RO",
|
271
|
+
"Russia" => "RU",
|
272
|
+
"Rwanda" => "RW",
|
273
|
+
"Saint Barthelemy" => "BL",
|
274
|
+
"Saint Helena (UK)" => "SH",
|
275
|
+
"Saint Kitts and Nevis" => "KN",
|
276
|
+
"Saint Lucia" => "LC",
|
277
|
+
"Saint Martin" => "MF",
|
278
|
+
"Saint Pierre & Miquelon (FR)" => "PM",
|
279
|
+
"Saint Vincent and the Grenadines" => "VC",
|
280
|
+
"Samoa" => "WS",
|
281
|
+
"San Marino" => "SM",
|
282
|
+
"Sao Tome and Principe" => "ST",
|
283
|
+
"Saudi Arabia" => "SA",
|
284
|
+
"Senegal" => "SN",
|
285
|
+
"Serbia" => "RS",
|
286
|
+
"Seychelles" => "SC",
|
287
|
+
"Sierra Leone" => "SL",
|
288
|
+
"Singapore" => "SG",
|
289
|
+
"Sint Maarten (Dutch Part)" => "SX",
|
290
|
+
"Slovakia" => "SK",
|
291
|
+
"Slovenia" => "SI",
|
292
|
+
"Solomon Islands" => "SB",
|
293
|
+
"Somalia" => "SO",
|
294
|
+
"South Africa" => "ZA",
|
295
|
+
"South Georgia & South Sandwich Islands (UK)" => "GS",
|
296
|
+
"South Sudan" => "SS",
|
297
|
+
"Spain" => "ES",
|
298
|
+
"Sri Lanka" => "LK",
|
299
|
+
"Sudan" => "SD",
|
300
|
+
"Suriname" => "SR",
|
301
|
+
"Svalbard and Jan Mayen" => "SJ",
|
302
|
+
"Swaziland" => "SZ",
|
303
|
+
"Sweden" => "SE",
|
304
|
+
"Switzerland" => "CH",
|
305
|
+
"Syria" => "SY",
|
306
|
+
"Taiwan" => "TW",
|
307
|
+
"Tajikistan" => "TJ",
|
308
|
+
"Tanzania" => "TZ",
|
309
|
+
"Thailand" => "TH",
|
310
|
+
"Timor-Leste" => "TL",
|
311
|
+
"Togo" => "TG",
|
312
|
+
"Tokelau" => "TK",
|
313
|
+
"Tonga" => "TO",
|
314
|
+
"Trinidad and Tobago" => "TT",
|
315
|
+
"Tunisia" => "TN",
|
316
|
+
"Turkey" => "TR",
|
317
|
+
"Turkmenistan" => "TM",
|
318
|
+
"Turks and Caicos Islands (UK)" => "TC",
|
319
|
+
"Tuvalu" => "TV",
|
320
|
+
"Uganda" => "UG",
|
321
|
+
"Ukraine" => "UA",
|
322
|
+
"United Arab Emirates" => "AE",
|
323
|
+
"United Kingdom" => "GB",
|
324
|
+
"United States" => "US",
|
325
|
+
"United States Minor Outlying Islands" => "UM",
|
326
|
+
"Uruguay" => "UY",
|
327
|
+
"Uzbekistan" => "UZ",
|
328
|
+
"Vanuatu" => "VU",
|
329
|
+
"Venezuela" => "VE",
|
330
|
+
"Vietnam" => "VN",
|
331
|
+
"Virgin Islands (US)" => "VI",
|
332
|
+
"Wallis and Futuna (FR)" => "WF",
|
333
|
+
"Western Sahara" => "EH",
|
334
|
+
"Yemen" => "YE",
|
335
|
+
"Zambia" => "ZM",
|
336
|
+
"Zimbabwe" => "ZW"
|
337
|
+
}
|
338
|
+
end
|
339
|
+
|
340
|
+
def us_states
|
341
|
+
{
|
342
|
+
"Alabama" => "AL",
|
343
|
+
"Alaska" => "AK",
|
344
|
+
"Arizona" => "AZ",
|
345
|
+
"Arkansas" => "AR",
|
346
|
+
"California" => "CA",
|
347
|
+
"Colorado" => "CO",
|
348
|
+
"Connecticut" => "CT",
|
349
|
+
"Delaware" => "DE",
|
350
|
+
"Florida" => "FL",
|
351
|
+
"Georgia" => "GA",
|
352
|
+
"Hawaii" => "HI",
|
353
|
+
"Idaho" => "ID",
|
354
|
+
"Illinois" => "IL",
|
355
|
+
"Indiana" => "IN",
|
356
|
+
"Iowa" => "IA",
|
357
|
+
"Kansas" => "KS",
|
358
|
+
"Kentucky" => "KY",
|
359
|
+
"Louisiana" => "LA",
|
360
|
+
"Maine" => "ME",
|
361
|
+
"Maryland" => "MD",
|
362
|
+
"Massachusetts" => "MA",
|
363
|
+
"Michigan" => "MI",
|
364
|
+
"Minnesota" => "MN",
|
365
|
+
"Mississippi" => "MS",
|
366
|
+
"Missouri" => "MO",
|
367
|
+
"Montana" => "MT",
|
368
|
+
"Nebraska" => "NE",
|
369
|
+
"Nevada" => "NV",
|
370
|
+
"New Hampshire" => "NH",
|
371
|
+
"New Jersey" => "NJ",
|
372
|
+
"New Mexico" => "NM",
|
373
|
+
"New York" => "NY",
|
374
|
+
"North Carolina" => "NC",
|
375
|
+
"North Dakota" => "ND",
|
376
|
+
"Ohio" => "OH",
|
377
|
+
"Oklahoma" => "OK",
|
378
|
+
"Oregon" => "OR",
|
379
|
+
"Pennsylvania" => "PA",
|
380
|
+
"Rhode Island" => "RI",
|
381
|
+
"South Carolina" => "SC",
|
382
|
+
"South Dakota" => "SD",
|
383
|
+
"Tennessee" => "TN",
|
384
|
+
"Texas" => "TX",
|
385
|
+
"Utah" => "UT",
|
386
|
+
"Vermont" => "VT",
|
387
|
+
"Virginia" => "VA",
|
388
|
+
"Washington" => "WA",
|
389
|
+
"West Virginia" => "WV",
|
390
|
+
"Wisconsin" => "WI",
|
391
|
+
"Wyoming" => "WY"
|
392
|
+
}
|
393
|
+
end
|
394
|
+
|
395
|
+
def card_types
|
396
|
+
{
|
397
|
+
'Visa' => '001',
|
398
|
+
'MasterCard' => '002',
|
399
|
+
'American Express' => '003',
|
400
|
+
'Discover' => '004'
|
401
|
+
}
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_support/core_ext/array/conversions.rb' # so we can use to_sentence
|
3
|
+
|
4
|
+
module Cybersourcery
|
5
|
+
class Profile
|
6
|
+
include ActiveModel::Validations
|
7
|
+
|
8
|
+
VALID_ENDPOINTS = {
|
9
|
+
standard: '/silent/pay',
|
10
|
+
create_payment_token: '/silent/token/create',
|
11
|
+
update_payment_token: '/silent/token/update',
|
12
|
+
iframe_standard: '/silent/embedded/pay',
|
13
|
+
iframe_create_payment_token: 'silent/embedded/token/create',
|
14
|
+
iframe_update_payment_token: '/silent/embedded/token/update'
|
15
|
+
}
|
16
|
+
|
17
|
+
attr_accessor :profile_id, :name, :service, :access_key, :secret_key, :success_url,
|
18
|
+
:transaction_type, :endpoint_type, :payment_method, :locale, :currency,
|
19
|
+
:unsigned_field_names
|
20
|
+
validates_presence_of :profile_id, :name, :service, :access_key, :secret_key
|
21
|
+
validates_inclusion_of :service, in: %w(test live), allow_nil: false
|
22
|
+
validates_inclusion_of :endpoint_type, in: VALID_ENDPOINTS.keys, allow_nil: false
|
23
|
+
validates_inclusion_of :payment_method, in: %w(card echeck), allow_nil: false
|
24
|
+
validates_format_of :locale, with: /\A[a-z]{2}-[a-z]{2}\Z/, allow_nil: false
|
25
|
+
validates_format_of :currency, with: /\A[A-Z]{3}\Z/, allow_nil: false
|
26
|
+
|
27
|
+
def initialize(profile_id, profiles = Cybersourcery.configuration.profiles)
|
28
|
+
profiles[profile_id].each do |k,v|
|
29
|
+
self.send "#{k}=", v
|
30
|
+
end
|
31
|
+
|
32
|
+
@profile_id = profile_id
|
33
|
+
@endpoint_type = @endpoint_type.to_sym
|
34
|
+
|
35
|
+
unless self.valid?
|
36
|
+
raise Cybersourcery::CybersourceryError, self.errors.full_messages.to_sentence
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def transaction_url(proxy_url = ENV['CYBERSOURCERY_SOP_PROXY_URL'], env = Rails.env)
|
41
|
+
if env == 'test' && proxy_url.present?
|
42
|
+
"#{proxy_url}#{VALID_ENDPOINTS[@endpoint_type]}"
|
43
|
+
elsif env == 'test' && proxy_url.blank?
|
44
|
+
"#{Cybersourcery.configuration.sop_test_url}#{VALID_ENDPOINTS[@endpoint_type]}"
|
45
|
+
elsif @service == 'test'
|
46
|
+
"#{Cybersourcery.configuration.sop_test_url}#{VALID_ENDPOINTS[@endpoint_type]}"
|
47
|
+
elsif @service == 'live'
|
48
|
+
"#{Cybersourcery.configuration.sop_live_url}#{VALID_ENDPOINTS[@endpoint_type]}"
|
49
|
+
else
|
50
|
+
raise Cybersourcery::CybersourceryError, 'Invalid conditions for determining the transaction_url'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Cybersourcery
|
2
|
+
class ReasonCodeChecker
|
3
|
+
REASON_CODE_EXPLANATIONS = {
|
4
|
+
'100' => 'Successful transaction.',
|
5
|
+
'101' => 'Declined: The request is missing one or more required fields.',
|
6
|
+
'102' => 'Declined: One or more fields in the request contains invalid data',
|
7
|
+
'104' => 'Declined: An identical authorization request has been submitted within the past 15 minutes',
|
8
|
+
'150' => 'Error: General system failure. Please wait a few minutes and try again.',
|
9
|
+
'151' => 'Error: The request was received but there was a server timeout. Please wait a few minutes and try again.',
|
10
|
+
'152' => 'Error: The request was received, but a service did not finish running in time. Please wait a few minutes and try again.',
|
11
|
+
'200' => 'Declined: The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the Address Verification Service (AVS) check',
|
12
|
+
'201' => 'Declined: The issuing bank has questions about the request. Please contact your credit card company.',
|
13
|
+
'202' => 'Declined: Expired card. Please verify your card information, or try a different card.',
|
14
|
+
'203' => 'Declined: General decline of the card. No other information provided by the issuing bank. Please try a different card.',
|
15
|
+
'204' => 'Declined: Insufficient funds in the account. Please try a different card.',
|
16
|
+
'205' => 'Declined: Stolen or lost card',
|
17
|
+
'207' => 'Declined: Issuing bank unavailable. Please wait a few minutes and try again.',
|
18
|
+
'208' => 'Declined: Inactive card or card not authorized for card-not-present transactions. Please try a different card.',
|
19
|
+
'209' => 'Declined: American Express Card Identification Digits (CID) did not match. Please verify your card information, or try a different card.',
|
20
|
+
'210' => 'Declined: The card has reached the credit limit. Please try a different card.',
|
21
|
+
'211' => 'Declined: Invalid card verification number. Please verify your card information, or try a different card.',
|
22
|
+
'221' => 'Declined: The customer matched an entry on the processors negative file.',
|
23
|
+
'230' => 'Declined: The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the card verification (CV) check',
|
24
|
+
'231' => 'Declined: Invalid account number, or the card type is not valid for the number provided. Please try a different card.',
|
25
|
+
'232' => 'Declined: The card type is not accepted by the payment processor. Please try a different card.',
|
26
|
+
'233' => 'Declined: General decline by the processor. Please try a different card.',
|
27
|
+
'234' => 'Declined: There is a problem with your CyberSource merchant configuration',
|
28
|
+
'235' => 'Declined: The requested amount exceeds the originally authorized amount.',
|
29
|
+
'236' => 'Declined: Processor failure. Please wait a few minutes and try again.',
|
30
|
+
'237' => 'Declined: The authorization has already been reversed',
|
31
|
+
'238' => 'Declined: The authorization has already been captured',
|
32
|
+
'239' => 'Declined: The requested transaction amount must match the previous transaction amount.',
|
33
|
+
'240' => 'Declined: The card type sent is invalid or does not correlate with the credit card number',
|
34
|
+
'241' => 'Declined: The request ID is invalid',
|
35
|
+
'242' => 'Declined: You requested a capture, but there is no corresponding, unused authorization record. Occurs if there was not a previously successful authorization request or if the previously successful authorization has already been used by another capture request',
|
36
|
+
'243' => 'Declined: The transaction has already been settled or reversed',
|
37
|
+
'246' => 'Declined: The capture or credit is not voidable because the capture or credit information has already been submitted to your processor. Or, you requested a void for a type of transaction that cannot be voided',
|
38
|
+
'247' => 'Declined: You requested a credit for a capture that was previously voided',
|
39
|
+
'250' => 'Error: The request was received, but there was a timeout at the payment processor. Please try again in a few minutes.',
|
40
|
+
'251' => "Declined: The Pinless Debit card's use frequency or maximum amount per use has been exceeded.",
|
41
|
+
'254' => 'Declined: Account is prohibited from processing stand-alone refunds.',
|
42
|
+
'400' => 'Declined: Fraud score exceeds threshold.',
|
43
|
+
'450' => 'Apartment number missing or not found. Please verify your address information and try again.',
|
44
|
+
'451' => 'Insufficient address information. Please verify your address information and try again.',
|
45
|
+
'452' => 'House/Box number not found on street. Please verify your address information and try again.',
|
46
|
+
'453' => 'Multiple address matches were found. Please verify your address information and try again.',
|
47
|
+
'454' => 'P.O. Box identifier not found or out of range. Please verify your address information and try again.',
|
48
|
+
'455' => 'Route service identifier not found or out of range. Please verify your address information and try again.',
|
49
|
+
'456' => 'Street name not found in Postal code. Please verify your address information and try again.',
|
50
|
+
'457' => 'Postal code not found in database. Please verify your address information and try again.',
|
51
|
+
'458' => 'Unable to verify or correct address. Please verify your address information and try again.',
|
52
|
+
'459' => 'Multiple international address matches were found. Please verify your address information and try again.',
|
53
|
+
'460' => 'Address match not found. Please verify your address information and try again.',
|
54
|
+
'461' => 'Error: Unsupported character set.',
|
55
|
+
'475' => 'Error: The cardholder is enrolled in Payer Authentication. Please authenticate the cardholder before continuing with the transaction.',
|
56
|
+
'476' => 'Error: Encountered a Payer Authentication problem. Payer could not be authenticated.',
|
57
|
+
'480' => 'The order is marked for review by the Cybersource Decision Manager',
|
58
|
+
'481' => 'Error: The order has been rejected by the Cybersource Decision Manager',
|
59
|
+
'520' => 'Declined: The authorization request was approved by the issuing bank but declined by CyberSource based on your Smart Authorization settings.'
|
60
|
+
}
|
61
|
+
|
62
|
+
def self.run(reason_code)
|
63
|
+
REASON_CODE_EXPLANATIONS.fetch(
|
64
|
+
reason_code,
|
65
|
+
"Declined: unknown reason (code #{reason_code})"
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.run!(reason_code)
|
70
|
+
if reason_code == '100'
|
71
|
+
self.run(reason_code)
|
72
|
+
else
|
73
|
+
raise Cybersourcery::CybersourceryError, self.run(reason_code)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Cybersourcery
|
2
|
+
class SignatureChecker
|
3
|
+
attr_reader :profile, :params
|
4
|
+
|
5
|
+
def initialize(args = {})
|
6
|
+
@profile = args[:profile]
|
7
|
+
@params = args[:params]
|
8
|
+
post_initialize(args)
|
9
|
+
end
|
10
|
+
|
11
|
+
# subclasses can override
|
12
|
+
def post_initialize(args)
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
signature == Cybersourcery::CybersourceSigner::Signer.signature(signature_message, @profile.secret_key)
|
18
|
+
end
|
19
|
+
|
20
|
+
def run!
|
21
|
+
raise Cybersourcery::CybersourceryError, 'Detected possible data tampering. Signatures do not match.' unless run
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def signed_field_names
|
27
|
+
raise NotImplementedError, "This #{self.class} cannot respond to:"
|
28
|
+
end
|
29
|
+
|
30
|
+
def signature
|
31
|
+
raise NotImplementedError, "This #{self.class} cannot respond to:"
|
32
|
+
end
|
33
|
+
|
34
|
+
def signature_message
|
35
|
+
signed_fields_keys = signed_field_names.split(',')
|
36
|
+
signed_fields = @params.select { |k, v| signed_fields_keys.include? k }
|
37
|
+
Cybersourcery::CybersourceSigner.signature_message(signed_fields, signed_fields_keys)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Cybersourcery
|
2
|
+
module Generators
|
3
|
+
class ConfigGenerator < Rails::Generators::Base
|
4
|
+
desc 'Creates a configuration file and an initializer file for the Cybersourcery gem'
|
5
|
+
|
6
|
+
def self.source_root
|
7
|
+
@source_root ||= File.expand_path('../templates', __FILE__)
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_config_file
|
11
|
+
template 'cybersourcery_profiles.yml', File.join('config', 'cybersourcery_profiles.yml')
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_initializer_file
|
15
|
+
template 'cybersourcery.rb', File.join('config', 'initializers', 'cybersourcery.rb')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
replace_this_key_with_your_cybersource_profile_id:
|
2
|
+
name: A nice description
|
3
|
+
service: test
|
4
|
+
access_key: your_access_key
|
5
|
+
secret_key: your_secret_key
|
6
|
+
success_url: http://your_optional_url_for_redirect_after_a_successful_transaction.com
|
7
|
+
transaction_type: sale,create_payment_token
|
8
|
+
endpoint_type: standard
|
9
|
+
payment_method: card
|
10
|
+
locale: en-us
|
11
|
+
currency: USD
|
12
|
+
unsigned_field_names: bill_to_email,bill_to_forename,bill_to_surname,bill_to_address_line1,bill_to_address_line2,bill_to_address_country,bill_to_address_state,bill_to_address_postal_code,bill_to_address_city,card_cvn,card_expiry_date,card_number,card_type
|
13
|
+
|
14
|
+
# you can have multiple profiles here
|
metadata
ADDED
@@ -0,0 +1,293 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cybersourcery
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Toppa
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: ruby-hmac
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.4'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.4'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.6'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.6'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.3'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: capybara
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.4'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.4'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: poltergeist
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.5'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.5'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec-rails
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: sqlite3
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.3'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ~>
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '1.3'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: slim-rails
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ~>
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 2.1.5
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ~>
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 2.1.5
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: bootstrap-sass
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ~>
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 3.2.0.1
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ~>
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 3.2.0.1
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: simple_form
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ~>
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 3.1.0.rc2
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ~>
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: 3.1.0.rc2
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: sass-rails
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ~>
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '4.0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ~>
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '4.0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: coffee-rails
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ~>
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '4.0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ~>
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '4.0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: jquery-rails
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ~>
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '3.1'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ~>
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '3.1'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: dotenv-rails
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - ~>
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0.11'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ~>
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0.11'
|
223
|
+
- !ruby/object:Gem::Dependency
|
224
|
+
name: cybersourcery_testing
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
226
|
+
requirements:
|
227
|
+
- - ~>
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
version: 0.0.2
|
230
|
+
type: :development
|
231
|
+
prerelease: false
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
233
|
+
requirements:
|
234
|
+
- - ~>
|
235
|
+
- !ruby/object:Gem::Version
|
236
|
+
version: 0.0.2
|
237
|
+
description: Cybersourcery takes care of the most difficult aspects of working with
|
238
|
+
Cybersource in Rails. It makes as few assumptions as possible about your business
|
239
|
+
requirements, allowing you to use any subset of features appropriate to your needs.
|
240
|
+
email:
|
241
|
+
- public@toppa.com
|
242
|
+
executables: []
|
243
|
+
extensions: []
|
244
|
+
extra_rdoc_files: []
|
245
|
+
files:
|
246
|
+
- LICENSE
|
247
|
+
- Rakefile
|
248
|
+
- lib/cybersourcery.rb
|
249
|
+
- lib/cybersourcery/cart_signature_checker.rb
|
250
|
+
- lib/cybersourcery/cart_signer.rb
|
251
|
+
- lib/cybersourcery/configuration.rb
|
252
|
+
- lib/cybersourcery/container.rb
|
253
|
+
- lib/cybersourcery/cybersource_params_normalizer.rb
|
254
|
+
- lib/cybersourcery/cybersource_signature_checker.rb
|
255
|
+
- lib/cybersourcery/cybersource_signer.rb
|
256
|
+
- lib/cybersourcery/exceptions.rb
|
257
|
+
- lib/cybersourcery/merchant_data_serializer.rb
|
258
|
+
- lib/cybersourcery/payment.rb
|
259
|
+
- lib/cybersourcery/payments_helper.rb
|
260
|
+
- lib/cybersourcery/profile.rb
|
261
|
+
- lib/cybersourcery/railtie.rb
|
262
|
+
- lib/cybersourcery/reason_code_checker.rb
|
263
|
+
- lib/cybersourcery/signature_checker.rb
|
264
|
+
- lib/cybersourcery/version.rb
|
265
|
+
- lib/rails/generators/cybersourcery/config/config_generator.rb
|
266
|
+
- lib/rails/generators/cybersourcery/config/templates/cybersourcery.rb
|
267
|
+
- lib/rails/generators/cybersourcery/config/templates/cybersourcery_profiles.yml
|
268
|
+
- lib/tasks/cybersourcery_tasks.rake
|
269
|
+
homepage: https://github.com/promptworks/cybersourcery
|
270
|
+
licenses: []
|
271
|
+
metadata: {}
|
272
|
+
post_install_message:
|
273
|
+
rdoc_options: []
|
274
|
+
require_paths:
|
275
|
+
- lib
|
276
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
277
|
+
requirements:
|
278
|
+
- - '>='
|
279
|
+
- !ruby/object:Gem::Version
|
280
|
+
version: '0'
|
281
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
282
|
+
requirements:
|
283
|
+
- - '>='
|
284
|
+
- !ruby/object:Gem::Version
|
285
|
+
version: '0'
|
286
|
+
requirements: []
|
287
|
+
rubyforge_project:
|
288
|
+
rubygems_version: 2.4.1
|
289
|
+
signing_key:
|
290
|
+
specification_version: 4
|
291
|
+
summary: A pain removal gem for working with Cybersource Secure Acceptance Silent
|
292
|
+
Order POST
|
293
|
+
test_files: []
|