kount_complete 1.0.4

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 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: