@staxpayments/staxpayments-js 2.30.18
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.
- package/.babelrc +8 -0
- package/LICENSE +21 -0
- package/README.md +1192 -0
- package/dist/blockchyp-js-all.js +48535 -0
- package/dist/blockchyp-js-all.min.js +34 -0
- package/dist/client.js +972 -0
- package/dist/cryptoutils.js +111 -0
- package/dist/global.js +13 -0
- package/dist/mappers.js +75 -0
- package/dist/payments.js +94 -0
- package/dist/staxpaymentsclient.js +74 -0
- package/dist/terminals.js +308 -0
- package/eslint.config.mjs +34 -0
- package/index.js +4 -0
- package/package.json +69 -0
- package/spec/CryptoSpec.js +46 -0
- package/spec/SanitySpec.js +27 -0
- package/spec/support/jasmine.json +11 -0
- package/src/client.js +707 -0
- package/src/cryptoutils.js +95 -0
- package/src/global.js +6 -0
- package/src/mappers.js +72 -0
- package/src/payments.js +41 -0
- package/src/staxpaymentsclient.js +54 -0
- package/src/terminals.js +104 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,972 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.StaxPaymentsCredentials = exports.StaxPaymentsBaseClient = exports.StaxApiCredentials = exports.SignatureFormat = exports.RoundingMode = exports.PromptType = exports.HealthcareType = exports.CardType = exports.CVMType = exports.AVSResponse = void 0;
|
|
8
|
+
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
9
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
10
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
12
|
+
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
13
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
14
|
+
var _axios = _interopRequireDefault(require("axios"));
|
|
15
|
+
var _cryptoutils = _interopRequireDefault(require("./cryptoutils"));
|
|
16
|
+
var _https = _interopRequireDefault(require("https"));
|
|
17
|
+
var _httpsBrowserify = _interopRequireDefault(require("https-browserify"));
|
|
18
|
+
var _aesJs = _interopRequireDefault(require("aes-js"));
|
|
19
|
+
var _sha = require("@noble/hashes/sha256");
|
|
20
|
+
var _utils = require("@noble/hashes/utils");
|
|
21
|
+
/**
|
|
22
|
+
* Copyright 2019-2026 BlockChyp, Inc. All rights reserved. Use of this code is governed
|
|
23
|
+
* by a license that can be found in the LICENSE file.
|
|
24
|
+
*
|
|
25
|
+
* This file was generated automatically by the BlockChyp SDK Generator. Changes to this
|
|
26
|
+
* file will be lost every time the code is regenerated.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
// optionalNodeModule resolves a Node built-in at run time, returning undefined
|
|
30
|
+
// in the browser. The name is held in a variable so the browser bundler cannot
|
|
31
|
+
// statically resolve it and try to shim it into the bundle.
|
|
32
|
+
function optionalNodeModule(name) {
|
|
33
|
+
try {
|
|
34
|
+
if (typeof module !== 'undefined' && typeof module.require === 'function') {
|
|
35
|
+
return module.require(name);
|
|
36
|
+
}
|
|
37
|
+
} catch (e) {
|
|
38
|
+
// Not running under Node.
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* eslint-disable no-unused-vars */
|
|
44
|
+
var CardType = exports.CardType = Object.freeze({
|
|
45
|
+
CREDIT: 0,
|
|
46
|
+
DEBIT: 1,
|
|
47
|
+
EBT: 2,
|
|
48
|
+
BLOCKCHAIN_GIFT: 3,
|
|
49
|
+
HEALTHCARE: 4
|
|
50
|
+
});
|
|
51
|
+
var SignatureFormat = exports.SignatureFormat = Object.freeze({
|
|
52
|
+
NONE: '',
|
|
53
|
+
PNG: 'png',
|
|
54
|
+
JPG: 'jpg',
|
|
55
|
+
GIF: 'gif'
|
|
56
|
+
});
|
|
57
|
+
var RoundingMode = exports.RoundingMode = Object.freeze({
|
|
58
|
+
UP: 'up',
|
|
59
|
+
NEAREST: 'nearest',
|
|
60
|
+
DOWN: 'down'
|
|
61
|
+
});
|
|
62
|
+
var PromptType = exports.PromptType = Object.freeze({
|
|
63
|
+
AMOUNT: 'amount',
|
|
64
|
+
EMAIL: 'email',
|
|
65
|
+
PHONE_NUMBER: 'phone',
|
|
66
|
+
CUSTOMER_NUMBER: 'customer-number',
|
|
67
|
+
REWARDS_NUMBER: 'rewards-number',
|
|
68
|
+
FIRST_NAME: 'first-name',
|
|
69
|
+
LAST_NAME: 'last-name'
|
|
70
|
+
});
|
|
71
|
+
var AVSResponse = exports.AVSResponse = Object.freeze({
|
|
72
|
+
NOT_APPLICABLE: '',
|
|
73
|
+
NOT_SUPPORTED: 'not_supported',
|
|
74
|
+
RETRY: 'retry',
|
|
75
|
+
NO_MATCH: 'no_match',
|
|
76
|
+
ADDRESS_MATCH: 'address_match',
|
|
77
|
+
POSTAL_CODE_MATCH: 'zip_match',
|
|
78
|
+
ADDRESS_AND_POSTAL_CODE_MATCH: 'match'
|
|
79
|
+
});
|
|
80
|
+
var CVMType = exports.CVMType = Object.freeze({
|
|
81
|
+
SIGNATURE: 'Signature',
|
|
82
|
+
OFFLINE_PIN: 'Offline PIN',
|
|
83
|
+
ONLINE_PIN: 'Online PIN',
|
|
84
|
+
CDCVM: 'CDCVM',
|
|
85
|
+
NO_CVM: 'No CVM'
|
|
86
|
+
});
|
|
87
|
+
var HealthcareType = exports.HealthcareType = Object.freeze({
|
|
88
|
+
HEALTHCARE: 'healthcare',
|
|
89
|
+
PRESCRIPTION: 'prescription',
|
|
90
|
+
VISION: 'vision',
|
|
91
|
+
CLINIC: 'clinic',
|
|
92
|
+
DENTAL: 'dental'
|
|
93
|
+
});
|
|
94
|
+
/* eslint-enable no-unused-vars */
|
|
95
|
+
|
|
96
|
+
var VERSION = require('../package.json').version;
|
|
97
|
+
var USER_AGENT = "StaxPayments-JavaScript/".concat(VERSION);
|
|
98
|
+
// Some browsers do not allow setting the user-agent header, so we set
|
|
99
|
+
// an alternative if running from a browser.
|
|
100
|
+
var AGENT_HEADER = typeof window === 'undefined' ? 'User-Agent' : 'X-Requested-With';
|
|
101
|
+
|
|
102
|
+
// DEFAULT_CORE_HOST is the default Stax core API host used when none is supplied.
|
|
103
|
+
var DEFAULT_CORE_HOST = 'https://apiprod.fattlabs.com';
|
|
104
|
+
|
|
105
|
+
// TRANSIENT_CREDENTIALS_PATH is the core API path that exchanges a Stax bearer
|
|
106
|
+
// token for short-lived Stax Payments transient credentials. This is an
|
|
107
|
+
// internal mechanism of the SDK and is never exposed as a public method.
|
|
108
|
+
var TRANSIENT_CREDENTIALS_PATH = '/terminals/transient-credentials';
|
|
109
|
+
|
|
110
|
+
// EXPIRY_SKEW_MS refreshes transient credentials this many milliseconds before
|
|
111
|
+
// their stated expiry to avoid a credential lapsing mid-request (clock-skew
|
|
112
|
+
// buffer).
|
|
113
|
+
var EXPIRY_SKEW_MS = 30 * 1000;
|
|
114
|
+
|
|
115
|
+
// EXPIRY_FALLBACK_MS is how long transient credentials are assumed to live when
|
|
116
|
+
// the core API does not state an expiry. The core endpoint does not populate
|
|
117
|
+
// expiresAt yet, so in practice this is the credential lifetime.
|
|
118
|
+
var EXPIRY_FALLBACK_MS = 8 * 60 * 60 * 1000;
|
|
119
|
+
|
|
120
|
+
// OFFLINE_FIXED_KEY is the static half of the offline route cache key. It is
|
|
121
|
+
// hashed together with the current signing key, so a cache file is readable
|
|
122
|
+
// only by a client holding the same credentials. It matches the constant used
|
|
123
|
+
// by the other Stax Payments SDKs, so the cache format is portable between
|
|
124
|
+
// them.
|
|
125
|
+
var OFFLINE_FIXED_KEY = 'cb22789c9d5c344a10e0474f134db39e25eb3bbf5a1b1a5e89b507f15ea9519c';
|
|
126
|
+
|
|
127
|
+
// StaxPaymentsBaseClient holds the shared transport: host configuration,
|
|
128
|
+
// transient-credential exchange, and the gateway/dashboard/terminal/core
|
|
129
|
+
// request plumbing. Each API namespace ships a client that wraps this base and
|
|
130
|
+
// adds only the endpoint methods for that namespace (e.g. PaymentsClient); the
|
|
131
|
+
// root StaxPaymentsClient builds one base and shares it across namespaces.
|
|
132
|
+
var StaxPaymentsBaseClient = exports.StaxPaymentsBaseClient = /*#__PURE__*/function () {
|
|
133
|
+
// Construct the shared transport with your Stax bearer token. Terminal
|
|
134
|
+
// transactions transparently exchange it for short-lived transient
|
|
135
|
+
// credentials.
|
|
136
|
+
function StaxPaymentsBaseClient(creds) {
|
|
137
|
+
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
138
|
+
(0, _classCallCheck2["default"])(this, StaxPaymentsBaseClient);
|
|
139
|
+
this.gatewayHost = opts.gatewayHost || 'https://api.blockchyp.com';
|
|
140
|
+
this.testGatewayHost = 'https://test.blockchyp.com';
|
|
141
|
+
this.dashboardHost = 'https://dashboard.blockchyp.com';
|
|
142
|
+
this.coreHost = opts.coreHost || DEFAULT_CORE_HOST;
|
|
143
|
+
this.bearerToken = creds.bearerToken;
|
|
144
|
+
// bcCredentials holds the short-lived BlockChyp transient credentials
|
|
145
|
+
// obtained by exchanging the Stax bearer token. SDK-managed; never set by
|
|
146
|
+
// the integrator.
|
|
147
|
+
this.bcCredentials = undefined;
|
|
148
|
+
this.bcCredentialsExpiresAtMs = 0;
|
|
149
|
+
// Single-flight guard: concurrent callers share one in-flight exchange.
|
|
150
|
+
this.bcCredentialsInFlight = undefined;
|
|
151
|
+
this.https = true;
|
|
152
|
+
this.cloudRelay = false;
|
|
153
|
+
this.routeCacheTTL = 60;
|
|
154
|
+
this.gatewayTimeout = 20;
|
|
155
|
+
this.terminalTimeout = 120;
|
|
156
|
+
this._routeCache = {};
|
|
157
|
+
}
|
|
158
|
+
return (0, _createClass2["default"])(StaxPaymentsBaseClient, [{
|
|
159
|
+
key: "getGatewayHost",
|
|
160
|
+
value: function getGatewayHost() {
|
|
161
|
+
return this.gatewayHost;
|
|
162
|
+
}
|
|
163
|
+
}, {
|
|
164
|
+
key: "getDashboardHost",
|
|
165
|
+
value: function getDashboardHost() {
|
|
166
|
+
return this.dashboardHost;
|
|
167
|
+
}
|
|
168
|
+
}, {
|
|
169
|
+
key: "setGatewayHost",
|
|
170
|
+
value: function setGatewayHost(host) {
|
|
171
|
+
this.gatewayHost = host;
|
|
172
|
+
}
|
|
173
|
+
}, {
|
|
174
|
+
key: "setDashboardHost",
|
|
175
|
+
value: function setDashboardHost(host) {
|
|
176
|
+
this.dashboardHost = host;
|
|
177
|
+
}
|
|
178
|
+
}, {
|
|
179
|
+
key: "setTestGatewayHost",
|
|
180
|
+
value: function setTestGatewayHost(host) {
|
|
181
|
+
this.testGatewayHost = host;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// setCoreHost overrides the Stax core API host. An empty host resets it to the
|
|
185
|
+
// default. Cached credentials remain valid; subsequent exchanges and
|
|
186
|
+
// core-routed calls use the new host.
|
|
187
|
+
}, {
|
|
188
|
+
key: "setCoreHost",
|
|
189
|
+
value: function setCoreHost(host) {
|
|
190
|
+
this.coreHost = host || DEFAULT_CORE_HOST;
|
|
191
|
+
}
|
|
192
|
+
}, {
|
|
193
|
+
key: "heartbeat",
|
|
194
|
+
value: function heartbeat() {
|
|
195
|
+
return this._gatewayRequest('get', '/api/heartbeat');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// routeTransaction runs a transaction end to end, dispatching based on whether
|
|
199
|
+
// a terminal is named: to the terminal (card-present), directly or via cloud
|
|
200
|
+
// relay, when a terminal name is supplied, or to the gateway (card-not-present)
|
|
201
|
+
// otherwise.
|
|
202
|
+
}, {
|
|
203
|
+
key: "routeTransaction",
|
|
204
|
+
value: function () {
|
|
205
|
+
var _routeTransaction = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee(method, request, terminalPath, cloudPath) {
|
|
206
|
+
var response, route, _t;
|
|
207
|
+
return _regenerator["default"].wrap(function (_context) {
|
|
208
|
+
while (1) switch (_context.prev = _context.next) {
|
|
209
|
+
case 0:
|
|
210
|
+
_context.next = 1;
|
|
211
|
+
return this.ensure();
|
|
212
|
+
case 1:
|
|
213
|
+
_context.next = 2;
|
|
214
|
+
return this._populateSignatureOptions(request);
|
|
215
|
+
case 2:
|
|
216
|
+
if (!this.isTerminalRouted(request)) {
|
|
217
|
+
_context.next = 8;
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
_context.next = 3;
|
|
221
|
+
return this._resolveTerminalRoute(request.terminalName);
|
|
222
|
+
case 3:
|
|
223
|
+
route = _context.sent;
|
|
224
|
+
if (!route.cloudRelayEnabled) {
|
|
225
|
+
_context.next = 5;
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
_context.next = 4;
|
|
229
|
+
return this._relayRequest(method, cloudPath, request);
|
|
230
|
+
case 4:
|
|
231
|
+
_t = _context.sent;
|
|
232
|
+
_context.next = 7;
|
|
233
|
+
break;
|
|
234
|
+
case 5:
|
|
235
|
+
_context.next = 6;
|
|
236
|
+
return this._terminalRequest(method, route, terminalPath, request);
|
|
237
|
+
case 6:
|
|
238
|
+
_t = _context.sent;
|
|
239
|
+
case 7:
|
|
240
|
+
response = _t;
|
|
241
|
+
_context.next = 10;
|
|
242
|
+
break;
|
|
243
|
+
case 8:
|
|
244
|
+
_context.next = 9;
|
|
245
|
+
return this._gatewayRequest(method, cloudPath, request);
|
|
246
|
+
case 9:
|
|
247
|
+
response = _context.sent;
|
|
248
|
+
case 10:
|
|
249
|
+
_context.next = 11;
|
|
250
|
+
return this._handleSignature(request, response ? response.data : undefined);
|
|
251
|
+
case 11:
|
|
252
|
+
return _context.abrupt("return", response);
|
|
253
|
+
case 12:
|
|
254
|
+
case "end":
|
|
255
|
+
return _context.stop();
|
|
256
|
+
}
|
|
257
|
+
}, _callee, this);
|
|
258
|
+
}));
|
|
259
|
+
function routeTransaction(_x, _x2, _x3, _x4) {
|
|
260
|
+
return _routeTransaction.apply(this, arguments);
|
|
261
|
+
}
|
|
262
|
+
return routeTransaction;
|
|
263
|
+
}()
|
|
264
|
+
}, {
|
|
265
|
+
key: "routeTransactionPost",
|
|
266
|
+
value: function () {
|
|
267
|
+
var _routeTransactionPost = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee2(request, terminalPath, cloudPath) {
|
|
268
|
+
return _regenerator["default"].wrap(function (_context2) {
|
|
269
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
270
|
+
case 0:
|
|
271
|
+
return _context2.abrupt("return", this.routeTransaction('post', request, terminalPath, cloudPath));
|
|
272
|
+
case 1:
|
|
273
|
+
case "end":
|
|
274
|
+
return _context2.stop();
|
|
275
|
+
}
|
|
276
|
+
}, _callee2, this);
|
|
277
|
+
}));
|
|
278
|
+
function routeTransactionPost(_x5, _x6, _x7) {
|
|
279
|
+
return _routeTransactionPost.apply(this, arguments);
|
|
280
|
+
}
|
|
281
|
+
return routeTransactionPost;
|
|
282
|
+
}()
|
|
283
|
+
}, {
|
|
284
|
+
key: "returnValidationError",
|
|
285
|
+
value: function returnValidationError(desc) {
|
|
286
|
+
var result = {
|
|
287
|
+
data: {
|
|
288
|
+
approved: false,
|
|
289
|
+
success: false,
|
|
290
|
+
error: desc
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
return result;
|
|
294
|
+
}
|
|
295
|
+
}, {
|
|
296
|
+
key: "validateRequest",
|
|
297
|
+
value: function validateRequest(request) {
|
|
298
|
+
if (!this.validateCurrency(request.amount)) {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
return true;
|
|
302
|
+
}
|
|
303
|
+
}, {
|
|
304
|
+
key: "validateCurrency",
|
|
305
|
+
value: function validateCurrency(val) {
|
|
306
|
+
var amt = parseFloat(val);
|
|
307
|
+
console.log(amt);
|
|
308
|
+
if (amt && !isNaN(amt)) {
|
|
309
|
+
var decMatch = val.match(/\./g || []);
|
|
310
|
+
if (decMatch && decMatch.length > 1) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// isTerminalRouted reports whether a request names a terminal. Whether that
|
|
319
|
+
// terminal is reached directly or over cloud relay is a property of its
|
|
320
|
+
// route, resolved per terminal, not a client-wide setting.
|
|
321
|
+
}, {
|
|
322
|
+
key: "isTerminalRouted",
|
|
323
|
+
value: function isTerminalRouted(request) {
|
|
324
|
+
return Boolean(request && request.terminalName);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// ensure guarantees the client holds valid merchant-scoped transient
|
|
328
|
+
// credentials, exchanging the Stax bearer token via the core API when the
|
|
329
|
+
// cache is empty or near expiry. Concurrent callers share one in-flight
|
|
330
|
+
// exchange (single-flight). Terminal calls invoke this before routing.
|
|
331
|
+
}, {
|
|
332
|
+
key: "ensure",
|
|
333
|
+
value: function () {
|
|
334
|
+
var _ensure = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee3() {
|
|
335
|
+
return _regenerator["default"].wrap(function (_context3) {
|
|
336
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
337
|
+
case 0:
|
|
338
|
+
if (!(this.bcCredentials && Date.now() + EXPIRY_SKEW_MS < this.bcCredentialsExpiresAtMs)) {
|
|
339
|
+
_context3.next = 1;
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
342
|
+
return _context3.abrupt("return");
|
|
343
|
+
case 1:
|
|
344
|
+
if (!this.bcCredentialsInFlight) {
|
|
345
|
+
_context3.next = 3;
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
_context3.next = 2;
|
|
349
|
+
return this.bcCredentialsInFlight;
|
|
350
|
+
case 2:
|
|
351
|
+
return _context3.abrupt("return");
|
|
352
|
+
case 3:
|
|
353
|
+
this.bcCredentialsInFlight = this._exchange();
|
|
354
|
+
_context3.prev = 4;
|
|
355
|
+
_context3.next = 5;
|
|
356
|
+
return this.bcCredentialsInFlight;
|
|
357
|
+
case 5:
|
|
358
|
+
_context3.prev = 5;
|
|
359
|
+
this.bcCredentialsInFlight = undefined;
|
|
360
|
+
return _context3.finish(5);
|
|
361
|
+
case 6:
|
|
362
|
+
case "end":
|
|
363
|
+
return _context3.stop();
|
|
364
|
+
}
|
|
365
|
+
}, _callee3, this, [[4,, 5, 6]]);
|
|
366
|
+
}));
|
|
367
|
+
function ensure() {
|
|
368
|
+
return _ensure.apply(this, arguments);
|
|
369
|
+
}
|
|
370
|
+
return ensure;
|
|
371
|
+
}()
|
|
372
|
+
}, {
|
|
373
|
+
key: "_exchange",
|
|
374
|
+
value: function () {
|
|
375
|
+
var _exchange2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee4() {
|
|
376
|
+
var response, data;
|
|
377
|
+
return _regenerator["default"].wrap(function (_context4) {
|
|
378
|
+
while (1) switch (_context4.prev = _context4.next) {
|
|
379
|
+
case 0:
|
|
380
|
+
_context4.next = 1;
|
|
381
|
+
return this._coreRequest('get', TRANSIENT_CREDENTIALS_PATH);
|
|
382
|
+
case 1:
|
|
383
|
+
response = _context4.sent;
|
|
384
|
+
data = response.data;
|
|
385
|
+
this.bcCredentials = new StaxPaymentsCredentials(data.apiKey, data.bearerToken, data.signingKey);
|
|
386
|
+
this.bcCredentialsExpiresAtMs = data.expiresAt ? Date.parse(data.expiresAt) : Date.now() + EXPIRY_FALLBACK_MS;
|
|
387
|
+
case 2:
|
|
388
|
+
case "end":
|
|
389
|
+
return _context4.stop();
|
|
390
|
+
}
|
|
391
|
+
}, _callee4, this);
|
|
392
|
+
}));
|
|
393
|
+
function _exchange() {
|
|
394
|
+
return _exchange2.apply(this, arguments);
|
|
395
|
+
}
|
|
396
|
+
return _exchange;
|
|
397
|
+
}()
|
|
398
|
+
}, {
|
|
399
|
+
key: "_relayRequest",
|
|
400
|
+
value: function _relayRequest(method, path, request) {
|
|
401
|
+
return this._gatewayRequest(method, path, request, true);
|
|
402
|
+
}
|
|
403
|
+
}, {
|
|
404
|
+
key: "_uploadRequest",
|
|
405
|
+
value: function () {
|
|
406
|
+
var _uploadRequest2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee5(path, request, content) {
|
|
407
|
+
var config;
|
|
408
|
+
return _regenerator["default"].wrap(function (_context5) {
|
|
409
|
+
while (1) switch (_context5.prev = _context5.next) {
|
|
410
|
+
case 0:
|
|
411
|
+
_context5.next = 1;
|
|
412
|
+
return this.ensure();
|
|
413
|
+
case 1:
|
|
414
|
+
config = {
|
|
415
|
+
method: 'post',
|
|
416
|
+
url: this._assembleDashboardUrl(path),
|
|
417
|
+
timeout: this._getTimeout(request, this.gatewayTimeout) * 1000,
|
|
418
|
+
headers: (0, _defineProperty2["default"])({}, AGENT_HEADER, USER_AGENT)
|
|
419
|
+
};
|
|
420
|
+
config.data = content;
|
|
421
|
+
if (this.bcCredentials && this.bcCredentials.apiKey) {
|
|
422
|
+
config.headers = Object.assign(config.headers, _cryptoutils["default"].generateGatewayHeaders(this.bcCredentials));
|
|
423
|
+
}
|
|
424
|
+
if (request.fileSize) {
|
|
425
|
+
config.headers['X-File-Size'] = request.fileSize.toFixed();
|
|
426
|
+
}
|
|
427
|
+
if (request.fileName) {
|
|
428
|
+
config.headers['X-Upload-File-Name'] = request.fileName;
|
|
429
|
+
}
|
|
430
|
+
if (request.uploadId) {
|
|
431
|
+
config.headers['X-Upload-ID'] = request.uploadId;
|
|
432
|
+
}
|
|
433
|
+
return _context5.abrupt("return", (0, _axios["default"])(config));
|
|
434
|
+
case 2:
|
|
435
|
+
case "end":
|
|
436
|
+
return _context5.stop();
|
|
437
|
+
}
|
|
438
|
+
}, _callee5, this);
|
|
439
|
+
}));
|
|
440
|
+
function _uploadRequest(_x8, _x9, _x0) {
|
|
441
|
+
return _uploadRequest2.apply(this, arguments);
|
|
442
|
+
}
|
|
443
|
+
return _uploadRequest;
|
|
444
|
+
}()
|
|
445
|
+
}, {
|
|
446
|
+
key: "_dashboardRequest",
|
|
447
|
+
value: function () {
|
|
448
|
+
var _dashboardRequest2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee6(method, path, request) {
|
|
449
|
+
var config;
|
|
450
|
+
return _regenerator["default"].wrap(function (_context6) {
|
|
451
|
+
while (1) switch (_context6.prev = _context6.next) {
|
|
452
|
+
case 0:
|
|
453
|
+
_context6.next = 1;
|
|
454
|
+
return this.ensure();
|
|
455
|
+
case 1:
|
|
456
|
+
config = {
|
|
457
|
+
method: method,
|
|
458
|
+
url: this._assembleDashboardUrl(path),
|
|
459
|
+
timeout: this._getTimeout(request, this.gatewayTimeout) * 1000,
|
|
460
|
+
headers: (0, _defineProperty2["default"])((0, _defineProperty2["default"])({}, AGENT_HEADER, USER_AGENT), 'Content-Type', 'application/json')
|
|
461
|
+
};
|
|
462
|
+
if (method !== 'get') {
|
|
463
|
+
config.data = request;
|
|
464
|
+
}
|
|
465
|
+
if (this.bcCredentials && this.bcCredentials.apiKey) {
|
|
466
|
+
config.headers = Object.assign(config.headers, _cryptoutils["default"].generateGatewayHeaders(this.bcCredentials));
|
|
467
|
+
}
|
|
468
|
+
return _context6.abrupt("return", (0, _axios["default"])(config));
|
|
469
|
+
case 2:
|
|
470
|
+
case "end":
|
|
471
|
+
return _context6.stop();
|
|
472
|
+
}
|
|
473
|
+
}, _callee6, this);
|
|
474
|
+
}));
|
|
475
|
+
function _dashboardRequest(_x1, _x10, _x11) {
|
|
476
|
+
return _dashboardRequest2.apply(this, arguments);
|
|
477
|
+
}
|
|
478
|
+
return _dashboardRequest;
|
|
479
|
+
}()
|
|
480
|
+
}, {
|
|
481
|
+
key: "_gatewayRequest",
|
|
482
|
+
value: function () {
|
|
483
|
+
var _gatewayRequest2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee7(method, path, request, relay) {
|
|
484
|
+
var config;
|
|
485
|
+
return _regenerator["default"].wrap(function (_context7) {
|
|
486
|
+
while (1) switch (_context7.prev = _context7.next) {
|
|
487
|
+
case 0:
|
|
488
|
+
_context7.next = 1;
|
|
489
|
+
return this.ensure();
|
|
490
|
+
case 1:
|
|
491
|
+
config = {
|
|
492
|
+
method: method,
|
|
493
|
+
url: this._assembleGatewayUrl(path, request),
|
|
494
|
+
timeout: this._getTimeout(request, relay ? this.terminalTimeout : this.gatewayTimeout) * 1000,
|
|
495
|
+
headers: (0, _defineProperty2["default"])((0, _defineProperty2["default"])({}, AGENT_HEADER, USER_AGENT), 'Content-Type', 'application/json')
|
|
496
|
+
};
|
|
497
|
+
if (method !== 'get') {
|
|
498
|
+
config.data = request;
|
|
499
|
+
}
|
|
500
|
+
if (this.bcCredentials && this.bcCredentials.apiKey) {
|
|
501
|
+
config.headers = Object.assign(config.headers, _cryptoutils["default"].generateGatewayHeaders(this.bcCredentials));
|
|
502
|
+
}
|
|
503
|
+
return _context7.abrupt("return", (0, _axios["default"])(config));
|
|
504
|
+
case 2:
|
|
505
|
+
case "end":
|
|
506
|
+
return _context7.stop();
|
|
507
|
+
}
|
|
508
|
+
}, _callee7, this);
|
|
509
|
+
}));
|
|
510
|
+
function _gatewayRequest(_x12, _x13, _x14, _x15) {
|
|
511
|
+
return _gatewayRequest2.apply(this, arguments);
|
|
512
|
+
}
|
|
513
|
+
return _gatewayRequest;
|
|
514
|
+
}() // _coreRequest sends a request to the Stax core API authenticated with the
|
|
515
|
+
// Stax bearer token. It mirrors _gatewayRequest/_dashboardRequest, differing
|
|
516
|
+
// only in host (coreHost) and auth (the Stax bearer token rather than HMAC
|
|
517
|
+
// credentials). Used by core-routed endpoints and the internal
|
|
518
|
+
// transient-credential exchange.
|
|
519
|
+
}, {
|
|
520
|
+
key: "_coreRequest",
|
|
521
|
+
value: function _coreRequest(method, path, request) {
|
|
522
|
+
var config = {
|
|
523
|
+
method: method,
|
|
524
|
+
url: this._assembleCoreUrl(path),
|
|
525
|
+
timeout: this._getTimeout(request, this.gatewayTimeout) * 1000,
|
|
526
|
+
headers: (0, _defineProperty2["default"])((0, _defineProperty2["default"])((0, _defineProperty2["default"])({}, AGENT_HEADER, USER_AGENT), 'Content-Type', 'application/json'), "Authorization", "Bearer ".concat(this.bearerToken))
|
|
527
|
+
};
|
|
528
|
+
if (method !== 'get') {
|
|
529
|
+
config.data = request;
|
|
530
|
+
}
|
|
531
|
+
return (0, _axios["default"])(config);
|
|
532
|
+
}
|
|
533
|
+
}, {
|
|
534
|
+
key: "_getTimeout",
|
|
535
|
+
value: function _getTimeout(request, defaultTimeout) {
|
|
536
|
+
if (request && 'timeout' in request) {
|
|
537
|
+
return request['timeout'];
|
|
538
|
+
}
|
|
539
|
+
return defaultTimeout;
|
|
540
|
+
}
|
|
541
|
+
}, {
|
|
542
|
+
key: "_assembleDashboardUrl",
|
|
543
|
+
value: function _assembleDashboardUrl(path) {
|
|
544
|
+
return this.dashboardHost + path;
|
|
545
|
+
}
|
|
546
|
+
}, {
|
|
547
|
+
key: "_assembleCoreUrl",
|
|
548
|
+
value: function _assembleCoreUrl(path) {
|
|
549
|
+
return this.coreHost + path;
|
|
550
|
+
}
|
|
551
|
+
}, {
|
|
552
|
+
key: "_assembleGatewayUrl",
|
|
553
|
+
value: function _assembleGatewayUrl(path, payload) {
|
|
554
|
+
var result = '';
|
|
555
|
+
if (payload && payload.test) {
|
|
556
|
+
result = result + this.testGatewayHost;
|
|
557
|
+
} else {
|
|
558
|
+
result = result + this.gatewayHost;
|
|
559
|
+
}
|
|
560
|
+
result = result + path;
|
|
561
|
+
return result;
|
|
562
|
+
}
|
|
563
|
+
}, {
|
|
564
|
+
key: "_terminalRequest",
|
|
565
|
+
value: function () {
|
|
566
|
+
var _terminalRequest2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee8(method, route, path, request) {
|
|
567
|
+
var url, config;
|
|
568
|
+
return _regenerator["default"].wrap(function (_context8) {
|
|
569
|
+
while (1) switch (_context8.prev = _context8.next) {
|
|
570
|
+
case 0:
|
|
571
|
+
_context8.next = 1;
|
|
572
|
+
return this._assembleTerminalUrl(route, path);
|
|
573
|
+
case 1:
|
|
574
|
+
url = _context8.sent;
|
|
575
|
+
config = {
|
|
576
|
+
method: method,
|
|
577
|
+
url: url,
|
|
578
|
+
headers: (0, _defineProperty2["default"])((0, _defineProperty2["default"])({}, AGENT_HEADER, USER_AGENT), 'Content-Type', 'application/json'),
|
|
579
|
+
timeout: this._getTimeout(request, this.terminalTimeout) * 1000
|
|
580
|
+
};
|
|
581
|
+
if (this.https) {
|
|
582
|
+
if (_https["default"]) {
|
|
583
|
+
config.httpsAgent = new _https["default"].Agent({
|
|
584
|
+
rejectUnauthorized: false
|
|
585
|
+
});
|
|
586
|
+
} else {
|
|
587
|
+
config.httpsAgent = new _httpsBrowserify["default"].Agent({
|
|
588
|
+
rejectUnauthorized: false
|
|
589
|
+
});
|
|
590
|
+
config.httpsAgent.protocol = 'https:';
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
if (request) {
|
|
594
|
+
config.data = {
|
|
595
|
+
apiKey: route.transientCredentials.apiKey,
|
|
596
|
+
bearerToken: route.transientCredentials.bearerToken,
|
|
597
|
+
signingKey: route.transientCredentials.signingKey,
|
|
598
|
+
request: request
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
return _context8.abrupt("return", (0, _axios["default"])(config));
|
|
602
|
+
case 2:
|
|
603
|
+
case "end":
|
|
604
|
+
return _context8.stop();
|
|
605
|
+
}
|
|
606
|
+
}, _callee8, this);
|
|
607
|
+
}));
|
|
608
|
+
function _terminalRequest(_x16, _x17, _x18, _x19) {
|
|
609
|
+
return _terminalRequest2.apply(this, arguments);
|
|
610
|
+
}
|
|
611
|
+
return _terminalRequest;
|
|
612
|
+
}()
|
|
613
|
+
}, {
|
|
614
|
+
key: "_assembleTerminalUrl",
|
|
615
|
+
value: function _assembleTerminalUrl(route, path) {
|
|
616
|
+
var result = 'http';
|
|
617
|
+
if (this.https) {
|
|
618
|
+
result = result + 's';
|
|
619
|
+
}
|
|
620
|
+
result = result + '://';
|
|
621
|
+
result = result + route.ipAddress;
|
|
622
|
+
if (this.https) {
|
|
623
|
+
result = result + ':8443';
|
|
624
|
+
} else {
|
|
625
|
+
result = result + ':8080';
|
|
626
|
+
}
|
|
627
|
+
result = result + path;
|
|
628
|
+
return result;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// _populateSignatureOptions infers the signature image format from the
|
|
632
|
+
// requested file extension when the caller did not state one, and rejects a
|
|
633
|
+
// format the terminal cannot produce before the transaction is sent.
|
|
634
|
+
}, {
|
|
635
|
+
key: "_populateSignatureOptions",
|
|
636
|
+
value: function () {
|
|
637
|
+
var _populateSignatureOptions2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee9(request) {
|
|
638
|
+
var parts, valid;
|
|
639
|
+
return _regenerator["default"].wrap(function (_context9) {
|
|
640
|
+
while (1) switch (_context9.prev = _context9.next) {
|
|
641
|
+
case 0:
|
|
642
|
+
if (!(!request || !request.sigFile)) {
|
|
643
|
+
_context9.next = 1;
|
|
644
|
+
break;
|
|
645
|
+
}
|
|
646
|
+
return _context9.abrupt("return");
|
|
647
|
+
case 1:
|
|
648
|
+
if (!request.sigFormat) {
|
|
649
|
+
parts = String(request.sigFile).split('.');
|
|
650
|
+
request.sigFormat = parts[parts.length - 1].toLowerCase();
|
|
651
|
+
}
|
|
652
|
+
valid = [SignatureFormat.NONE, SignatureFormat.PNG, SignatureFormat.JPG, SignatureFormat.GIF];
|
|
653
|
+
if (!(valid.indexOf(request.sigFormat) < 0)) {
|
|
654
|
+
_context9.next = 2;
|
|
655
|
+
break;
|
|
656
|
+
}
|
|
657
|
+
throw new Error('invalid signature format: ' + request.sigFormat);
|
|
658
|
+
case 2:
|
|
659
|
+
case "end":
|
|
660
|
+
return _context9.stop();
|
|
661
|
+
}
|
|
662
|
+
}, _callee9);
|
|
663
|
+
}));
|
|
664
|
+
function _populateSignatureOptions(_x20) {
|
|
665
|
+
return _populateSignatureOptions2.apply(this, arguments);
|
|
666
|
+
}
|
|
667
|
+
return _populateSignatureOptions;
|
|
668
|
+
}() // _handleSignature writes the captured signature image to the file the caller
|
|
669
|
+
// asked for and clears it from the response, so the hex payload is not left
|
|
670
|
+
// in an object the caller is likely to log. Writing needs a filesystem, so in
|
|
671
|
+
// the browser the image is left on the response instead.
|
|
672
|
+
}, {
|
|
673
|
+
key: "_handleSignature",
|
|
674
|
+
value: function () {
|
|
675
|
+
var _handleSignature2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee0(request, response) {
|
|
676
|
+
var fs, content;
|
|
677
|
+
return _regenerator["default"].wrap(function (_context0) {
|
|
678
|
+
while (1) switch (_context0.prev = _context0.next) {
|
|
679
|
+
case 0:
|
|
680
|
+
if (!(!request || !request.sigFile || !response || !response.sigFile)) {
|
|
681
|
+
_context0.next = 1;
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
return _context0.abrupt("return");
|
|
685
|
+
case 1:
|
|
686
|
+
fs = optionalNodeModule('fs');
|
|
687
|
+
if (fs) {
|
|
688
|
+
_context0.next = 2;
|
|
689
|
+
break;
|
|
690
|
+
}
|
|
691
|
+
return _context0.abrupt("return");
|
|
692
|
+
case 2:
|
|
693
|
+
content = Buffer.from(response.sigFile, 'hex');
|
|
694
|
+
response.sigFile = '';
|
|
695
|
+
fs.writeFileSync(request.sigFile, content, {
|
|
696
|
+
mode: 384
|
|
697
|
+
});
|
|
698
|
+
case 3:
|
|
699
|
+
case "end":
|
|
700
|
+
return _context0.stop();
|
|
701
|
+
}
|
|
702
|
+
}, _callee0);
|
|
703
|
+
}));
|
|
704
|
+
function _handleSignature(_x21, _x22) {
|
|
705
|
+
return _handleSignature2.apply(this, arguments);
|
|
706
|
+
}
|
|
707
|
+
return _handleSignature;
|
|
708
|
+
}() // _offlineCacheFile is the path routes are persisted to, or undefined in the
|
|
709
|
+
// browser, where there is nothing to persist to.
|
|
710
|
+
}, {
|
|
711
|
+
key: "_offlineCacheFile",
|
|
712
|
+
value: function _offlineCacheFile() {
|
|
713
|
+
var os = optionalNodeModule('os');
|
|
714
|
+
var path = optionalNodeModule('path');
|
|
715
|
+
if (!os || !path) {
|
|
716
|
+
return undefined;
|
|
717
|
+
}
|
|
718
|
+
return path.join(os.tmpdir(), '.staxpayments_routes');
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// _routeCacheKey scopes a cached route to the credentials that resolved it, so
|
|
722
|
+
// rotating credentials cannot serve a route resolved under the previous set.
|
|
723
|
+
}, {
|
|
724
|
+
key: "_routeCacheKey",
|
|
725
|
+
value: function _routeCacheKey(terminalName) {
|
|
726
|
+
return (this.bcCredentials ? this.bcCredentials.apiKey : '') + terminalName;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// _deriveOfflineKey hashes the fixed key together with the current signing
|
|
730
|
+
// key. The cache is therefore readable only while the same credentials are
|
|
731
|
+
// held, and unreadable to anything else that finds the file.
|
|
732
|
+
}, {
|
|
733
|
+
key: "_deriveOfflineKey",
|
|
734
|
+
value: function _deriveOfflineKey() {
|
|
735
|
+
var signingKey = this.bcCredentials ? this.bcCredentials.signingKey : '';
|
|
736
|
+
var input = new Uint8Array([].concat((0, _toConsumableArray2["default"])((0, _utils.hexToBytes)(OFFLINE_FIXED_KEY)), (0, _toConsumableArray2["default"])((0, _utils.hexToBytes)(signingKey))));
|
|
737
|
+
return (0, _sha.sha256)(input);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// AES/CBC/PKCS7 over the first 16 bytes of the derived key, hex encoded with
|
|
741
|
+
// the IV prefixed. The scheme is shared with the other Stax Payments SDKs.
|
|
742
|
+
}, {
|
|
743
|
+
key: "_encrypt",
|
|
744
|
+
value: function _encrypt(value) {
|
|
745
|
+
var key = this._deriveOfflineKey().slice(0, 16);
|
|
746
|
+
var iv = (0, _utils.randomBytes)(16);
|
|
747
|
+
var cbc = new _aesJs["default"].ModeOfOperation.cbc(key, iv);
|
|
748
|
+
var encrypted = cbc.encrypt(_aesJs["default"].padding.pkcs7.pad((0, _utils.utf8ToBytes)(value)));
|
|
749
|
+
return (0, _utils.bytesToHex)(iv) + (0, _utils.bytesToHex)(encrypted);
|
|
750
|
+
}
|
|
751
|
+
}, {
|
|
752
|
+
key: "_decrypt",
|
|
753
|
+
value: function _decrypt(value) {
|
|
754
|
+
var key = this._deriveOfflineKey().slice(0, 16);
|
|
755
|
+
var raw = (0, _utils.hexToBytes)(value);
|
|
756
|
+
var cbc = new _aesJs["default"].ModeOfOperation.cbc(key, raw.slice(0, 16));
|
|
757
|
+
var decrypted = _aesJs["default"].padding.pkcs7.strip(cbc.decrypt(raw.slice(16)));
|
|
758
|
+
return _aesJs["default"].utils.utf8.fromBytes(decrypted);
|
|
759
|
+
}
|
|
760
|
+
}, {
|
|
761
|
+
key: "_readOfflineCache",
|
|
762
|
+
value: function _readOfflineCache() {
|
|
763
|
+
var fs = optionalNodeModule('fs');
|
|
764
|
+
var file = this._offlineCacheFile();
|
|
765
|
+
if (!fs || !file) {
|
|
766
|
+
return undefined;
|
|
767
|
+
}
|
|
768
|
+
try {
|
|
769
|
+
if (!fs.existsSync(file)) {
|
|
770
|
+
return undefined;
|
|
771
|
+
}
|
|
772
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
773
|
+
} catch (e) {
|
|
774
|
+
// An unreadable or corrupt cache is a missing cache, never a failed
|
|
775
|
+
// transaction.
|
|
776
|
+
return undefined;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// _readFromOfflineCache returns a persisted route. Credentials are decrypted
|
|
781
|
+
// on the way out. When stale is false an expired entry is ignored; when true
|
|
782
|
+
// it is served anyway, which is what keeps a terminal reachable while the
|
|
783
|
+
// gateway is not.
|
|
784
|
+
}, {
|
|
785
|
+
key: "_readFromOfflineCache",
|
|
786
|
+
value: function _readFromOfflineCache(terminalName, stale) {
|
|
787
|
+
var cache = this._readOfflineCache();
|
|
788
|
+
if (!cache || !cache.routes) {
|
|
789
|
+
return undefined;
|
|
790
|
+
}
|
|
791
|
+
var entry = cache.routes[this._routeCacheKey(terminalName)];
|
|
792
|
+
if (!entry) {
|
|
793
|
+
return undefined;
|
|
794
|
+
}
|
|
795
|
+
if (!stale && Date.parse(entry.TTL) <= Date.now()) {
|
|
796
|
+
return undefined;
|
|
797
|
+
}
|
|
798
|
+
try {
|
|
799
|
+
var route = entry.Route;
|
|
800
|
+
route.transientCredentials = {
|
|
801
|
+
apiKey: this._decrypt(route.transientCredentials.apiKey),
|
|
802
|
+
bearerToken: this._decrypt(route.transientCredentials.bearerToken),
|
|
803
|
+
signingKey: this._decrypt(route.transientCredentials.signingKey)
|
|
804
|
+
};
|
|
805
|
+
return route;
|
|
806
|
+
} catch (e) {
|
|
807
|
+
// Written under different credentials, so it cannot be decrypted now.
|
|
808
|
+
return undefined;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}, {
|
|
812
|
+
key: "_updateOfflineCache",
|
|
813
|
+
value: function _updateOfflineCache(route, ttlMs) {
|
|
814
|
+
var fs = optionalNodeModule('fs');
|
|
815
|
+
var file = this._offlineCacheFile();
|
|
816
|
+
if (!fs || !file) {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
try {
|
|
820
|
+
var cache = this._readOfflineCache() || {
|
|
821
|
+
routes: {}
|
|
822
|
+
};
|
|
823
|
+
if (!cache.routes) {
|
|
824
|
+
cache.routes = {};
|
|
825
|
+
}
|
|
826
|
+
cache.routes[this._routeCacheKey(route.terminalName)] = {
|
|
827
|
+
TTL: new Date(ttlMs).toISOString(),
|
|
828
|
+
Route: Object.assign({}, route, {
|
|
829
|
+
transientCredentials: {
|
|
830
|
+
apiKey: this._encrypt(route.transientCredentials.apiKey),
|
|
831
|
+
bearerToken: this._encrypt(route.transientCredentials.bearerToken),
|
|
832
|
+
signingKey: this._encrypt(route.transientCredentials.signingKey)
|
|
833
|
+
}
|
|
834
|
+
})
|
|
835
|
+
};
|
|
836
|
+
fs.writeFileSync(file, JSON.stringify(cache), {
|
|
837
|
+
mode: 384
|
|
838
|
+
});
|
|
839
|
+
} catch (e) {
|
|
840
|
+
// Persisting is an optimization; the in-memory cache still stands.
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
// _requestRouteFromGateway resolves a route and rejects anything that is not
|
|
845
|
+
// a usable one, so a failed lookup is never cached or routed on.
|
|
846
|
+
}, {
|
|
847
|
+
key: "_requestRouteFromGateway",
|
|
848
|
+
value: function () {
|
|
849
|
+
var _requestRouteFromGateway2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee1(terminalName) {
|
|
850
|
+
var routeResponse, route;
|
|
851
|
+
return _regenerator["default"].wrap(function (_context1) {
|
|
852
|
+
while (1) switch (_context1.prev = _context1.next) {
|
|
853
|
+
case 0:
|
|
854
|
+
_context1.next = 1;
|
|
855
|
+
return this._gatewayRequest('get', '/api/terminal-route?terminal=' + encodeURIComponent(terminalName));
|
|
856
|
+
case 1:
|
|
857
|
+
routeResponse = _context1.sent;
|
|
858
|
+
route = routeResponse.data;
|
|
859
|
+
if (!(!route || route.success === false || !route.ipAddress)) {
|
|
860
|
+
_context1.next = 2;
|
|
861
|
+
break;
|
|
862
|
+
}
|
|
863
|
+
throw new Error('unknown terminal: ' + terminalName);
|
|
864
|
+
case 2:
|
|
865
|
+
route.exists = true;
|
|
866
|
+
route.https = true;
|
|
867
|
+
return _context1.abrupt("return", route);
|
|
868
|
+
case 3:
|
|
869
|
+
case "end":
|
|
870
|
+
return _context1.stop();
|
|
871
|
+
}
|
|
872
|
+
}, _callee1, this);
|
|
873
|
+
}));
|
|
874
|
+
function _requestRouteFromGateway(_x23) {
|
|
875
|
+
return _requestRouteFromGateway2.apply(this, arguments);
|
|
876
|
+
}
|
|
877
|
+
return _requestRouteFromGateway;
|
|
878
|
+
}()
|
|
879
|
+
}, {
|
|
880
|
+
key: "_resolveTerminalRoute",
|
|
881
|
+
value: function () {
|
|
882
|
+
var _resolveTerminalRoute2 = (0, _asyncToGenerator2["default"])(/*#__PURE__*/_regenerator["default"].mark(function _callee10(terminalName) {
|
|
883
|
+
var key, cacheEntry, offline, route, stale, ttl, _t2;
|
|
884
|
+
return _regenerator["default"].wrap(function (_context10) {
|
|
885
|
+
while (1) switch (_context10.prev = _context10.next) {
|
|
886
|
+
case 0:
|
|
887
|
+
key = this._routeCacheKey(terminalName);
|
|
888
|
+
cacheEntry = this._routeCache[key];
|
|
889
|
+
if (!(cacheEntry && cacheEntry.ttl >= new Date().getTime())) {
|
|
890
|
+
_context10.next = 1;
|
|
891
|
+
break;
|
|
892
|
+
}
|
|
893
|
+
return _context10.abrupt("return", cacheEntry.route);
|
|
894
|
+
case 1:
|
|
895
|
+
if (!((terminalName.match(/\./g) || []).length === 3)) {
|
|
896
|
+
_context10.next = 2;
|
|
897
|
+
break;
|
|
898
|
+
}
|
|
899
|
+
return _context10.abrupt("return", {
|
|
900
|
+
terminalName: terminalName,
|
|
901
|
+
ipAddress: terminalName,
|
|
902
|
+
cloudRelayEnabled: false,
|
|
903
|
+
exists: true,
|
|
904
|
+
https: false,
|
|
905
|
+
transientCredentials: {
|
|
906
|
+
apiKey: '',
|
|
907
|
+
bearerToken: '',
|
|
908
|
+
signingKey: ''
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
case 2:
|
|
912
|
+
offline = this._readFromOfflineCache(terminalName, false);
|
|
913
|
+
if (!offline) {
|
|
914
|
+
_context10.next = 3;
|
|
915
|
+
break;
|
|
916
|
+
}
|
|
917
|
+
return _context10.abrupt("return", offline);
|
|
918
|
+
case 3:
|
|
919
|
+
_context10.prev = 3;
|
|
920
|
+
_context10.next = 4;
|
|
921
|
+
return this._requestRouteFromGateway(terminalName);
|
|
922
|
+
case 4:
|
|
923
|
+
route = _context10.sent;
|
|
924
|
+
_context10.next = 7;
|
|
925
|
+
break;
|
|
926
|
+
case 5:
|
|
927
|
+
_context10.prev = 5;
|
|
928
|
+
_t2 = _context10["catch"](3);
|
|
929
|
+
// The gateway is unreachable or does not know the terminal. A stale
|
|
930
|
+
// persisted route is better than no transaction.
|
|
931
|
+
stale = this._readFromOfflineCache(terminalName, true);
|
|
932
|
+
if (!stale) {
|
|
933
|
+
_context10.next = 6;
|
|
934
|
+
break;
|
|
935
|
+
}
|
|
936
|
+
return _context10.abrupt("return", stale);
|
|
937
|
+
case 6:
|
|
938
|
+
throw _t2;
|
|
939
|
+
case 7:
|
|
940
|
+
ttl = new Date().getTime() + this.routeCacheTTL * 60000;
|
|
941
|
+
this._routeCache[key] = {
|
|
942
|
+
ttl: ttl,
|
|
943
|
+
route: route
|
|
944
|
+
};
|
|
945
|
+
this._updateOfflineCache(route, ttl);
|
|
946
|
+
return _context10.abrupt("return", route);
|
|
947
|
+
case 8:
|
|
948
|
+
case "end":
|
|
949
|
+
return _context10.stop();
|
|
950
|
+
}
|
|
951
|
+
}, _callee10, this, [[3, 5]]);
|
|
952
|
+
}));
|
|
953
|
+
function _resolveTerminalRoute(_x24) {
|
|
954
|
+
return _resolveTerminalRoute2.apply(this, arguments);
|
|
955
|
+
}
|
|
956
|
+
return _resolveTerminalRoute;
|
|
957
|
+
}()
|
|
958
|
+
}]);
|
|
959
|
+
}(); // StaxApiCredentials is the Stax bearer token used to construct a client. It is
|
|
960
|
+
// the only credential an integrator supplies; the BlockChyp gateway credentials
|
|
961
|
+
// are obtained and managed internally by the SDK.
|
|
962
|
+
var StaxApiCredentials = exports.StaxApiCredentials = /*#__PURE__*/(0, _createClass2["default"])(function StaxApiCredentials(bearerToken) {
|
|
963
|
+
(0, _classCallCheck2["default"])(this, StaxApiCredentials);
|
|
964
|
+
this.bearerToken = bearerToken;
|
|
965
|
+
}); // StaxPaymentsCredentials models the BlockChyp gateway credentials the SDK
|
|
966
|
+
// obtains by exchanging the bearer token. It is internal to the SDK.
|
|
967
|
+
var StaxPaymentsCredentials = exports.StaxPaymentsCredentials = /*#__PURE__*/(0, _createClass2["default"])(function StaxPaymentsCredentials(apiKey, bearerToken, signingKey) {
|
|
968
|
+
(0, _classCallCheck2["default"])(this, StaxPaymentsCredentials);
|
|
969
|
+
this.apiKey = apiKey;
|
|
970
|
+
this.bearerToken = bearerToken;
|
|
971
|
+
this.signingKey = signingKey;
|
|
972
|
+
});
|