kount_complete 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e167c870a61adbe09bdba84a062a208dc6fbbc28
4
+ data.tar.gz: 5f56607da3704188e926bb60136542d0cdbad985
5
+ SHA512:
6
+ metadata.gz: d4c52706b2d584bf7f5340077006b2ccab48021dd706a0a0e1ad139e851eda818c4a7199297694f3e6da94e1fe470f4fa5a2c765d5db4beceace8f12cec62654
7
+ data.tar.gz: 802ccd7df576560e41bc3dbb8919c3461591cbda111ead9e39fca84b2767927d5f5b4b7bedf1ed415a2399949adb096c2c2545b5b39f7c2bdda4ba83fe69de76
data/lib/kount.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'kount/client'
2
+ require 'kount/payment_types'
3
+
4
+ ##
5
+ # This module is the main entry point to the service wrapper.
6
+ # Its primary function is to collect the runtime options
7
+ # and return a Client object, on which all of the runtime
8
+ # integration takes place.
9
+ module Kount
10
+ # Creates the client object
11
+ #
12
+ # Expected options include:
13
+ # options = {
14
+ # :merchant_id => "MERCHANT_ID" # required (6 digit number)
15
+ # :ksalt => "KSALT" # required (provided by Kount)
16
+ # :key => "RIS_KEY" # required (created in the AWC web app)
17
+ # :endpoint => "RIS_ENDPOINT" # optional (default https://risk.kount.net)
18
+ # :version => "RIS_VERSION" # optional (defaults "0630")
19
+ # :is_test => "IS_TEST" # optional (defaults to false)
20
+ # }
21
+ # @param options Hash
22
+ def new(options = {})
23
+ fail ArgumentError, 'Config options required' if options.empty?
24
+ Client.new(options)
25
+ end
26
+
27
+ module_function :new
28
+ end
data/lib/kount/cart.rb ADDED
@@ -0,0 +1,36 @@
1
+ module Kount
2
+ ##
3
+ # This class handles cart data until the get_request is ready
4
+ # to push the data into the form fields
5
+ class Cart
6
+ attr_accessor :items
7
+
8
+ # Initialize cart object
9
+ def initialize
10
+ @items = []
11
+ end
12
+
13
+ # Add cart items
14
+ #
15
+ # @param item [String] Cart item name
16
+ # @param type [String] Cart type name
17
+ # @param desc [String] Cart item long description
18
+ # @param quant [String] Cart item quantity
19
+ # @param price [String] Cart item price in cents
20
+ def add_item(item, type, desc, quant, price)
21
+ @items << { TYPE: type,
22
+ DESC: desc,
23
+ ITEM: item,
24
+ QUANT: quant,
25
+ PRICE: price }
26
+ end
27
+
28
+ # Initialize an Inquiry object
29
+ #
30
+ # @param param [String] Param type: :TYPE, :DESC, :ITEM, :PRICE, or :QUANT
31
+ # @return [Array] Ordered array of the cart contents for each param type
32
+ def get_item(param)
33
+ @items.collect { |item| item[param] }
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,122 @@
1
+ require 'kount/security_mash'
2
+ require 'kount/cart'
3
+ require 'kount/request'
4
+ require 'kount/request/update'
5
+ require 'kount/request/inquiry'
6
+ require 'rest-client'
7
+ require 'uri'
8
+
9
+ # rubocop:disable Style/ClassVars
10
+ module Kount
11
+ ##
12
+ # This class is where the primary interaction with
13
+ # the merchant integration will take place.
14
+ class Client
15
+ # Tells the RIS server to respond in JSON instead of key/value pairs
16
+ # This cannot be overridden.
17
+ RESPONSE_FORMAT = 'JSON'
18
+
19
+ # RIS Version. Can be overridden my merchant if required.
20
+ DEFAULT_VERSION = '0630'
21
+
22
+ # Default endpoint for production. Used by the DEFAULT_OPTIONS
23
+ ENDPOINT_PROD = 'https://risk.kount.net'
24
+
25
+ # Default endpoint for test. Used by the TEST_DEFAULT_OPTIONS
26
+ ENDPOINT_TEST = 'https://risk.test.kount.net'
27
+
28
+ # Default params for production
29
+ PROD_DEFAULT_OPTIONS = {
30
+ endpoint: ENDPOINT_PROD,
31
+ version: DEFAULT_VERSION,
32
+ is_test: false
33
+ }
34
+
35
+ # Default params for test if is_test is TRUE
36
+ TEST_DEFAULT_OPTIONS = {
37
+ endpoint: ENDPOINT_TEST,
38
+ version: DEFAULT_VERSION
39
+ }
40
+
41
+ # Initialize a client object
42
+ #
43
+ # Example usage
44
+ # {:merchant_id => "123456", :key => "trhvihsrihsta7ftadk6edkre7y8..."}
45
+ #
46
+ # @param params [Hash] Hash with merchant_id, ksalt and key, plus any
47
+ # other optional params
48
+ def initialize(params = {})
49
+ @options = {}
50
+ if params[:is_test]
51
+ @options.merge!(TEST_DEFAULT_OPTIONS)
52
+ else
53
+ @options.merge!(PROD_DEFAULT_OPTIONS)
54
+ end
55
+ @options.merge!(params)
56
+ end
57
+
58
+ # Makes the call to the Kount RIS server
59
+ #
60
+ # @param request [Kount::Request] Kount inquiry or update object
61
+ # @return [Hash] RIS response formatted into a native hash
62
+ def get_response(request)
63
+ params = prepare_request_params(request)
64
+ response = RestClient::Resource.new(
65
+ endpoint,
66
+ verify_ssl: verify_ssl_option).post params, x_kount_api_key: key
67
+ begin
68
+ JSON.parse(response)
69
+ rescue
70
+ # RIS errors do not come back as JSON, so just pass them along raw.
71
+ response
72
+ end
73
+ end
74
+
75
+ # Give the request object what it needs to know to process the params
76
+ # to send to RIS.
77
+ def prepare_request_params(request)
78
+ request.prepare_params(version, merchant_id, RESPONSE_FORMAT, ksalt)
79
+ end
80
+
81
+ # Kount Merchant ID
82
+ def merchant_id
83
+ @options[:merchant_id]
84
+ end
85
+
86
+ # RIS Interface Version
87
+ def version
88
+ @options[:version]
89
+ end
90
+
91
+ # RIS Endpoint URL
92
+ def endpoint
93
+ @options[:endpoint]
94
+ end
95
+
96
+ # Merchant API for RIS acess
97
+ def key
98
+ @options[:key]
99
+ end
100
+
101
+ # Secret Kount salt for KHASH
102
+ def ksalt
103
+ @options[:ksalt]
104
+ end
105
+
106
+ # Is test or production setting
107
+ def test?
108
+ @options[:is_test]
109
+ end
110
+
111
+ private
112
+
113
+ # Helper method to turn on/off the SSL cert verify based on is_test config
114
+ def verify_ssl_option
115
+ if test?
116
+ OpenSSL::SSL::VERIFY_NONE
117
+ else
118
+ OpenSSL::SSL::VERIFY_PEER
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,50 @@
1
+ module Kount
2
+ ##
3
+ # Convenience class to provide a list of PTYP values
4
+ class PaymentTypes
5
+ # Credit card (VISA, MasterCard, Amercian Express, etc)
6
+ CREDIT_CARD = 'CARD'
7
+ # PayPal
8
+ PAYPAL = 'PYPL'
9
+ # Check
10
+ CHECK = 'CHEK'
11
+ # Merchant issued gift card (not the ones with VISA/MC on them)
12
+ GIFT_CARD = 'GIFT'
13
+ # Carte Bleue
14
+ CARTE_BLEUE = 'CARTE_BLEUE'
15
+ # Sofort
16
+ SOFORT = 'SOFORT'
17
+ # Elv
18
+ ELV = 'ELV'
19
+ # Poli
20
+ POLI = 'POLI'
21
+ # Neteller
22
+ NETELLER = 'NETELLER'
23
+ # Giropay
24
+ GIROPAY = 'GIROPAY'
25
+ # BPay
26
+ BPAY = 'BPAY'
27
+ # Interac
28
+ INTERAC = 'INTERAC'
29
+ # Apple Pay
30
+ APPLE_PAY = 'APAY'
31
+ # Skrill
32
+ SKRILL = 'SKRILL'
33
+ # Moneybooker (basically another name for Skrill)
34
+ MONEYBOOKERS = 'SKRILL'
35
+ # Mercado Pago
36
+ MERCADO_PAGO = 'MERCADE_PAGO'
37
+ # Bill Me Later
38
+ BILL_ME_LATER = 'BLML'
39
+ # Google Checkout
40
+ GOOGLE_CHECKOUT = 'GOOG'
41
+ # Green Dot Money Pack
42
+ GREEN_DOT_MONEY_PACK = 'GDMP'
43
+ # Single Euro Payments Area
44
+ SINGLE_EURO_PAYMENTS_AREA = 'SEPA'
45
+ # None
46
+ NONE = 'NONE'
47
+ # Other
48
+ OTHER = 'OTHER'
49
+ end
50
+ end
@@ -0,0 +1,41 @@
1
+ require 'kount/security_mash'
2
+ module Kount
3
+ ##
4
+ # This class acts as an abstract class for each type of request.
5
+ class Request
6
+ attr_accessor :params
7
+
8
+ # Initialize a Request object
9
+ #
10
+ # Example usage
11
+ # Not used directly. Use Inquiry or Update instead.
12
+ #
13
+ # @param initial_params [Hash] Initial params for request
14
+ def initialize(initial_params = {})
15
+ fail "Cannot directly instantiate a #{self.class}." if
16
+ self.class == Request
17
+ @params = initial_params
18
+ end
19
+
20
+ # Add params to the current request object
21
+ # @param hash [Hash] Hash of values to be added
22
+ def add_params(hash)
23
+ @params.merge!(hash)
24
+ end
25
+
26
+ # This method creates the final state of the params collection such that
27
+ # it can be sent to RIS. Items that are specific to either the Inquiry
28
+ # or Update calls are delegated to the prepare_params method in each
29
+ # respective class.
30
+ #
31
+ # @param version [String] RIS version
32
+ # @param merchant_id [String] Merchant ID
33
+ # @param response_format [String] Response format (JSON)
34
+ # @param _ksalt [String] Kount supplied secret salt for KHASH
35
+ def prepare_params(version, merchant_id, response_format, _ksalt = '')
36
+ # The KSALT is not used here, however, it is used in the corresponding
37
+ # subclass prepare_params methods.
38
+ params.merge!(VERS: version, MERC: merchant_id, FRMT: response_format)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,85 @@
1
+ module Kount
2
+ ##
3
+ # This class extends the Request class.
4
+ class Inquiry < Request
5
+ attr_accessor :cart
6
+
7
+ # Initialize an Inquiry object
8
+ #
9
+ # Example usage
10
+ # {:MACK => "Y", :AUTH => "A"}
11
+ #
12
+ # @param initial_params [Hash] Initial params for request
13
+ def initialize(initial_params = {})
14
+ super(initial_params)
15
+ @cart = Cart.new
16
+ # We want Request to default to MODE Q unless a different mode has
17
+ # been passed.
18
+ add_params(MODE: 'Q') unless initial_params.key?(:MODE)
19
+ end
20
+
21
+ # @param version [String] RIS version
22
+ # @param merchant_id [String] Merchant ID
23
+ # @param response_format [String] Response format (JSON)
24
+ # @param ksalt [String] Kount supplied secret salt for KHASH
25
+ def prepare_params(version, merchant_id, response_format, ksalt)
26
+ super(version, merchant_id, response_format, ksalt)
27
+ begin
28
+ params.merge! collect_cart_items
29
+ # The Kount::Request has no knowledge of the KSALT or merchant_id, both
30
+ # of which are needed for KHASH. Request form params have everything we
31
+ # need at this point to do the KHASH if needed.
32
+ fixup_payment_params(ksalt, merchant_id)
33
+ end
34
+ params
35
+ end
36
+
37
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
38
+ def fixup_payment_params(ksalt, merchant_id)
39
+ ptok = params[:PTOK]
40
+ case params[:PTYP]
41
+ when 'CARD'
42
+ ptok = Kount::SecurityMash.hash_credit_card(ptok, ksalt)
43
+ params.merge!(PTOK: ptok, PENC: 'KHASH')
44
+ when 'GIFT', 'OTHER'
45
+ ptok = Kount::SecurityMash.hash_gift_card(ptok, ksalt, merchant_id)
46
+ params.merge!(PTOK: ptok, PENC: 'KHASH')
47
+ when 'NONE'
48
+ params.merge!(PTOK: nil, PENC: nil)
49
+ else
50
+ params[:PENC] = 'NONE'
51
+ end
52
+ end
53
+
54
+ # Pulls the cart data into the request params hash
55
+ def collect_cart_items
56
+ {
57
+ PROD_TYPE: cart.get_item(:TYPE),
58
+ PROD_DESC: cart.get_item(:DESC),
59
+ PROD_ITEM: cart.get_item(:ITEM),
60
+ PROD_PRICE: cart.get_item(:PRICE),
61
+ PROD_QUANT: cart.get_item(:QUANT)
62
+ }
63
+ end
64
+
65
+ # Puts the cart object into the request for processing
66
+ # @param cart [Kount::Cart] Cart object
67
+ def add_cart(cart)
68
+ @cart = cart
69
+ end
70
+
71
+ # Add UDF to request
72
+ # @param name [String] UDF label name
73
+ # @param value [String] UDF value
74
+ def add_udf(name, value)
75
+ @params.merge!("UDF[#{name}]" => value)
76
+ end
77
+
78
+ # Convenience method to create the payment params
79
+ # @param type [String] Payment type
80
+ # @param token [String] Payment token
81
+ def add_payment(type, token = '')
82
+ add_params(PTYP: type, PTOK: token)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,28 @@
1
+ module Kount
2
+ ##
3
+ # This class extends the Request class and is used in the
4
+ # process of sending updates to an existing transaction
5
+ # generated by a previous Inquiry request.
6
+ class Update < Request
7
+ # Initialize an Update object
8
+ #
9
+ # Example usage
10
+ # {:MACK => "Y", :AUTH => "A"}
11
+ #
12
+ # @param initial_params [Hash] Initial params for request
13
+ def initialize(initial_params = {})
14
+ super(initial_params)
15
+ # Default to mode U unless mode X is explicitly set
16
+ add_params(MODE: 'U') unless initial_params[:MODE] == 'X'
17
+ end
18
+
19
+ # @param version [String] RIS version
20
+ # @param merchant_id [String] Merchant ID
21
+ # @param response_format [String] Response format (JSON)
22
+ # @param ksalt [String] Kount supplied secret salt for KHASH
23
+ def prepare_params(version, merchant_id, response_format, ksalt)
24
+ super(version, merchant_id, response_format, ksalt)
25
+ params
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,82 @@
1
+ require 'digest/sha1'
2
+ module Kount
3
+ ##
4
+ # This class implements the Kount KHASH for cards and gift cards.
5
+ # rubocop:disable Style/Documentation
6
+ class SecurityMash
7
+ # @param plain_text [String] String to be hashed
8
+ # @param ptyp [String] Payment type code: CARD, GIFT, or OTHER
9
+ # @return [String] KHASH version of string
10
+ def self.hash_token(plain_text, ptyp, ksalt, merchant_id = '')
11
+ if ptyp == 'CARD'
12
+ hash_credit_card(plain_text, ksalt)
13
+ else
14
+ hash_gift_card(plain_text, ksalt, merchant_id)
15
+ end
16
+ end
17
+
18
+ # Hash a credit card number.
19
+ # Preserves first six characters of the input so that hashed cards can be
20
+ # categorized by Bank Identification Number (BIN).
21
+ #
22
+ # Example usage:
23
+ # hashed = Kount::SecurityMash.hash_credit_card("4111111111111111")
24
+ # Expect: 411111WMS5YA6FUZA1KC
25
+ # hashed = Kount::SecurityMash.hash_credit_card("5199185454061655")
26
+ # Expect: 5199182NOQRXNKTTFL11
27
+ # hashed = Kount::SecurityMash.hash_credit_card("4259344583883")
28
+ # Expect: 425934FEXQI1QS6TH2O5
29
+ #
30
+ # @param plain_text [String] String to be hashed
31
+ # @return [String] KHASH version of string
32
+ def self.hash_credit_card(plain_text, ksalt)
33
+ return plain_text if khashed?(plain_text)
34
+ first_six = plain_text[0..5]
35
+ mashed = mash(plain_text, 14, ksalt)
36
+ "#{first_six}#{mashed}"
37
+ end
38
+
39
+ # Hash a gift card number.
40
+ # Use the six characters of the merchant id so that hashed cards can be
41
+ # unique across the entire domain.
42
+ #
43
+ # Example usage:
44
+ # hashed = Kount::SecurityMash.hash_gift_card("123456", "3245876")
45
+ # Expect: 1234569HXH32Y5NNJCGB
46
+
47
+ # @param plain_text [String] String to be hashed
48
+ # @return [String] KHASH version of string
49
+ def self.hash_gift_card(plain_text, ksalt, merchant_id)
50
+ mashed = mash(plain_text, 14, ksalt)
51
+ "#{merchant_id}#{mashed}"
52
+ end
53
+
54
+ # Compute a base64 hash of the provided data.
55
+ #
56
+ # @param data [String] Data to hash
57
+ # @param len [int] Length of hash to retain
58
+ # @return [String] Hashed data
59
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
60
+ def self.mash(data, len, m)
61
+ a = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
62
+ r = Digest::SHA1.hexdigest("#{data}.#{m}")
63
+ c = ''
64
+ len = 17 if len > 17
65
+ limit = 2 * len
66
+ i = 0
67
+ while i < limit
68
+ c << a[r[i..i + 6].to_i(16) % 36]
69
+ i += 2
70
+ end
71
+ c
72
+ end
73
+
74
+ # end mash
75
+
76
+ # @param val [String] Token that may or may not be khashed
77
+ # @return [Boolean] True if token is already khashed
78
+ def self.khashed?(val)
79
+ true if val =~ /(\d{6}[A-Z0-9]{14})/
80
+ end
81
+ end # end KountSecurityMash
82
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kount_complete
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Brandon Thompson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.8'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.8.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.8'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.8.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: rspec
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ description: A wrapper to facilitate making Kount RIS and API calls
48
+ email: bst@keynetics.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - lib/kount.rb
54
+ - lib/kount/cart.rb
55
+ - lib/kount/client.rb
56
+ - lib/kount/payment_types.rb
57
+ - lib/kount/request.rb
58
+ - lib/kount/request/inquiry.rb
59
+ - lib/kount/request/update.rb
60
+ - lib/kount/security_mash.rb
61
+ homepage: http://rubygems.org/gems/kount_complete
62
+ licenses:
63
+ - MIT
64
+ metadata: {}
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 1.9.3
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 1.3.5
79
+ requirements: []
80
+ rubyforge_project:
81
+ rubygems_version: 2.4.5
82
+ signing_key:
83
+ specification_version: 4
84
+ summary: Kount Complete Services Wrapper
85
+ test_files: []
86
+ has_rdoc: