blockchyp 2.0.0.pre.alpha7 → 2.0.1.pre.rc8

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.
data/lib/blockchyp.rb CHANGED
@@ -1,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Copyright 2019 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. Changes to this file will be lost
7
+ # every time the code is regenerated.
8
+
3
9
  require_relative 'blockchyp_client'
4
10
 
5
11
  module CardType
@@ -29,79 +35,84 @@ module BlockChyp
29
35
  class BlockChyp < BlockChypClient
30
36
 
31
37
  def heartbeat(test)
32
- gateway_get('/api/heartbeat', test)
38
+ gateway_request('GET', '/api/heartbeat', {'test' => test})
33
39
  end
34
40
 
35
41
  # Executes a standard direct preauth and capture.
36
42
  def charge(request)
37
- route_terminal_request(request, '/api/charge', '/api/charge', 'POST')
43
+ route_terminal_request('POST', '/api/charge', '/api/charge', request)
38
44
  end
39
45
 
40
46
  # Executes a preauthorization intended to be captured later.
41
47
  def preauth(request)
42
- route_terminal_request(request, '/api/preauth', '/api/preauth', 'POST')
48
+ route_terminal_request('POST', '/api/preauth', '/api/preauth', request)
43
49
  end
44
50
 
45
51
  # Tests connectivity with a payment terminal.
46
52
  def ping(request)
47
- route_terminal_request(request, '/api/test', '/api/terminal-test', 'POST')
53
+ route_terminal_request('POST', '/api/test', '/api/terminal-test', request)
48
54
  end
49
55
 
50
56
  # Checks the remaining balance on a payment method.
51
57
  def balance(request)
52
- route_terminal_request(request, '/api/balance', '/api/balance', 'POST')
58
+ route_terminal_request('POST', '/api/balance', '/api/balance', request)
53
59
  end
54
60
 
55
61
  # Clears the line item display and any in progress transaction.
56
62
  def clear(request)
57
- route_terminal_request(request, '/api/clear', '/api/terminal-clear', 'POST')
63
+ route_terminal_request('POST', '/api/clear', '/api/terminal-clear', request)
58
64
  end
59
65
 
60
66
  # Prompts the user to accept terms and conditions.
61
67
  def terms_and_conditions(request)
62
- route_terminal_request(request, '/api/tc', '/api/terminal-tc', 'POST')
68
+ route_terminal_request('POST', '/api/tc', '/api/terminal-tc', request)
63
69
  end
64
70
 
65
- # Appends items to an existing transaction display Subtotal, Tax, and
71
+ # Appends items to an existing transaction display. Subtotal, Tax, and
66
72
  # Total are overwritten by the request. Items with the same description
67
73
  # are combined into groups.
68
74
  def update_transaction_display(request)
69
- route_terminal_request(request, '/api/txdisplay', '/api/terminal-txdisplay', 'PUT')
75
+ route_terminal_request('PUT', '/api/txdisplay', '/api/terminal-txdisplay', request)
70
76
  end
71
77
 
72
78
  # Displays a new transaction on the terminal.
73
79
  def new_transaction_display(request)
74
- route_terminal_request(request, '/api/txdisplay', '/api/terminal-txdisplay', 'POST')
80
+ route_terminal_request('POST', '/api/txdisplay', '/api/terminal-txdisplay', request)
75
81
  end
76
82
 
77
- # Asks the consumer text based question.
83
+ # Asks the consumer a text based question.
78
84
  def text_prompt(request)
79
- route_terminal_request(request, '/api/text-prompt', '/api/text-prompt', 'POST')
85
+ route_terminal_request('POST', '/api/text-prompt', '/api/text-prompt', request)
80
86
  end
81
87
 
82
88
  # Asks the consumer a yes/no question.
83
89
  def boolean_prompt(request)
84
- route_terminal_request(request, '/api/boolean-prompt', '/api/boolean-prompt', 'POST')
90
+ route_terminal_request('POST', '/api/boolean-prompt', '/api/boolean-prompt', request)
85
91
  end
86
92
 
87
93
  # Displays a short message on the terminal.
88
94
  def message(request)
89
- route_terminal_request(request, '/api/message', '/api/message', 'POST')
95
+ route_terminal_request('POST', '/api/message', '/api/message', request)
90
96
  end
91
97
 
92
98
  # Executes a refund.
93
99
  def refund(request)
94
- route_terminal_request(request, '/api/refund', '/api/refund', 'POST')
100
+ route_terminal_request('POST', '/api/refund', '/api/refund', request)
95
101
  end
96
102
 
97
103
  # Adds a new payment method to the token vault.
98
104
  def enroll(request)
99
- route_terminal_request(request, '/api/enroll', '/api/enroll', 'POST')
105
+ route_terminal_request('POST', '/api/enroll', '/api/enroll', request)
100
106
  end
101
107
 
102
108
  # Activates or recharges a gift card.
103
109
  def gift_activate(request)
104
- route_terminal_request(request, '/api/gift-activate', '/api/gift-activate', 'POST')
110
+ route_terminal_request('POST', '/api/gift-activate', '/api/gift-activate', request)
111
+ end
112
+
113
+ # Returns the current status of a terminal.
114
+ def terminal_status(request)
115
+ route_terminal_request('POST', '/api/terminal-status', '/api/terminal-status', request)
105
116
  end
106
117
 
107
118
  # Executes a manual time out reversal.
@@ -115,22 +126,22 @@ module BlockChyp
115
126
  # an id, you wouldn't know what it is because your request to the terminal
116
127
  # timed out before you got a response.
117
128
  def reverse(request)
118
- gateway_request('/api/reverse', request, 'POST')
129
+ gateway_request('POST', '/api/reverse', request)
119
130
  end
120
131
 
121
132
  # Captures a preauthorization.
122
133
  def capture(request)
123
- gateway_request('/api/capture', request, 'POST')
134
+ gateway_request('POST', '/api/capture', request)
124
135
  end
125
136
 
126
137
  # Closes the current credit card batch.
127
138
  def close_batch(request)
128
- gateway_request('/api/close-batch', request, 'POST')
139
+ gateway_request('POST', '/api/close-batch', request)
129
140
  end
130
141
 
131
142
  # Discards a previous preauth transaction.
132
143
  def void(request)
133
- gateway_request('/api/void', request, 'POST')
144
+ gateway_request('POST', '/api/void', request)
134
145
  end
135
146
 
136
147
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BlockChyp
4
- VERSION = '2.0.0.pre.alpha7'
4
+ VERSION = '2.0.1.pre.rc8'
5
5
  end
@@ -46,25 +46,6 @@ module BlockChyp
46
46
  attr_accessor :terminal_connect_timeout
47
47
  attr_accessor :route_cache_location
48
48
 
49
- def gateway_get(path, test)
50
- path = resolve_gateway_url(path, test)
51
- puts 'GET: ' + path
52
- uri = URI(path)
53
- req = Net::HTTP::Get.new(uri)
54
- headers = generate_gateway_headers
55
- headers.each do |key, value|
56
- req[key] = value
57
- end
58
- res = Net::HTTP.new(uri.host, uri.port).start do |inner_http|
59
- inner_http.request(req)
60
- end
61
- if res.is_a?(Net::HTTPSuccess)
62
- JSON.parse(res.body)
63
- else
64
- raise res.message
65
- end
66
- end
67
-
68
49
  def generate_gateway_headers
69
50
  nonce = CryptoUtils.generate_nonce
70
51
  tsp = CryptoUtils.timestamp
@@ -84,14 +65,14 @@ module BlockChyp
84
65
  OpenSSL::HMAC.hexdigest('SHA256', CryptoUtils.hex2bin(signing_key), canonical_string)
85
66
  end
86
67
 
87
- def resolve_gateway_url(path, test)
88
- url = if test
89
- test_gateway_host
90
- else
68
+ def resolve_gateway_uri(path, request)
69
+ url = if request.nil? || !request['test']
91
70
  gateway_host
71
+ else
72
+ test_gateway_host
92
73
  end
93
74
 
94
- url + path
75
+ URI.parse(url + path)
95
76
  end
96
77
 
97
78
  def generate_error_response(msg)
@@ -102,69 +83,74 @@ module BlockChyp
102
83
  ]
103
84
  end
104
85
 
105
- def route_terminal_request(request, terminal_path, gateway_path, method)
86
+ def route_terminal_request(method, terminal_path, gateway_path, request)
106
87
  if request['terminalName'].nil?
107
- return gateway_request(gateway_path, request, method)
88
+ return gateway_request(method, gateway_path, request)
108
89
  end
109
90
 
110
91
  route = resolve_terminal_route(request['terminalName'])
111
92
  if !route
112
93
  return generate_error_response('Unkown Terminal')
113
94
  elsif route['cloudRelayEnabled']
114
- return gateway_request(gateway_path, request, method)
95
+ return gateway_request(method, gateway_path, request, relay: true)
115
96
  end
116
97
 
117
- terminal_request(route, terminal_path, request, method, true)
98
+ terminal_request(method, route, terminal_path, request, true)
118
99
  end
119
100
 
120
- def terminal_request(route, path, request, method, open_retry)
121
- url = resolve_terminal_url(route, path)
101
+ def terminal_request(method, route, path, request, open_retry)
102
+ uri = resolve_terminal_uri(route, path)
103
+ http = Net::HTTP.new(uri.host, uri.port)
104
+ timeout = get_timeout(request, terminal_timeout)
105
+ http.open_timeout = timeout
106
+ http.read_timeout = timeout
122
107
 
123
108
  tx_creds = route['transientCredentials']
124
109
 
125
- terminal_request = {
110
+ wrapped_request = {
126
111
  'apiKey' => tx_creds['apiKey'],
127
112
  'bearerToken' => tx_creds['bearerToken'],
128
113
  'signingKey' => tx_creds['signingKey'],
129
114
  'request' => request
130
115
  }
131
116
 
132
- puts method + ': ' + url
133
- puts terminal_request.to_json
117
+ req = get_http_request(method, uri)
134
118
 
135
- uri = URI(url)
136
- req = if method == 'PUT'
137
- Net::HTTP::Put.new(uri)
138
- else
139
- Net::HTTP::Post.new(uri)
140
- end
141
- json = terminal_request.to_json
119
+ req['User-Agent'] = user_agent
120
+ json = wrapped_request.to_json
142
121
  req['Content-Type'] = 'application/json'
143
122
  req['Content-Length'] = json.length
144
123
  req.body = json
145
- http = Net::HTTP.new(uri.host, uri.port)
146
- http.open_timeout = terminal_connect_timeout
147
- http.read_timeout = terminal_timeout
124
+
148
125
  begin
149
- res = http.start do |inner_http|
150
- inner_http.request(req)
151
- end
126
+ response = http.request(req)
152
127
  rescue Net::OpenTimeout, Errno::EHOSTDOWN, Errno::EHOSTUNREACH, Errno::ETIMEDOUT, Errno::ENETUNREACH
153
128
  if open_retry
154
129
  evict(route['terminalName'])
155
130
  route = resolve_terminal_route(route['terminalName'])
156
- return terminal_request(route, path, request, method, false)
131
+ return terminal_request(method, route, path, request, false)
157
132
  end
133
+ raise
158
134
  end
159
- if res.is_a?(Net::HTTPSuccess)
160
- puts 'Response: ' + res.body
161
- JSON.parse(res.body)
135
+ if response.is_a?(Net::HTTPSuccess)
136
+ JSON.parse(response.body)
162
137
  else
163
- raise res.message
138
+ raise response.message
139
+ end
140
+ end
141
+
142
+ def get_http_request(method, uri)
143
+ case method
144
+ when 'GET'
145
+ Net::HTTP::Get.new(uri.request_uri)
146
+ when 'PUT'
147
+ Net::HTTP::Put.new(uri.request_uri)
148
+ when 'POST'
149
+ Net::HTTP::Post.new(uri.request_uri)
164
150
  end
165
151
  end
166
152
 
167
- def resolve_terminal_url(route, path)
153
+ def resolve_terminal_uri(route, path)
168
154
  url = if https
169
155
  'https://'
170
156
  else
@@ -176,37 +162,37 @@ module BlockChyp
176
162
  else
177
163
  ':8080'
178
164
  end
179
- url + port + path
165
+ URI.parse(url + port + path)
180
166
  end
181
167
 
182
- def gateway_request(path, request, method)
183
- url = resolve_gateway_url(path, request['test'])
184
-
185
- puts method + ': ' + url
186
- puts request.to_json
168
+ def gateway_request(method, path, request = nil, relay = false)
169
+ uri = resolve_gateway_uri(path, request)
170
+ http = Net::HTTP.new(uri.host, uri.port)
171
+ timeout = get_timeout(request, relay ? terminal_timeout : gateway_timeout)
172
+ http.open_timeout = timeout
173
+ http.read_timeout = timeout
174
+
175
+ req = get_http_request(method, uri)
176
+
177
+ req['User-Agent'] = user_agent
178
+ unless request.nil?
179
+ json = request.to_json
180
+ req['Content-Type'] = 'application/json'
181
+ req['Content-Length'] = json.length
182
+ req.body = json
183
+ end
187
184
 
188
- uri = URI(url)
189
- req = if method == 'PUT'
190
- Net::HTTP::Put.new(uri)
191
- else
192
- Net::HTTP::Post.new(uri)
193
- end
194
- json = request.to_json
195
- req['Content-Type'] = 'application/json'
196
- req['Content-Length'] = json.length
197
185
  headers = generate_gateway_headers
198
186
  headers.each do |key, value|
199
187
  req[key] = value
200
188
  end
201
- req.body = json
202
- res = Net::HTTP.new(uri.host, uri.port).start do |http|
203
- http.request(req)
204
- end
205
- if res.is_a?(Net::HTTPSuccess)
206
- puts 'Response: ' + res.body
207
- JSON.parse(res.body)
189
+
190
+ response = http.request(req)
191
+
192
+ if response.is_a?(Net::HTTPSuccess)
193
+ JSON.parse(response.body)
208
194
  else
209
- raise res.message
195
+ raise response.message
210
196
  end
211
197
  end
212
198
 
@@ -237,17 +223,19 @@ module BlockChyp
237
223
  offline_entry = route_cache_entry.clone
238
224
  route = route_cache_entry['route'].clone
239
225
  tx_creds = route['transientCredentials'].clone
240
- tx_creds['apiKey'] = encrypt(tx_creds['api_key'])
226
+ tx_creds['apiKey'] = encrypt(tx_creds['apiKey'])
241
227
  tx_creds['bearerToken'] = encrypt(tx_creds['bearerToken'])
242
228
  tx_creds['signingKey'] = encrypt(tx_creds['signingKey'])
243
229
  route['transientCredentials'] = tx_creds
244
230
  offline_entry['route'] = route
245
- offline_cache[apiKey + route['terminalName']] = offline_entry
231
+ offline_cache[api_key + route['terminalName']] = offline_entry
246
232
  File.write(route_cache_location, offline_cache.to_json)
247
233
  end
248
234
  end
249
235
 
250
236
  def encrypt(plain_text)
237
+ return plain_text if plain_text.nil? || plain_text.empty?
238
+
251
239
  cipher = OpenSSL::Cipher::AES256.new(:CBC)
252
240
  cipher.encrypt
253
241
  cipher.key = derive_offline_key
@@ -257,8 +245,12 @@ module BlockChyp
257
245
  end
258
246
 
259
247
  def decrypt(cipher_text)
248
+ return cipher_text if cipher_text.nil? || cipher_text.empty?
249
+
260
250
  tokens = cipher_text.split(':')
261
251
 
252
+ return cipher_text if tokens[0].nil? || tokens[1].nil?
253
+
262
254
  iv = Base64.decode64(tokens[0])
263
255
  cp = Base64.decode64(tokens[1])
264
256
 
@@ -275,7 +267,7 @@ module BlockChyp
275
267
  end
276
268
 
277
269
  def request_route_from_gateway(terminal_name)
278
- route = gateway_get('/api/terminal-route?terminal=' + CGI.escape(terminal_name), false)
270
+ route = gateway_request('GET', '/api/terminal-route?terminal=' + CGI.escape(terminal_name))
279
271
  if !route.nil? && !route['ipAddress'].empty?
280
272
  route['exists'] = true
281
273
  end
@@ -305,22 +297,24 @@ module BlockChyp
305
297
  tx_creds['bearerToken'] = decrypt(tx_creds['bearerToken'])
306
298
  tx_creds['signingKey'] = decrypt(tx_creds['signingKey'])
307
299
  route['transientCredentials'] = tx_creds
308
- routeCacheEntry['route'] = route
300
+ route_cache_entry['route'] = route
309
301
  end
310
302
 
311
303
  if route_cache_entry
312
304
  now = Time.new
313
- ttl = Time.parse(route_cache_entry['ttl'])
305
+ raw_ttl = route_cache_entry['ttl']
306
+ if raw_ttl.instance_of?(Time)
307
+ ttl = raw_ttl
308
+ else
309
+ ttl = Time.parse(route_cache_entry['ttl'])
310
+ end
314
311
  if stale || now < ttl
315
- puts 'Cache Hit ' + route_cache_entry.to_json
316
312
  route_cache_entry['route']
317
313
  end
318
314
  end
319
315
  end
320
316
 
321
317
  def read_offline_cache
322
- puts route_cache_location
323
-
324
318
  if File.file?(route_cache_location)
325
319
 
326
320
  config_file = File.open(route_cache_location)
@@ -330,5 +324,21 @@ module BlockChyp
330
324
  end
331
325
  {}
332
326
  end
327
+
328
+ def user_agent
329
+ if defined? VERSION
330
+ "BlockChyp-Ruby/#{VERSION}"
331
+ else
332
+ "BlockChyp-Ruby"
333
+ end
334
+ end
335
+
336
+ def get_timeout(request, default)
337
+ if request.nil? || request['timeout'].nil? || request['timeout'].zero?
338
+ return default
339
+ end
340
+
341
+ request['timeout']
342
+ end
333
343
  end
334
344
  end
@@ -1,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Copyright 2019 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. Changes to this file will be lost
7
+ # every time the code is regenerated.
8
+
3
9
  require ::File.expand_path('test_helper', __dir__)
4
10
 
5
11
  module BlockChyp
@@ -15,7 +21,8 @@ module BlockChyp
15
21
  blockchyp.gateway_host = config['gatewayHost']
16
22
  blockchyp.test_gateway_host = config['testGatewayHost']
17
23
 
18
- test_delay(blockchyp, 'BooleanPromptTest')
24
+ test_delay(blockchyp, 'boolean_prompt_test')
25
+
19
26
  # setup request object
20
27
  request = {}
21
28
  request['test'] = true
@@ -23,7 +30,8 @@ module BlockChyp
23
30
  request['prompt'] = 'Would you like to become a member?'
24
31
  request['yesCaption'] = 'Yes'
25
32
  request['noCaption'] = 'No'
26
- response = blockchyp.booleanPrompt(request)
33
+
34
+ response = blockchyp.boolean_prompt(request)
27
35
 
28
36
  assert_not_nil(response)
29
37
  # response assertions