kount_complete 2.2.0 → 3.0.0
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 +4 -4
- data/lib/kount/Response.rb +62 -61
- data/lib/kount/client.rb +120 -17
- data/lib/kount/config.rb +1 -1
- data/lib/kount/payment_types.rb +21 -23
- data/lib/kount/request/inquiry.rb +8 -12
- data/lib/kount/request.rb +2 -1
- data/lib/kount/security_mash.rb +15 -70
- data/lib/kount/utils/khash.rb +49 -32
- metadata +6 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0594c812d04334112250610f423e7f3f1bcd57a08395df9ba2ce74a92c72a81
|
4
|
+
data.tar.gz: 829832f26be3fe70c4620920983abd2ee7f5b1f7ca3ef83cbc5df7fb01dcdbc7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1c97349871d6aabef60e0598c8dad20d3a0888341302fbeb853457717eeed9b5ba8ee6143ccc3dc75f4b00cb8bccf8b8c88302a3c666487fe21f516738d1413
|
7
|
+
data.tar.gz: 938011bc69fa002935991fb6127f17e997fa7561040038474cbd6118afa6f296ad176c5f576b75a2e8d7d9b86c6feac56b12f3631ece08239d91dfff434fae82
|
data/lib/kount/Response.rb
CHANGED
@@ -10,287 +10,287 @@ module Response
|
|
10
10
|
|
11
11
|
def get_mode
|
12
12
|
modes = @paramlist['MODE'].to_s
|
13
|
-
|
13
|
+
modes unless modes.empty?
|
14
14
|
end
|
15
15
|
|
16
16
|
def get_version
|
17
17
|
vers = @paramlist['VERS'].to_s
|
18
|
-
|
18
|
+
vers unless vers.empty?
|
19
19
|
end
|
20
20
|
|
21
21
|
def get_transaction_id
|
22
22
|
tran = @paramlist['TRAN'].to_s
|
23
|
-
|
23
|
+
tran unless tran.empty?
|
24
24
|
end
|
25
25
|
|
26
26
|
def get_merchant_id
|
27
27
|
merchantid = @paramlist['MERC'].to_s
|
28
|
-
|
28
|
+
merchantid unless merchantid.empty?
|
29
29
|
end
|
30
30
|
|
31
31
|
def get_session_id
|
32
32
|
sessionid = @paramlist['SESS'].to_s
|
33
|
-
|
33
|
+
sessionid unless sessionid.empty?
|
34
34
|
end
|
35
35
|
|
36
36
|
def get_order_number
|
37
37
|
orderno = @paramlist['ORDR'].to_s
|
38
|
-
|
38
|
+
orderno unless orderno.empty?
|
39
39
|
end
|
40
40
|
|
41
41
|
def get_site
|
42
42
|
site = @paramlist['SITE'].to_s
|
43
|
-
|
43
|
+
site unless site.empty?
|
44
44
|
end
|
45
45
|
|
46
46
|
def get_auto
|
47
47
|
auto = @paramlist['AUTO'].to_s
|
48
|
-
|
48
|
+
auto unless auto.empty?
|
49
49
|
end
|
50
50
|
|
51
51
|
def get_score
|
52
52
|
score = @paramlist['SCOR'].to_s
|
53
|
-
|
53
|
+
score unless score.empty?
|
54
54
|
end
|
55
55
|
|
56
56
|
def get_omniscore
|
57
57
|
omniscore = @paramlist['OMNISCORE'].to_s
|
58
|
-
|
58
|
+
omniscore unless omniscore.empty?
|
59
59
|
end
|
60
60
|
|
61
61
|
def get_geox
|
62
62
|
geox = @paramlist['GEOX'].to_s
|
63
|
-
|
63
|
+
geox unless geox.empty?
|
64
64
|
end
|
65
65
|
|
66
66
|
def get_brand
|
67
67
|
brand = @paramlist['BRND'].to_s
|
68
|
-
|
68
|
+
brand unless brand.empty?
|
69
69
|
end
|
70
70
|
|
71
71
|
def get_velo
|
72
72
|
velo = @paramlist['VELO'].to_s
|
73
|
-
|
73
|
+
velo unless velo.empty?
|
74
74
|
end
|
75
75
|
|
76
76
|
def get_vmax
|
77
77
|
vmax = @paramlist['VMAX'].to_s
|
78
|
-
|
78
|
+
vmax unless vmax.empty?
|
79
79
|
end
|
80
80
|
|
81
81
|
def get_network
|
82
82
|
network = @paramlist['NETW'].to_s
|
83
|
-
|
83
|
+
network unless network.empty?
|
84
84
|
end
|
85
85
|
|
86
86
|
def get_region
|
87
87
|
region = @paramlist['REGN'].to_s
|
88
|
-
|
88
|
+
region unless region.empty?
|
89
89
|
end
|
90
90
|
|
91
91
|
def get_kaptcha
|
92
92
|
kapt = @paramlist['KAPT'].to_s
|
93
|
-
|
93
|
+
kapt unless kapt.empty?
|
94
94
|
end
|
95
95
|
|
96
96
|
def get_proxy
|
97
97
|
proxy = @paramlist['PROXY'].to_s
|
98
|
-
|
98
|
+
proxy unless proxy.empty?
|
99
99
|
end
|
100
100
|
|
101
101
|
def get_emails
|
102
102
|
email = @paramlist['EMAILS'].to_s
|
103
|
-
|
103
|
+
email unless email.empty?
|
104
104
|
end
|
105
105
|
|
106
106
|
def get_http_country
|
107
107
|
httmcountry = @paramlist['HTTP_COUNTRY'].to_s
|
108
|
-
|
108
|
+
httmcountry unless httmcountry.empty?
|
109
109
|
end
|
110
110
|
|
111
111
|
def get_timezone
|
112
112
|
timezone = @paramlist['TIMEZONE'].to_s
|
113
|
-
|
113
|
+
timezone unless timezone.empty?
|
114
114
|
end
|
115
115
|
|
116
116
|
def get_cards
|
117
117
|
cards = @paramlist['CARDS'].to_s
|
118
|
-
|
118
|
+
cards unless cards.empty?
|
119
119
|
end
|
120
120
|
|
121
121
|
def get_pc_remote
|
122
122
|
pcremote = @paramlist['PC_REMOTE'].to_s
|
123
|
-
|
123
|
+
pcremote unless pcremote.empty?
|
124
124
|
end
|
125
125
|
|
126
126
|
def get_devices
|
127
127
|
devices = @paramlist['DEVICES'].to_s
|
128
|
-
|
128
|
+
devices unless devices.empty?
|
129
129
|
end
|
130
130
|
|
131
131
|
def get_device_layers
|
132
132
|
device_layers = @paramlist['DEVICE_LAYERS'].to_s
|
133
|
-
|
133
|
+
device_layers unless device_layers.empty?
|
134
134
|
end
|
135
135
|
|
136
136
|
def get_mobile_forwarder
|
137
137
|
mobile_forwarder = @paramlist['MOBILE_FORWARDER'].to_s
|
138
|
-
|
138
|
+
mobile_forwarder unless mobile_forwarder.empty?
|
139
139
|
end
|
140
140
|
|
141
141
|
def get_voice_device
|
142
142
|
voicedevice = @paramlist['VOICE_DEVICE'].to_s
|
143
|
-
|
143
|
+
voicedevice unless voicedevice.empty?
|
144
144
|
end
|
145
145
|
|
146
146
|
def get_local_time
|
147
147
|
localtime = @paramlist['LOCALTIME'].to_s
|
148
|
-
|
148
|
+
localtime unless localtime.empty?
|
149
149
|
end
|
150
150
|
|
151
151
|
def get_mobile_type
|
152
152
|
mobiletype = @paramlist['MOBILE_TYPE'].to_s
|
153
|
-
|
153
|
+
mobiletype unless mobiletype.empty?
|
154
154
|
end
|
155
155
|
|
156
156
|
def get_fingerprint
|
157
157
|
fingerprint = @paramlist['FINGERPRINT'].to_s
|
158
|
-
|
158
|
+
fingerprint unless fingerprint.empty?
|
159
159
|
end
|
160
160
|
|
161
161
|
def get_flash
|
162
162
|
flash = @paramlist['FLASH'].to_s
|
163
|
-
|
163
|
+
flash unless flash.empty?
|
164
164
|
end
|
165
165
|
|
166
166
|
def get_language
|
167
167
|
language = @paramlist['LANGUAGE'].to_s
|
168
|
-
|
168
|
+
language unless language.empty?
|
169
169
|
end
|
170
170
|
|
171
171
|
def get_country
|
172
172
|
country = @paramlist['COUNTRY'].to_s
|
173
|
-
|
173
|
+
country unless country.empty?
|
174
174
|
end
|
175
175
|
|
176
176
|
def get_javascript
|
177
177
|
javascript = @paramlist['JAVASCRIPT'].to_s
|
178
|
-
|
178
|
+
javascript unless javascript.empty?
|
179
179
|
end
|
180
180
|
|
181
181
|
def get_cookies
|
182
182
|
cookie = @paramlist['COOKIES'].to_s
|
183
|
-
|
183
|
+
cookie unless cookie.empty?
|
184
184
|
end
|
185
185
|
|
186
186
|
def get_mobile_device
|
187
187
|
mobiledevice = @paramlist['MOBILE_DEVICE'].to_s
|
188
|
-
|
188
|
+
mobiledevice unless mobiledevice.empty?
|
189
189
|
end
|
190
190
|
|
191
191
|
def get_pierced_ipaddress
|
192
192
|
pip_address = @paramlist['PIP_IPAD'].to_s
|
193
|
-
|
193
|
+
pip_address unless pip_address.empty?
|
194
194
|
end
|
195
195
|
|
196
196
|
def get_piercedipaddress_latitude
|
197
197
|
pip_lat = @paramlist['PIP_LAT'].to_s
|
198
|
-
|
198
|
+
pip_lat unless pip_lat.empty?
|
199
199
|
end
|
200
200
|
|
201
201
|
def get_piercedipaddress_longitude
|
202
202
|
pip_long = @paramlist['PIP_LON'].to_s
|
203
|
-
|
203
|
+
pip_long unless pip_long.empty?
|
204
204
|
end
|
205
205
|
|
206
206
|
def get_piercedipaddress_country
|
207
207
|
pip_country = @paramlist['PIP_COUNTRY'].to_s
|
208
|
-
|
208
|
+
pip_country unless pip_country.empty?
|
209
209
|
end
|
210
210
|
|
211
211
|
def get_piercedipaddress_region
|
212
212
|
pip_region = @paramlist['PIP_REGION'].to_s
|
213
|
-
|
213
|
+
pip_region unless pip_region.empty?
|
214
214
|
end
|
215
215
|
|
216
216
|
def get_piercedipaddress_city
|
217
217
|
pip_city = @paramlist['PIP_CITY'].to_s
|
218
|
-
|
218
|
+
pip_city unless pip_city.empty?
|
219
219
|
end
|
220
220
|
|
221
221
|
def get_piercedipaddress_organization
|
222
222
|
pip_org = @paramlist['PIP_ORG'].to_s
|
223
|
-
|
223
|
+
pip_org unless pip_org.empty?
|
224
224
|
end
|
225
225
|
|
226
226
|
def get_ipaddress
|
227
227
|
ip_ipad = @paramlist['IP_IPAD'].to_s
|
228
|
-
|
228
|
+
ip_ipad unless ip_ipad.empty?
|
229
229
|
end
|
230
230
|
|
231
231
|
def get_ipaddress_latitude
|
232
232
|
ip_lat = @paramlist['IP_LAT'].to_s
|
233
|
-
|
233
|
+
ip_lat unless ip_lat.empty?
|
234
234
|
end
|
235
235
|
|
236
236
|
def get_previous_whitelisted
|
237
237
|
whitelisted = @paramlist['PREVIOUSLY_WHITELISTED'].to_s
|
238
|
-
|
238
|
+
whitelisted unless whitelisted.empty?
|
239
239
|
end
|
240
240
|
|
241
241
|
def get_secure_merchant_response
|
242
242
|
merchant_response = @paramlist['THREE_DS_MERCHANT_RESPONSE'].to_s
|
243
|
-
|
243
|
+
merchant_response unless merchant_response.empty?
|
244
244
|
end
|
245
245
|
|
246
246
|
def get_ipaddress_longitude
|
247
247
|
ip_long = @paramlist['IP_LON'].to_s
|
248
|
-
|
248
|
+
ip_long unless ip_long.empty?
|
249
249
|
end
|
250
250
|
|
251
251
|
def get_ipaddress_country
|
252
252
|
ip_country = @paramlist['IP_COUNTRY'].to_s
|
253
|
-
|
253
|
+
ip_country unless ip_country.empty?
|
254
254
|
end
|
255
255
|
|
256
256
|
def get_ipaddress_region
|
257
257
|
ip_region = @paramlist['IP_REGION'].to_s
|
258
|
-
|
258
|
+
ip_region unless ip_region.empty?
|
259
259
|
end
|
260
260
|
|
261
261
|
def get_ipaddress_city
|
262
262
|
ip_city = @paramlist['IP_CITY'].to_s
|
263
|
-
|
263
|
+
ip_city unless ip_city.empty?
|
264
264
|
end
|
265
265
|
|
266
266
|
def get_ipaddress_organization
|
267
267
|
ip_org = @paramlist['IP_ORG'].to_s
|
268
|
-
|
268
|
+
ip_org unless ip_org.empty?
|
269
269
|
end
|
270
270
|
|
271
271
|
def get_date_device_firstseen
|
272
272
|
ddfs = @paramlist['DDFS'].to_s
|
273
|
-
|
273
|
+
ddfs unless ddfs.empty?
|
274
274
|
end
|
275
275
|
|
276
276
|
def get_useragent_string
|
277
277
|
user_agent = @paramlist['UAS'].to_s
|
278
|
-
|
278
|
+
user_agent unless user_agent.empty?
|
279
279
|
end
|
280
280
|
|
281
281
|
def get_devicescreen_resolution
|
282
282
|
dsr = @paramlist['DSR'].to_s
|
283
|
-
|
283
|
+
dsr unless dsr.empty?
|
284
284
|
end
|
285
285
|
|
286
286
|
def get_os
|
287
287
|
os = @paramlist['OS'].to_s
|
288
|
-
|
288
|
+
os unless os.empty?
|
289
289
|
end
|
290
290
|
|
291
291
|
def get_browser
|
292
292
|
browser = @paramlist['BROWSER'].to_s
|
293
|
-
|
293
|
+
browser unless browser.empty?
|
294
294
|
end
|
295
295
|
|
296
296
|
def get_numberrules_triggered
|
@@ -327,14 +327,15 @@ module Response
|
|
327
327
|
@paramlist['ERROR_COUNT'].to_s
|
328
328
|
end
|
329
329
|
|
330
|
-
def
|
330
|
+
def get_errors
|
331
331
|
errors = []
|
332
|
-
error_count = get_error_count
|
333
|
-
(0..error_count
|
334
|
-
errors
|
332
|
+
error_count = get_error_count.to_i
|
333
|
+
(0..error_count - 1).each do |i|
|
334
|
+
errors << @paramlist["ERROR_#{i}"]
|
335
335
|
end
|
336
336
|
errors.compact
|
337
337
|
end
|
338
|
+
alias geterrors get_errors
|
338
339
|
|
339
340
|
def get_numbercounters_triggered
|
340
341
|
# changed due to rubocop styling rules for ruby
|
data/lib/kount/client.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
require '
|
1
|
+
require 'date'
|
2
2
|
require 'kount/cart'
|
3
3
|
require 'kount/request'
|
4
4
|
require 'kount/request/update'
|
5
5
|
require 'kount/request/inquiry'
|
6
|
-
require 'rest-client'
|
7
6
|
require 'uri'
|
8
7
|
require 'kount/utils/khash'
|
8
|
+
require 'net/https'
|
9
9
|
|
10
10
|
|
11
11
|
module Kount
|
@@ -26,9 +26,28 @@ module Kount
|
|
26
26
|
# Default endpoint for test. Used by the TEST_DEFAULT_OPTIONS
|
27
27
|
ENDPOINT_TEST = 'https://risk.test.kount.net'
|
28
28
|
|
29
|
+
# Default endpoint for Payments Fraud by Kount 360 production. Used by the DEFAULT_OPTIONS
|
30
|
+
PAYMENTS_FRAUD_API_ENDPOINT_PROD = 'https://api.kount.com/commerce/ris'
|
31
|
+
|
32
|
+
# Default endpoint for Payments Fraud by Kount 360 test. Used by the TEST_DEFAULT_OPTIONS
|
33
|
+
PAYMENTS_FRAUD_API_ENDPOINT_TEST = 'https://api-sandbox.kount.com/commerce/ris'
|
34
|
+
|
35
|
+
# Default endpoint for Payments Fraud by Kount 360 production. Used by the DEFAULT_OPTIONS
|
36
|
+
PAYMENTS_FRAUD_AUTH_ENDPOINT_PROD = 'https://login.kount.com/oauth2/ausdppksgrbyM0abp357/v1/token'
|
37
|
+
|
38
|
+
# Default endpoint for Payments Fraud by Kount 360 test. Used by the TEST_DEFAULT_OPTIONS
|
39
|
+
PAYMENTS_FRAUD_AUTH_ENDPOINT_TEST = 'https://login.kount.com/oauth2/ausdppkujzCPQuIrY357/v1/token'
|
40
|
+
|
41
|
+
# Migration mode enabled
|
42
|
+
@migration_mode_enabled = false
|
43
|
+
@access_token = ''
|
44
|
+
@token_expires_at = DateTime.now
|
45
|
+
|
29
46
|
# Default params for production
|
30
47
|
PROD_DEFAULT_OPTIONS = {
|
31
48
|
endpoint: ENDPOINT_PROD,
|
49
|
+
pf_api_endpoint: PAYMENTS_FRAUD_API_ENDPOINT_PROD,
|
50
|
+
pf_auth_endpoint: PAYMENTS_FRAUD_AUTH_ENDPOINT_PROD,
|
32
51
|
version: DEFAULT_VERSION,
|
33
52
|
is_test: false,
|
34
53
|
timeout: 10
|
@@ -37,6 +56,8 @@ module Kount
|
|
37
56
|
# Default params for test if is_test is TRUE
|
38
57
|
TEST_DEFAULT_OPTIONS = {
|
39
58
|
endpoint: ENDPOINT_TEST,
|
59
|
+
pf_api_endpoint: PAYMENTS_FRAUD_API_ENDPOINT_TEST,
|
60
|
+
pf_auth_endpoint: PAYMENTS_FRAUD_AUTH_ENDPOINT_TEST,
|
40
61
|
version: DEFAULT_VERSION,
|
41
62
|
timeout: 10
|
42
63
|
}
|
@@ -50,29 +71,53 @@ module Kount
|
|
50
71
|
# other optional params
|
51
72
|
def initialize(params = {})
|
52
73
|
@options = {}
|
74
|
+
migration_mode = params[:migration_mode_enabled]
|
75
|
+
if migration_mode.nil?
|
76
|
+
@migration_mode_enabled = false
|
77
|
+
else
|
78
|
+
@migration_mode_enabled = migration_mode.to_s.downcase == 'true'
|
79
|
+
end
|
80
|
+
|
53
81
|
if params[:is_test]
|
54
82
|
@options.merge!(TEST_DEFAULT_OPTIONS)
|
55
83
|
else
|
56
84
|
@options.merge!(PROD_DEFAULT_OPTIONS)
|
57
85
|
end
|
86
|
+
|
58
87
|
@options.merge!(params)
|
88
|
+
|
89
|
+
if @migration_mode_enabled
|
90
|
+
@options[:version] = DEFAULT_VERSION # this is needed for the intg to work correctly
|
91
|
+
end
|
59
92
|
end
|
60
93
|
|
61
94
|
# Makes the call to the Kount RIS server
|
62
95
|
#
|
63
96
|
# @param request [Kount::Request] Kount inquiry or update object
|
64
97
|
# @return [Hash] RIS response formatted into a native hash
|
98
|
+
# rubocop:disable Metrics/AbcSize
|
65
99
|
def get_response(request)
|
66
|
-
|
100
|
+
headers = {}
|
101
|
+
if @migration_mode_enabled
|
102
|
+
if @token_expires_at.nil? || DateTime.now >= @token_expires_at
|
103
|
+
refresh_pf_auth_token
|
104
|
+
if @access_token.nil? || @access_token == ''
|
105
|
+
raise RuntimeError, 'Access token could not be retrieved'
|
106
|
+
end
|
107
|
+
headers = pf_http_headers
|
108
|
+
headers.merge!({ 'Authorization': "Bearer #{@access_token}" })
|
109
|
+
end
|
110
|
+
else
|
111
|
+
headers = http_headers
|
112
|
+
end
|
113
|
+
|
114
|
+
payload = URI.encode_www_form(prepare_request_params(request))
|
67
115
|
response = {}
|
68
116
|
begin
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
JSON.parse(response)
|
75
|
-
rescue StandardError
|
117
|
+
resp = http.post(http_path, payload, headers)
|
118
|
+
response = JSON.parse(resp.body)
|
119
|
+
rescue StandardError => e
|
120
|
+
puts e
|
76
121
|
# RIS errors do not come back as JSON, so just pass them along raw.
|
77
122
|
response
|
78
123
|
end
|
@@ -86,6 +131,9 @@ module Kount
|
|
86
131
|
|
87
132
|
# Kount Merchant ID
|
88
133
|
def merchant_id
|
134
|
+
if @migration_mode_enabled
|
135
|
+
return @options[:pf_client_id]
|
136
|
+
end
|
89
137
|
@options[:merchant_id]
|
90
138
|
end
|
91
139
|
|
@@ -96,6 +144,9 @@ module Kount
|
|
96
144
|
|
97
145
|
# RIS Endpoint URL
|
98
146
|
def endpoint
|
147
|
+
if @migration_mode_enabled
|
148
|
+
return @options[:pf_api_endpoint]
|
149
|
+
end
|
99
150
|
@options[:endpoint]
|
100
151
|
end
|
101
152
|
|
@@ -104,7 +155,7 @@ module Kount
|
|
104
155
|
@options[:timeout]
|
105
156
|
end
|
106
157
|
|
107
|
-
# Merchant API for RIS
|
158
|
+
# Merchant API for RIS access
|
108
159
|
def key
|
109
160
|
@options[:key]
|
110
161
|
end
|
@@ -121,13 +172,65 @@ module Kount
|
|
121
172
|
|
122
173
|
private
|
123
174
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
175
|
+
def endpoint_uri
|
176
|
+
@endpoint_uri ||= URI(endpoint)
|
177
|
+
end
|
178
|
+
|
179
|
+
# rubocop:disable Metrics/AbcSize
|
180
|
+
def http
|
181
|
+
if endpoint_uri.host.nil? || endpoint_uri.port.nil?
|
182
|
+
raise ArgumentError, 'Invalid endpoint or port'
|
183
|
+
end
|
184
|
+
net_http = Net::HTTP.new(endpoint_uri.host, endpoint_uri.port)
|
185
|
+
if endpoint_uri.scheme == 'https'
|
186
|
+
net_http.use_ssl = true
|
187
|
+
net_http.verify_mode = test? ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
|
188
|
+
OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] |= OpenSSL::SSL::OP_IGNORE_UNEXPECTED_EOF
|
130
189
|
end
|
190
|
+
net_http.open_timeout = timeout
|
191
|
+
net_http.read_timeout = timeout
|
192
|
+
net_http.ignore_eof = true
|
193
|
+
net_http
|
194
|
+
end
|
195
|
+
|
196
|
+
def http_headers
|
197
|
+
{
|
198
|
+
'Accept' => 'application/json',
|
199
|
+
'Content-Type' => 'application/x-www-form-urlencoded',
|
200
|
+
'User-Agent' => "SDK-RIS-Ruby/#{Config::SDK_VERSION}",
|
201
|
+
'X-Kount-Api-Key' => key
|
202
|
+
}
|
203
|
+
end
|
204
|
+
|
205
|
+
def pf_http_headers
|
206
|
+
{
|
207
|
+
'Accept' => 'application/json',
|
208
|
+
'Content-Type' => 'application/x-www-form-urlencoded',
|
209
|
+
'User-Agent' => "SDK-RIS-Ruby/#{Config::SDK_VERSION}",
|
210
|
+
'Authorization' => 'Bearer '
|
211
|
+
}
|
212
|
+
end
|
213
|
+
|
214
|
+
# rubocop:disable Metrics/AbcSize
|
215
|
+
def refresh_pf_auth_token
|
216
|
+
payload = URI.encode_www_form({ grant_type: 'client_credentials', scope: 'k1_integration_api' })
|
217
|
+
headers = { Authorization: "Basic #{@options[:pf_api_key]}", 'Content-Type': 'application/x-www-form-urlencoded' }
|
218
|
+
uri = URI(@options[:pf_auth_endpoint])
|
219
|
+
client = Net::HTTP.new(uri.host, uri.port)
|
220
|
+
client.ignore_eof = true
|
221
|
+
client.use_ssl = true
|
222
|
+
response = client.post(@options[:pf_auth_endpoint], payload, headers)
|
223
|
+
|
224
|
+
return unless response.code == '200'
|
225
|
+
|
226
|
+
data = JSON.parse(response.body)
|
227
|
+
expires_in = data['expires_in'].to_i
|
228
|
+
@access_token = data['access_token']
|
229
|
+
@token_expires_at = DateTime.now.to_time + (expires_in - 60) # less 60 seconds for latency
|
230
|
+
end
|
231
|
+
|
232
|
+
def http_path
|
233
|
+
endpoint_uri.path.empty? ? '/' : endpoint_uri.path
|
131
234
|
end
|
132
235
|
end
|
133
236
|
end
|
data/lib/kount/config.rb
CHANGED
data/lib/kount/payment_types.rb
CHANGED
@@ -3,50 +3,48 @@ module Kount
|
|
3
3
|
# Convenience class to provide a list of PTYP values
|
4
4
|
class PaymentTypes
|
5
5
|
# Credit card (VISA, MasterCard, Amercian Express, etc)
|
6
|
-
CREDIT_CARD
|
6
|
+
CREDIT_CARD = 'CARD'
|
7
7
|
#Generic Token
|
8
|
-
TOKEN
|
8
|
+
TOKEN = 'TOKEN'
|
9
9
|
# PayPal
|
10
|
-
PAYPAL
|
10
|
+
PAYPAL = 'PYPL'
|
11
11
|
# Check
|
12
|
-
CHECK
|
12
|
+
CHECK = 'CHEK'
|
13
13
|
# Merchant issued gift card (not the ones with VISA/MC on them)
|
14
|
-
GIFT_CARD
|
14
|
+
GIFT_CARD = 'GIFT'
|
15
15
|
# Carte Bleue
|
16
|
-
CARTE_BLEUE
|
16
|
+
CARTE_BLEUE = 'CARTE_BLEUE'
|
17
17
|
# Sofort
|
18
|
-
SOFORT
|
18
|
+
SOFORT = 'SOFORT'
|
19
19
|
# Elv
|
20
|
-
ELV
|
20
|
+
ELV = 'ELV'
|
21
21
|
# Poli
|
22
|
-
POLI
|
22
|
+
POLI = 'POLI'
|
23
23
|
# Neteller
|
24
|
-
NETELLER
|
24
|
+
NETELLER = 'NETELLER'
|
25
25
|
# Giropay
|
26
|
-
GIROPAY
|
26
|
+
GIROPAY = 'GIROPAY'
|
27
27
|
# BPay
|
28
|
-
BPAY
|
28
|
+
BPAY = 'BPAY'
|
29
29
|
# Interac
|
30
|
-
INTERAC
|
30
|
+
INTERAC = 'INTERAC'
|
31
31
|
# Apple Pay
|
32
|
-
APPLE_PAY
|
32
|
+
APPLE_PAY = 'APAY'
|
33
33
|
# Skrill
|
34
|
-
SKRILL
|
34
|
+
SKRILL = 'SKRILL'
|
35
35
|
# Moneybooker (basically another name for Skrill)
|
36
|
-
MONEYBOOKERS
|
36
|
+
MONEYBOOKERS = 'SKRILL'
|
37
37
|
# Mercado Pago
|
38
|
-
MERCADO_PAGO
|
38
|
+
MERCADO_PAGO = 'MERCADE_PAGO'
|
39
39
|
# Bill Me Later
|
40
|
-
BILL_ME_LATER
|
40
|
+
BILL_ME_LATER = 'BLML'
|
41
41
|
# Google Checkout
|
42
|
-
GOOGLE_CHECKOUT
|
42
|
+
GOOGLE_CHECKOUT = 'GOOG'
|
43
43
|
# Green Dot Money Pack
|
44
|
-
GREEN_DOT_MONEY_PACK
|
44
|
+
GREEN_DOT_MONEY_PACK = 'GDMP'
|
45
45
|
# Single Euro Payments Area
|
46
46
|
SINGLE_EURO_PAYMENTS_AREA = 'SEPA'
|
47
47
|
# None
|
48
|
-
NONE
|
49
|
-
# Other
|
50
|
-
OTHER = 'OTHER'
|
48
|
+
NONE = 'NONE'
|
51
49
|
end
|
52
50
|
end
|
@@ -38,23 +38,19 @@ module Kount
|
|
38
38
|
|
39
39
|
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
40
40
|
def fixup_payment_params(ksalt, merchant_id)
|
41
|
-
ptok = params[:PTOK]
|
42
41
|
case params[:PTYP]
|
43
|
-
when 'CARD'
|
44
|
-
|
45
|
-
ptok = Kount::Khash.hash_payment_token(
|
42
|
+
when 'CARD'
|
43
|
+
return if params[:PENC] == 'MASK'
|
44
|
+
ptok = Kount::Khash.hash_payment_token(params[:PTOK], ksalt)
|
46
45
|
params.merge!(PTOK: ptok, PENC: 'KHASH')
|
47
|
-
when '
|
48
|
-
|
49
|
-
ptok = Kount::Khash.hash_gift_card(ptok, ksalt, merchant_id)
|
46
|
+
when 'CHEK', 'PYPL'
|
47
|
+
ptok = Kount::Khash.hash_payment_token(params[:PTOK], ksalt)
|
50
48
|
params.merge!(PTOK: ptok, PENC: 'KHASH')
|
51
|
-
when '
|
52
|
-
ptok = Kount::Khash.
|
49
|
+
when 'GIFT'
|
50
|
+
ptok = Kount::Khash.hash_gift_card(params[:PTOK], ksalt, merchant_id)
|
53
51
|
params.merge!(PTOK: ptok, PENC: 'KHASH')
|
54
52
|
when 'NONE'
|
55
|
-
params.merge!(PTOK: nil
|
56
|
-
else
|
57
|
-
params[:PENC] ||= 'NONE'
|
53
|
+
params.merge!(PTOK: nil)
|
58
54
|
end
|
59
55
|
end
|
60
56
|
|
data/lib/kount/request.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'kount/security_mash'
|
2
1
|
module Kount
|
3
2
|
##
|
4
3
|
# This class acts as an abstract class for each type of request.
|
@@ -37,9 +36,11 @@ module Kount
|
|
37
36
|
end
|
38
37
|
|
39
38
|
# Add LBIN to request
|
39
|
+
# <b>DEPRECATED:</b> Please provide <tt>in the request constructor hash param</tt> instead.
|
40
40
|
# Supports BIN lengths of 6 digits or greater
|
41
41
|
# @param lbin [String] Long Bank Identification Number
|
42
42
|
def add_lbin(lbin)
|
43
|
+
warn "[DEPRECATION] LBIN should be provided in the constructor hash instead"
|
43
44
|
params.merge!(LBIN: lbin)
|
44
45
|
end
|
45
46
|
end
|
data/lib/kount/security_mash.rb
CHANGED
@@ -1,82 +1,27 @@
|
|
1
|
-
require 'digest/sha1'
|
2
1
|
module Kount
|
3
|
-
##
|
4
|
-
# This class implements the Kount KHASH for cards and gift cards.
|
5
|
-
|
6
2
|
class SecurityMash
|
7
|
-
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
if ptyp == 'CARD'
|
12
|
-
hash_credit_card(plain_text, ksalt)
|
13
|
-
else
|
14
|
-
hash_gift_card(plain_text, ksalt, merchant_id)
|
15
|
-
end
|
3
|
+
|
4
|
+
# <b>DEPRECATED:</b> This function should not be used. It duplicates the concerns of Kount::Inquiry.fixup_payment_params.
|
5
|
+
def self.hash_token(_plain_text, _ptyp, _ksalt, _merchant_id = '')
|
6
|
+
raise "do not use this function, prefer to use Kount::Inquiry.fixup_payment_params"
|
16
7
|
end
|
17
8
|
|
18
|
-
#
|
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
|
9
|
+
# <b>DEPRECATED:</b> Use Kount::Khash.hash_payment_token instead.
|
32
10
|
def self.hash_credit_card(plain_text, ksalt)
|
33
|
-
|
34
|
-
|
35
|
-
mashed = mash(plain_text, 14, ksalt)
|
36
|
-
"#{first_six}#{mashed}"
|
11
|
+
warn "[DEPRECATION] use Kount::Khash.hash_payment_token instead"
|
12
|
+
Kount::Khash.hash_payment_token(plain_text, ksalt)
|
37
13
|
end
|
38
|
-
|
39
|
-
#
|
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
|
14
|
+
|
15
|
+
# <b>DEPRECATED:</b> Use Kount::Khash.hash_gift_card instead.
|
49
16
|
def self.hash_gift_card(plain_text, ksalt, merchant_id)
|
50
|
-
|
51
|
-
|
17
|
+
warn "[DEPRECATION] use Kount::Khash.has_gift_card instead"
|
18
|
+
Kount::Khash.hash_gift_card(plain_text, ksalt, merchant_id)
|
52
19
|
end
|
53
20
|
|
54
|
-
#
|
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
|
21
|
+
# <b>DEPRECATED:</b> Use Kount::Khash.hash_gift_card instead.
|
60
22
|
def self.mash(data, len, m)
|
61
|
-
|
62
|
-
|
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})/
|
23
|
+
warn "[DEPRECATION] use Kount::Khash.getkhash instead"
|
24
|
+
Kount::Khash.getkhash(data, len, m)
|
80
25
|
end
|
81
|
-
end
|
26
|
+
end
|
82
27
|
end
|
data/lib/kount/utils/khash.rb
CHANGED
@@ -1,21 +1,58 @@
|
|
1
1
|
module Kount
|
2
|
-
|
2
|
+
module Khash
|
3
|
+
# Hash a PAN.
|
4
|
+
#
|
5
|
+
# Preserves first six characters of the input so that hashed cards can be
|
6
|
+
# categorized by Bank Identification Number (BIN).
|
7
|
+
#
|
8
|
+
# Example usage:
|
9
|
+
# hashed = Kount::Khash.hash_payment_token("4111111111111111", ksalt)
|
10
|
+
# Expect: 411111WMS5YA6FUZA1KC
|
11
|
+
#
|
3
12
|
# @param plain_text [String] String to be hashed
|
4
|
-
# @param
|
13
|
+
# @param ksalt [String] The kount khash salt provided by Kount
|
14
|
+
#
|
5
15
|
# @return [String] KHASH version of string
|
6
|
-
def self.
|
7
|
-
|
16
|
+
def self.hash_payment_token(plain_text, ksalt)
|
17
|
+
return plain_text if khashed?(plain_text)
|
18
|
+
mashed = getkhash(plain_text, 14, ksalt)
|
19
|
+
"#{plain_text[0..5]}#{mashed}"
|
20
|
+
end
|
8
21
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
HashCheckPayment(plain_text, ksalt)
|
14
|
-
else
|
15
|
-
HashGiftCard(plain_text, ksalt, merchant_id)
|
16
|
-
end
|
22
|
+
# <b>DEPRECATED:</b> Use Kount::Khash.hash_payment_token instead.
|
23
|
+
def self.hash_check_payment(plain_text, ksalt)
|
24
|
+
warn "[DEPRECATION] use Kount::Khash.hash_payment_token instead"
|
25
|
+
hash_payment_token(plain_text, ksalt)
|
17
26
|
end
|
18
27
|
|
28
|
+
# Hash a gift card number.
|
29
|
+
#
|
30
|
+
# Use the six characters of the merchant id so that hashed cards can be
|
31
|
+
# unique across the entire domain.
|
32
|
+
#
|
33
|
+
# Example usage:
|
34
|
+
# hashed = Kount::SecurityMash.hash_gift_card("3245876", salt, "123456")
|
35
|
+
# Expect: 1234569HXH32Y5NNJCGB
|
36
|
+
#
|
37
|
+
# @param plain_text [String] String to be hashed
|
38
|
+
# @param ksalt [String] The kount khash salt provided by Kount
|
39
|
+
# @param merchant_id [String] The merchant id that will serve as the common domain of all gift
|
40
|
+
# cards
|
41
|
+
#
|
42
|
+
# @return [String] KHASH version of string
|
43
|
+
def self.hash_gift_card(plain_text, ksalt, merchant_id)
|
44
|
+
return plain_text if khashed?(plain_text)
|
45
|
+
mashed = getkhash(plain_text, 14, ksalt)
|
46
|
+
"#{merchant_id}#{mashed}"
|
47
|
+
end
|
48
|
+
|
49
|
+
# Compute a base64 hash of the provided data.
|
50
|
+
#
|
51
|
+
# @param data [String] Data to hash
|
52
|
+
# @param len [int] Length of hash to retain
|
53
|
+
# @param m [String] The kount khash salt
|
54
|
+
#
|
55
|
+
# @return [String] Hashed data
|
19
56
|
def self.getkhash(data, len, m)
|
20
57
|
a = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
21
58
|
r = Digest::SHA1.hexdigest("#{data}.#{m}")
|
@@ -30,30 +67,10 @@ module Kount
|
|
30
67
|
c
|
31
68
|
end
|
32
69
|
|
33
|
-
def self.hash_payment_token(plain_text, ksalt)
|
34
|
-
return plain_text if khashed?(plain_text)
|
35
|
-
first_six = plain_text[0..5]
|
36
|
-
mashed = getkhash(plain_text, 14, ksalt)
|
37
|
-
"#{first_six}#{mashed}"
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.hash_check_payment(plain_text, ksalt)
|
41
|
-
return plain_text if khashed?(plain_text)
|
42
|
-
first_six = plain_text[0..5]
|
43
|
-
mashed = getkhash(plain_text, 14, ksalt)
|
44
|
-
"#{first_six}#{mashed}"
|
45
|
-
end
|
46
|
-
|
47
|
-
def self.hash_gift_card(plain_text, ksalt, merchant_id)
|
48
|
-
mashed = getkhash(plain_text, 14, ksalt)
|
49
|
-
"#{merchant_id}#{mashed}"
|
50
|
-
end
|
51
|
-
|
52
70
|
# @param val [String] Token that may or may not be khashed
|
53
71
|
# @return [Boolean] True if token is already khashed
|
54
72
|
def self.khashed?(val)
|
55
73
|
true if val =~ /(\d{6}[A-Z0-9]{14})/
|
56
74
|
end
|
57
|
-
|
58
75
|
end
|
59
76
|
end
|
metadata
CHANGED
@@ -1,49 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kount_complete
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kount
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
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.0
|
20
|
-
- - "<"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 3.0.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.0
|
30
|
-
- - "<"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: 3.0.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'
|
10
|
+
date: 2025-02-24 00:00:00.000000000 Z
|
11
|
+
dependencies: []
|
47
12
|
description: A wrapper to facilitate making Kount RIS calls
|
48
13
|
email: ruby@kount.com
|
49
14
|
executables: []
|
@@ -65,7 +30,6 @@ homepage: http://rubygems.org/gems/kount_complete
|
|
65
30
|
licenses:
|
66
31
|
- MIT
|
67
32
|
metadata: {}
|
68
|
-
post_install_message:
|
69
33
|
rdoc_options: []
|
70
34
|
require_paths:
|
71
35
|
- lib
|
@@ -73,15 +37,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
73
37
|
requirements:
|
74
38
|
- - ">="
|
75
39
|
- !ruby/object:Gem::Version
|
76
|
-
version:
|
40
|
+
version: 3.2.7
|
77
41
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
42
|
requirements:
|
79
43
|
- - ">="
|
80
44
|
- !ruby/object:Gem::Version
|
81
|
-
version:
|
45
|
+
version: 3.6.2
|
82
46
|
requirements: []
|
83
|
-
rubygems_version: 3.
|
84
|
-
signing_key:
|
47
|
+
rubygems_version: 3.6.5
|
85
48
|
specification_version: 4
|
86
49
|
summary: Kount Complete Services Wrapper
|
87
50
|
test_files: []
|