cybersourcery 0.0.6
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/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: []
|