blockchyp 1.24.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Makefile +78 -0
- data/README.md +3917 -0
- data/Rakefile +39 -0
- data/lib/blockchyp/version.rb +5 -0
- data/lib/blockchyp.rb +462 -0
- data/lib/blockchyp_client.rb +416 -0
- data/lib/crypto_utils.rb +25 -0
- data/test/activate_terminal_test.rb +45 -0
- data/test/add_test_merchant_test.rb +56 -0
- data/test/batch_history_test.rb +54 -0
- data/test/boolean_prompt_test.rb +49 -0
- data/test/cancel_payment_link_test.rb +72 -0
- data/test/capture_signature_test.rb +46 -0
- data/test/deactivate_terminal_test.rb +42 -0
- data/test/delete_branding_asset_test.rb +50 -0
- data/test/delete_customer_test.rb +55 -0
- data/test/delete_media_asset_test.rb +53 -0
- data/test/delete_queued_transaction_test.rb +56 -0
- data/test/delete_slide_show_test.rb +50 -0
- data/test/delete_survey_question_test.rb +51 -0
- data/test/delete_test_merchant_test.rb +59 -0
- data/test/delete_token_test.rb +55 -0
- data/test/empty_branding_asset_test.rb +44 -0
- data/test/empty_slide_show_test.rb +45 -0
- data/test/gateway_timeout_test.rb +49 -0
- data/test/get_customer_test.rb +55 -0
- data/test/get_merchants_test.rb +52 -0
- data/test/heartbeat_test.rb +27 -0
- data/test/invite_merchant_user_test.rb +45 -0
- data/test/link_token_test.rb +56 -0
- data/test/list_queued_transactions_test.rb +55 -0
- data/test/list_terminals_test.rb +42 -0
- data/test/media_asset_test.rb +57 -0
- data/test/media_test.rb +42 -0
- data/test/media_upload_test.rb +52 -0
- data/test/merchant_platforms_test.rb +59 -0
- data/test/merchant_profile_test.rb +43 -0
- data/test/merchant_users_test.rb +42 -0
- data/test/new_transaction_display_test.rb +64 -0
- data/test/pan_charge_test.rb +61 -0
- data/test/pan_enroll_test.rb +62 -0
- data/test/pan_preauth_test.rb +60 -0
- data/test/partial_refund_test.rb +58 -0
- data/test/search_customer_test.rb +55 -0
- data/test/send_payment_link_test.rb +67 -0
- data/test/simple_batch_close_test.rb +54 -0
- data/test/simple_capture_test.rb +55 -0
- data/test/simple_gift_activate_test.rb +48 -0
- data/test/simple_locate_test.rb +44 -0
- data/test/simple_message_test.rb +46 -0
- data/test/simple_ping_test.rb +45 -0
- data/test/simple_refund_test.rb +57 -0
- data/test/simple_reversal_test.rb +56 -0
- data/test/simple_void_test.rb +56 -0
- data/test/slide_show_test.rb +51 -0
- data/test/slide_shows_test.rb +49 -0
- data/test/survey_question_test.rb +48 -0
- data/test/survey_questions_test.rb +50 -0
- data/test/survey_results_test.rb +48 -0
- data/test/tc_delete_template_test.rb +51 -0
- data/test/tc_entry_test.rb +56 -0
- data/test/tc_log_test.rb +42 -0
- data/test/tc_template_test.rb +53 -0
- data/test/tc_template_update_test.rb +48 -0
- data/test/tc_templates_test.rb +42 -0
- data/test/terminal_branding_test.rb +42 -0
- data/test/terminal_charge_test.rb +57 -0
- data/test/terminal_clear_test.rb +45 -0
- data/test/terminal_ebt_balance_test.rb +47 -0
- data/test/terminal_ebt_charge_test.rb +59 -0
- data/test/terminal_enroll_test.rb +56 -0
- data/test/terminal_gift_card_balance_test.rb +46 -0
- data/test/terminal_keyed_charge_test.rb +58 -0
- data/test/terminal_manual_ebt_charge_test.rb +60 -0
- data/test/terminal_preauth_test.rb +57 -0
- data/test/terminal_queued_transaction_test.rb +51 -0
- data/test/terminal_status_test.rb +45 -0
- data/test/terminal_timeout_test.rb +46 -0
- data/test/terms_and_conditions_test.rb +50 -0
- data/test/test_helper.rb +64 -0
- data/test/testdata/aviato.png +0 -0
- data/test/text_prompt_test.rb +47 -0
- data/test/token_metadata_test.rb +55 -0
- data/test/transaction_history_test.rb +54 -0
- data/test/unlink_token_test.rb +56 -0
- data/test/update_branding_asset_test.rb +62 -0
- data/test/update_customer_test.rb +49 -0
- data/test/update_merchant_platforms_test.rb +61 -0
- data/test/update_merchant_test.rb +60 -0
- data/test/update_slide_show_test.rb +60 -0
- data/test/update_survey_question_test.rb +47 -0
- data/test/update_transaction_display_test.rb +64 -0
- data/test/upload_status_test.rb +53 -0
- metadata +136 -0
@@ -0,0 +1,416 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
require 'cgi'
|
5
|
+
require 'digest'
|
6
|
+
require 'json'
|
7
|
+
require 'net/http'
|
8
|
+
require 'openssl'
|
9
|
+
require 'time'
|
10
|
+
require 'tmpdir'
|
11
|
+
require 'uri'
|
12
|
+
|
13
|
+
require_relative 'crypto_utils'
|
14
|
+
|
15
|
+
module BlockChyp
|
16
|
+
# base class for the blockchyp generated blockchyp client
|
17
|
+
class BlockChypClient
|
18
|
+
def initialize(api_key, bearer_token, signing_key)
|
19
|
+
@api_key = api_key
|
20
|
+
@bearer_token = bearer_token
|
21
|
+
@signing_key = signing_key
|
22
|
+
@gateway_host = 'https://api.blockchyp.com'
|
23
|
+
@test_gateway_host = 'https://test.blockchyp.com'
|
24
|
+
@dashboard_host = 'https://dashboard.blockchyp.com'
|
25
|
+
@https = false
|
26
|
+
@route_cache_location = File.join(Dir.tmpdir, '.blockchyp_route')
|
27
|
+
@route_cache_ttl = 60
|
28
|
+
@gateway_timeout = 20
|
29
|
+
@terminal_timeout = 120
|
30
|
+
@terminal_connect_timeout = 5
|
31
|
+
@offline_cache_enabled = true
|
32
|
+
@route_cache = {}
|
33
|
+
@offline_fixed_key = 'cb22789c9d5c344a10e0474f134db39e25eb3bbf5a1b1a5e89b507f15ea9519c'
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :api_key
|
37
|
+
attr_reader :bearer_token
|
38
|
+
attr_reader :signing_key
|
39
|
+
attr_reader :offline_fixed_key
|
40
|
+
attr_accessor :gateway_host
|
41
|
+
attr_accessor :test_gateway_host
|
42
|
+
attr_accessor :dashboard_host
|
43
|
+
attr_accessor :https
|
44
|
+
attr_accessor :route_cache_ttl
|
45
|
+
attr_accessor :gateway_timeout
|
46
|
+
attr_accessor :terminal_timeout
|
47
|
+
attr_accessor :offline_cache_enabled
|
48
|
+
attr_accessor :terminal_connect_timeout
|
49
|
+
attr_accessor :route_cache_location
|
50
|
+
attr_accessor :route_cache
|
51
|
+
|
52
|
+
def generate_gateway_headers
|
53
|
+
nonce = CryptoUtils.generate_nonce
|
54
|
+
tsp = CryptoUtils.timestamp
|
55
|
+
|
56
|
+
sig = compute_hmac(tsp, nonce)
|
57
|
+
|
58
|
+
{
|
59
|
+
'Nonce' => nonce,
|
60
|
+
'Timestamp' => tsp,
|
61
|
+
'Authorization' => 'Dual ' + bearer_token + ':' + api_key + ':' + sig
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def compute_hmac(tsp, nonce)
|
66
|
+
canonical_string = api_key + bearer_token + tsp + nonce
|
67
|
+
|
68
|
+
OpenSSL::HMAC.hexdigest('SHA256', CryptoUtils.hex2bin(signing_key), canonical_string)
|
69
|
+
end
|
70
|
+
|
71
|
+
def resolve_gateway_uri(path, request)
|
72
|
+
url = request.nil? || !request[:test] ? gateway_host : test_gateway_host
|
73
|
+
|
74
|
+
URI.parse(path.nil? ? url : url + path)
|
75
|
+
end
|
76
|
+
|
77
|
+
def resolve_dashboard_uri(path, request)
|
78
|
+
URI.parse(dashboard_host + path)
|
79
|
+
end
|
80
|
+
|
81
|
+
def generate_error_response(msg)
|
82
|
+
{
|
83
|
+
success: false,
|
84
|
+
error: msg,
|
85
|
+
responseDescription: msg
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def route_terminal_request(method, terminal_path, gateway_path, request)
|
90
|
+
unless request.key?(:terminalName)
|
91
|
+
return gateway_request(method, gateway_path, request)
|
92
|
+
end
|
93
|
+
|
94
|
+
route = resolve_terminal_route(request[:terminalName])
|
95
|
+
if !route
|
96
|
+
return generate_error_response('Unkown Terminal')
|
97
|
+
elsif route[:cloudRelayEnabled]
|
98
|
+
return gateway_request(method, gateway_path, request, relay: true)
|
99
|
+
end
|
100
|
+
|
101
|
+
terminal_request(method, route, terminal_path, request, true)
|
102
|
+
end
|
103
|
+
|
104
|
+
def terminal_request(method, route, path, request, open_retry)
|
105
|
+
uri = resolve_terminal_uri(route, path)
|
106
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
107
|
+
http.use_ssl = uri.instance_of?(URI::HTTPS)
|
108
|
+
timeout = get_timeout(request, terminal_timeout)
|
109
|
+
http.open_timeout = timeout
|
110
|
+
http.read_timeout = timeout
|
111
|
+
|
112
|
+
tx_creds = route[:transientCredentials]
|
113
|
+
|
114
|
+
wrapped_request = {
|
115
|
+
apiKey: tx_creds[:apiKey],
|
116
|
+
bearerToken: tx_creds[:bearerToken],
|
117
|
+
signingKey: tx_creds[:signingKey],
|
118
|
+
request: request
|
119
|
+
}
|
120
|
+
|
121
|
+
req = get_http_request(method, uri)
|
122
|
+
|
123
|
+
req['User-Agent'] = user_agent
|
124
|
+
json = wrapped_request.to_json
|
125
|
+
req['Content-Type'] = 'application/json'
|
126
|
+
req['Content-Length'] = json.length
|
127
|
+
req.body = json
|
128
|
+
|
129
|
+
begin
|
130
|
+
response = http.request(req)
|
131
|
+
rescue Net::OpenTimeout, Errno::EHOSTDOWN, Errno::EHOSTUNREACH, Errno::ETIMEDOUT, Errno::ENETUNREACH
|
132
|
+
if open_retry
|
133
|
+
evict(route[:terminalName])
|
134
|
+
route = resolve_terminal_route(route[:terminalName])
|
135
|
+
return terminal_request(method, route, path, request, false)
|
136
|
+
end
|
137
|
+
raise
|
138
|
+
end
|
139
|
+
if response.is_a?(Net::HTTPSuccess)
|
140
|
+
JSON.parse(response.body, symbolize_names: true)
|
141
|
+
else
|
142
|
+
raise response.message
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def get_http_request(method, uri)
|
147
|
+
case method
|
148
|
+
when 'GET'
|
149
|
+
Net::HTTP::Get.new(uri.request_uri)
|
150
|
+
when 'PUT'
|
151
|
+
Net::HTTP::Put.new(uri.request_uri)
|
152
|
+
when 'POST'
|
153
|
+
Net::HTTP::Post.new(uri.request_uri)
|
154
|
+
when 'DELETE'
|
155
|
+
Net::HTTP::Delete.new(uri.request_uri)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def resolve_terminal_uri(route, path)
|
160
|
+
url = if https
|
161
|
+
'https://'
|
162
|
+
else
|
163
|
+
'http://'
|
164
|
+
end
|
165
|
+
url += route[:ipAddress]
|
166
|
+
port = if https
|
167
|
+
':8443'
|
168
|
+
else
|
169
|
+
':8080'
|
170
|
+
end
|
171
|
+
URI.parse(url + port + path)
|
172
|
+
end
|
173
|
+
|
174
|
+
def dashboard_request(method, path, request = nil)
|
175
|
+
uri = resolve_dashboard_uri(path, request)
|
176
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
177
|
+
http.use_ssl = uri.instance_of?(URI::HTTPS)
|
178
|
+
timeout = get_timeout(request, gateway_timeout)
|
179
|
+
http.open_timeout = timeout
|
180
|
+
http.read_timeout = timeout
|
181
|
+
|
182
|
+
req = get_http_request(method, uri)
|
183
|
+
|
184
|
+
req['User-Agent'] = user_agent
|
185
|
+
unless request.nil?
|
186
|
+
json = request.to_json
|
187
|
+
req['Content-Type'] = 'application/json'
|
188
|
+
req['Content-Length'] = json.length
|
189
|
+
req.body = json
|
190
|
+
end
|
191
|
+
|
192
|
+
headers = generate_gateway_headers
|
193
|
+
headers.each do |key, value|
|
194
|
+
req[key] = value
|
195
|
+
end
|
196
|
+
|
197
|
+
response = http.request(req)
|
198
|
+
|
199
|
+
if response.is_a?(Net::HTTPSuccess)
|
200
|
+
JSON.parse(response.body, symbolize_names: true)
|
201
|
+
else
|
202
|
+
raise response.message
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def upload_request(path, request, content)
|
207
|
+
uri = resolve_dashboard_uri(path, request)
|
208
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
209
|
+
http.use_ssl = uri.instance_of?(URI::HTTPS)
|
210
|
+
timeout = get_timeout(request, gateway_timeout)
|
211
|
+
http.open_timeout = timeout
|
212
|
+
http.read_timeout = timeout
|
213
|
+
|
214
|
+
req = get_http_request("POST", uri)
|
215
|
+
req.body = content
|
216
|
+
req['User-Agent'] = user_agent
|
217
|
+
req['Content-Type'] = 'application/octet-stream'
|
218
|
+
|
219
|
+
if request[:fileName]
|
220
|
+
req['X-Upload-File-Name'] = request[:fileName]
|
221
|
+
end
|
222
|
+
|
223
|
+
if request[:uploadId]
|
224
|
+
req['X-Upload-ID'] = request[:uploadId]
|
225
|
+
end
|
226
|
+
|
227
|
+
if request[:fileSize]
|
228
|
+
req['X-File-Size'] = request[:fileSize]
|
229
|
+
req['Content-Length'] = request[:fileSize]
|
230
|
+
end
|
231
|
+
|
232
|
+
headers = generate_gateway_headers
|
233
|
+
headers.each do |key, value|
|
234
|
+
req[key] = value
|
235
|
+
end
|
236
|
+
|
237
|
+
response = http.request(req)
|
238
|
+
|
239
|
+
if response.is_a?(Net::HTTPSuccess)
|
240
|
+
JSON.parse(response.body, symbolize_names: true)
|
241
|
+
else
|
242
|
+
raise response.message
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def gateway_request(method, path, request = nil, relay = false)
|
247
|
+
uri = resolve_gateway_uri(path, request)
|
248
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
249
|
+
http.use_ssl = uri.instance_of?(URI::HTTPS)
|
250
|
+
timeout = get_timeout(request, relay ? terminal_timeout : gateway_timeout)
|
251
|
+
http.open_timeout = timeout
|
252
|
+
http.read_timeout = timeout
|
253
|
+
|
254
|
+
req = get_http_request(method, uri)
|
255
|
+
|
256
|
+
req['User-Agent'] = user_agent
|
257
|
+
unless request.nil?
|
258
|
+
json = request.to_json
|
259
|
+
req['Content-Type'] = 'application/json'
|
260
|
+
req['Content-Length'] = json.length
|
261
|
+
req.body = json
|
262
|
+
end
|
263
|
+
|
264
|
+
headers = generate_gateway_headers
|
265
|
+
headers.each do |key, value|
|
266
|
+
req[key] = value
|
267
|
+
end
|
268
|
+
|
269
|
+
response = http.request(req)
|
270
|
+
|
271
|
+
if response.is_a?(Net::HTTPSuccess)
|
272
|
+
JSON.parse(response.body, symbolize_names: true)
|
273
|
+
else
|
274
|
+
raise response.message
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def resolve_terminal_route(terminal_name)
|
279
|
+
route = route_cache_get(terminal_name, false)
|
280
|
+
|
281
|
+
if route.nil?
|
282
|
+
route = request_route_from_gateway(terminal_name)
|
283
|
+
if route.nil?
|
284
|
+
return route
|
285
|
+
end
|
286
|
+
|
287
|
+
ttl = Time.now.utc + (route_cache_ttl * 60)
|
288
|
+
route_cache_entry = {}
|
289
|
+
route_cache_entry[:route] = route
|
290
|
+
route_cache_entry[:ttl] = ttl
|
291
|
+
@route_cache[api_key + terminal_name] = route_cache_entry
|
292
|
+
update_offline_cache(route_cache_entry)
|
293
|
+
end
|
294
|
+
route
|
295
|
+
end
|
296
|
+
|
297
|
+
def update_offline_cache(route_cache_entry)
|
298
|
+
if offline_cache_enabled
|
299
|
+
offline_cache = read_offline_cache
|
300
|
+
offline_entry = route_cache_entry.clone
|
301
|
+
route = route_cache_entry[:route].clone
|
302
|
+
tx_creds = route[:transientCredentials].clone
|
303
|
+
tx_creds[:apiKey] = encrypt(tx_creds[:apiKey])
|
304
|
+
tx_creds[:bearerToken] = encrypt(tx_creds[:bearerToken])
|
305
|
+
tx_creds[:signingKey] = encrypt(tx_creds[:signingKey])
|
306
|
+
route[:transientCredentials] = tx_creds
|
307
|
+
offline_entry[:route] = route
|
308
|
+
offline_cache[api_key + route[:terminalName]] = offline_entry
|
309
|
+
File.write(route_cache_location, offline_cache.to_json)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def encrypt(plain_text)
|
314
|
+
return plain_text if plain_text.nil? || plain_text.empty?
|
315
|
+
|
316
|
+
cipher = OpenSSL::Cipher::AES256.new(:CBC)
|
317
|
+
cipher.encrypt
|
318
|
+
cipher.key = derive_offline_key
|
319
|
+
iv = cipher.random_iv
|
320
|
+
|
321
|
+
Base64.encode64(iv) + ':' + Base64.encode64(cipher.update(plain_text) + cipher.final)
|
322
|
+
end
|
323
|
+
|
324
|
+
def decrypt(cipher_text)
|
325
|
+
return cipher_text if cipher_text.nil? || cipher_text.empty?
|
326
|
+
|
327
|
+
tokens = cipher_text.split(':')
|
328
|
+
|
329
|
+
return cipher_text if tokens[0].nil? || tokens[1].nil?
|
330
|
+
|
331
|
+
iv = Base64.decode64(tokens[0])
|
332
|
+
cp = Base64.decode64(tokens[1])
|
333
|
+
|
334
|
+
decipher = OpenSSL::Cipher::AES256.new(:CBC)
|
335
|
+
decipher.decrypt
|
336
|
+
decipher.key = derive_offline_key
|
337
|
+
decipher.iv = iv
|
338
|
+
|
339
|
+
decipher.update(cp) + decipher.final
|
340
|
+
end
|
341
|
+
|
342
|
+
def derive_offline_key
|
343
|
+
Digest::SHA256.digest offline_fixed_key + signing_key
|
344
|
+
end
|
345
|
+
|
346
|
+
def request_route_from_gateway(terminal_name)
|
347
|
+
route = gateway_request('GET', '/api/terminal-route?terminal=' + CGI.escape(terminal_name))
|
348
|
+
if !route.nil? && !route[:ipAddress].empty?
|
349
|
+
route[:exists] = true
|
350
|
+
end
|
351
|
+
route
|
352
|
+
end
|
353
|
+
|
354
|
+
def evict(terminal_name)
|
355
|
+
route_cache.delete(api_key + terminal_name)
|
356
|
+
|
357
|
+
offline_cache = read_offline_cache
|
358
|
+
offline_cache.delete(api_key + terminal_name)
|
359
|
+
File.write(route_cache_location, route_cache.to_json)
|
360
|
+
end
|
361
|
+
|
362
|
+
def route_cache_get(terminal_name, stale)
|
363
|
+
route_cache_entry = @route_cache[api_key + terminal_name]
|
364
|
+
|
365
|
+
if route_cache_entry.nil? && offline_cache_enabled
|
366
|
+
offline_cache = read_offline_cache
|
367
|
+
route_cache_entry = offline_cache[@api_key + terminal_name]
|
368
|
+
end
|
369
|
+
|
370
|
+
if route_cache_entry
|
371
|
+
route = route_cache_entry[:route]
|
372
|
+
tx_creds = route[:transientCredentials]
|
373
|
+
tx_creds[:apiKey] = decrypt(tx_creds[:apiKey])
|
374
|
+
tx_creds[:bearerToken] = decrypt(tx_creds[:bearerToken])
|
375
|
+
tx_creds[:signingKey] = decrypt(tx_creds[:signingKey])
|
376
|
+
route[:transientCredentials] = tx_creds
|
377
|
+
route_cache_entry[:route] = route
|
378
|
+
|
379
|
+
raw_ttl = route_cache_entry[:ttl]
|
380
|
+
|
381
|
+
ttl = raw_ttl.instance_of?(Time) ? raw_ttl : Time.parse(route_cache_entry[:ttl])
|
382
|
+
|
383
|
+
if stale || Time.new < ttl
|
384
|
+
route_cache_entry[:route]
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
def read_offline_cache
|
390
|
+
if File.file?(route_cache_location)
|
391
|
+
|
392
|
+
config_file = File.open(route_cache_location)
|
393
|
+
content = config_file.read
|
394
|
+
|
395
|
+
return JSON.parse(content, symbolize_names: true)
|
396
|
+
end
|
397
|
+
{}
|
398
|
+
end
|
399
|
+
|
400
|
+
def user_agent
|
401
|
+
if defined? VERSION
|
402
|
+
"BlockChyp-Ruby/#{VERSION}"
|
403
|
+
else
|
404
|
+
'BlockChyp-Ruby'
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
def get_timeout(request, default)
|
409
|
+
if request.nil? || !request.key?(:timeout) || request[:timeout].zero?
|
410
|
+
return default
|
411
|
+
end
|
412
|
+
|
413
|
+
request[:timeout]
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
data/lib/crypto_utils.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'securerandom'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
module BlockChyp
|
7
|
+
# crypto and encoding utilities
|
8
|
+
class CryptoUtils
|
9
|
+
def self.generate_nonce
|
10
|
+
bin2hex(SecureRandom.bytes(32))
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.timestamp
|
14
|
+
Time.now.utc.to_datetime.rfc3339
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.bin2hex(val)
|
18
|
+
val.each_byte.map { |b| b.to_s(16) }.join
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.hex2bin(val)
|
22
|
+
val.scan(/../).map { |x| x.hex.chr }.join
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2019-2022 BlockChyp, Inc. All rights reserved. Use of this code is
|
4
|
+
# governed by a license that can be found in the LICENSE file.
|
5
|
+
#
|
6
|
+
# This file was generated automatically by the BlockChyp SDK Generator.
|
7
|
+
# Changes to this file will be lost every time the code is regenerated.
|
8
|
+
|
9
|
+
require ::File.expand_path('test_helper', __dir__)
|
10
|
+
|
11
|
+
module BlockChyp
|
12
|
+
class ActivateTerminalTest < TestCase
|
13
|
+
def test_activate_terminal
|
14
|
+
|
15
|
+
puts "Running test_activate_terminal..."
|
16
|
+
|
17
|
+
config = load_test_config
|
18
|
+
|
19
|
+
blockchyp = BlockChyp.new(
|
20
|
+
config[:apiKey],
|
21
|
+
config[:bearerToken],
|
22
|
+
config[:signingKey]
|
23
|
+
)
|
24
|
+
blockchyp.gateway_host = config[:gatewayHost]
|
25
|
+
blockchyp.test_gateway_host = config[:testGatewayHost]
|
26
|
+
blockchyp.dashboard_host = config[:dashboardHost]
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
# Set request parameters
|
33
|
+
request = {
|
34
|
+
terminalName: 'Bad Terminal Code',
|
35
|
+
activationCode: 'XXXXXX'
|
36
|
+
}
|
37
|
+
|
38
|
+
response = blockchyp.activate_terminal(request)
|
39
|
+
assert_not_nil(response)
|
40
|
+
# response assertions
|
41
|
+
assert(!response[:success])
|
42
|
+
assert_equal('Invalid Activation Code', response[:error])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2019-2022 BlockChyp, Inc. All rights reserved. Use of this code is
|
4
|
+
# governed by a license that can be found in the LICENSE file.
|
5
|
+
#
|
6
|
+
# This file was generated automatically by the BlockChyp SDK Generator.
|
7
|
+
# Changes to this file will be lost every time the code is regenerated.
|
8
|
+
|
9
|
+
require ::File.expand_path('test_helper', __dir__)
|
10
|
+
|
11
|
+
module BlockChyp
|
12
|
+
class AddTestMerchantTest < TestCase
|
13
|
+
def test_add_test_merchant
|
14
|
+
|
15
|
+
puts "Running test_add_test_merchant..."
|
16
|
+
|
17
|
+
config = load_test_config
|
18
|
+
|
19
|
+
blockchyp = BlockChyp.new(
|
20
|
+
config[:apiKey],
|
21
|
+
config[:bearerToken],
|
22
|
+
config[:signingKey]
|
23
|
+
)
|
24
|
+
blockchyp.gateway_host = config[:gatewayHost]
|
25
|
+
blockchyp.test_gateway_host = config[:testGatewayHost]
|
26
|
+
blockchyp.dashboard_host = config[:dashboardHost]
|
27
|
+
|
28
|
+
|
29
|
+
profile = config[:profiles][:partner]
|
30
|
+
blockchyp = BlockChyp.new(
|
31
|
+
profile[:apiKey],
|
32
|
+
profile[:bearerToken],
|
33
|
+
profile[:signingKey]
|
34
|
+
)
|
35
|
+
blockchyp.gateway_host = config[:gatewayHost]
|
36
|
+
blockchyp.test_gateway_host = config[:testGatewayHost]
|
37
|
+
blockchyp.dashboard_host = config[:dashboardHost]
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
# Set request parameters
|
42
|
+
request = {
|
43
|
+
dbaName: 'Test Merchant',
|
44
|
+
companyName: 'Test Merchant'
|
45
|
+
}
|
46
|
+
|
47
|
+
response = blockchyp.add_test_merchant(request)
|
48
|
+
assert_not_nil(response)
|
49
|
+
# response assertions
|
50
|
+
assert(response[:success])
|
51
|
+
assert_equal('Test Merchant', response[:dbaName])
|
52
|
+
assert_equal('Test Merchant', response[:companyName])
|
53
|
+
assert(response[:visa])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2019-2022 BlockChyp, Inc. All rights reserved. Use of this code is
|
4
|
+
# governed by a license that can be found in the LICENSE file.
|
5
|
+
#
|
6
|
+
# This file was generated automatically by the BlockChyp SDK Generator.
|
7
|
+
# Changes to this file will be lost every time the code is regenerated.
|
8
|
+
|
9
|
+
require ::File.expand_path('test_helper', __dir__)
|
10
|
+
|
11
|
+
module BlockChyp
|
12
|
+
class BatchHistoryTest < TestCase
|
13
|
+
def test_batch_history
|
14
|
+
|
15
|
+
puts "Running test_batch_history..."
|
16
|
+
|
17
|
+
config = load_test_config
|
18
|
+
|
19
|
+
blockchyp = BlockChyp.new(
|
20
|
+
config[:apiKey],
|
21
|
+
config[:bearerToken],
|
22
|
+
config[:signingKey]
|
23
|
+
)
|
24
|
+
blockchyp.gateway_host = config[:gatewayHost]
|
25
|
+
blockchyp.test_gateway_host = config[:testGatewayHost]
|
26
|
+
blockchyp.dashboard_host = config[:dashboardHost]
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
# Set request parameters
|
33
|
+
setup_request = {
|
34
|
+
pan: '4111111111111111',
|
35
|
+
expMonth: '12',
|
36
|
+
expYear: '2025',
|
37
|
+
amount: '25.55',
|
38
|
+
test: true,
|
39
|
+
transactionRef: uuid
|
40
|
+
}
|
41
|
+
response = blockchyp.charge(setup_request)
|
42
|
+
|
43
|
+
# Set request parameters
|
44
|
+
request = {
|
45
|
+
maxResults: 10
|
46
|
+
}
|
47
|
+
|
48
|
+
response = blockchyp.batch_history(request)
|
49
|
+
assert_not_nil(response)
|
50
|
+
# response assertions
|
51
|
+
assert(response[:success])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2019-2022 BlockChyp, Inc. All rights reserved. Use of this code is
|
4
|
+
# governed by a license that can be found in the LICENSE file.
|
5
|
+
#
|
6
|
+
# This file was generated automatically by the BlockChyp SDK Generator.
|
7
|
+
# Changes to this file will be lost every time the code is regenerated.
|
8
|
+
|
9
|
+
require ::File.expand_path('test_helper', __dir__)
|
10
|
+
|
11
|
+
module BlockChyp
|
12
|
+
class BooleanPromptTest < TestCase
|
13
|
+
def test_boolean_prompt
|
14
|
+
|
15
|
+
puts "Running test_boolean_prompt..."
|
16
|
+
|
17
|
+
config = load_test_config
|
18
|
+
|
19
|
+
blockchyp = BlockChyp.new(
|
20
|
+
config[:apiKey],
|
21
|
+
config[:bearerToken],
|
22
|
+
config[:signingKey]
|
23
|
+
)
|
24
|
+
blockchyp.gateway_host = config[:gatewayHost]
|
25
|
+
blockchyp.test_gateway_host = config[:testGatewayHost]
|
26
|
+
blockchyp.dashboard_host = config[:dashboardHost]
|
27
|
+
|
28
|
+
test_delay(blockchyp, 'boolean_prompt_test', config[:defaultTerminalName])
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
# Set request parameters
|
34
|
+
request = {
|
35
|
+
test: true,
|
36
|
+
terminalName: config[:defaultTerminalName],
|
37
|
+
prompt: 'Would you like to become a member?',
|
38
|
+
yesCaption: 'Yes',
|
39
|
+
noCaption: 'No'
|
40
|
+
}
|
41
|
+
|
42
|
+
response = blockchyp.boolean_prompt(request)
|
43
|
+
assert_not_nil(response)
|
44
|
+
# response assertions
|
45
|
+
assert(response[:success])
|
46
|
+
assert(response[:response])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|