@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
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
var { hmac } = require('@noble/hashes/hmac')
|
|
2
|
+
var { sha256 } = require('@noble/hashes/sha256')
|
|
3
|
+
var { randomBytes, bytesToHex, utf8ToBytes } = require('@noble/hashes/utils')
|
|
4
|
+
var { p256 } = require('@noble/curves/nist')
|
|
5
|
+
var moment = require('moment')
|
|
6
|
+
var base32 = require('base32')
|
|
7
|
+
var aesjs = require('aes-js')
|
|
8
|
+
|
|
9
|
+
export class BlockChypCrypto {
|
|
10
|
+
generateGatewayHeaders (creds) {
|
|
11
|
+
let nonce = this.generateNonce()
|
|
12
|
+
let ts = this.generateIsoTimestamp()
|
|
13
|
+
let toSign = creds.apiKey + creds.bearerToken + ts + nonce
|
|
14
|
+
let key = Buffer.from(creds.signingKey, 'hex')
|
|
15
|
+
let mac = hmac(sha256, key, utf8ToBytes(toSign))
|
|
16
|
+
let sig = bytesToHex(mac)
|
|
17
|
+
|
|
18
|
+
var results = {
|
|
19
|
+
'Nonce': nonce,
|
|
20
|
+
'Timestamp': ts,
|
|
21
|
+
'Authorization': 'Dual ' + creds.bearerToken + ':' + creds.apiKey + ':' + sig
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return results
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
encrypt (hexKey, plainText) {
|
|
28
|
+
let key = Buffer.from(hexKey, 'hex').slice(0, 32)
|
|
29
|
+
let keyArr = [...key]
|
|
30
|
+
|
|
31
|
+
let iv = randomBytes(16)
|
|
32
|
+
let ivArr = [...iv]
|
|
33
|
+
|
|
34
|
+
let aesCbc = new aesjs.ModeOfOperation.cbc(keyArr, ivArr)
|
|
35
|
+
let plainBytes = aesjs.padding.pkcs7.pad(aesjs.utils.utf8.toBytes(plainText))
|
|
36
|
+
let encryptedBytes = aesCbc.encrypt(plainBytes)
|
|
37
|
+
|
|
38
|
+
return bytesToHex(iv) + aesjs.utils.hex.fromBytes(encryptedBytes)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
sha256Hash (msg) {
|
|
42
|
+
let msgBytes = Buffer.from(msg, 'hex')
|
|
43
|
+
return bytesToHex(sha256(msgBytes))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
validateSignature (publicKey, msg, sig) {
|
|
47
|
+
// Hash the message
|
|
48
|
+
let msgHash = this.sha256Hash(msg)
|
|
49
|
+
let msgHashBytes = Buffer.from(msgHash, 'hex')
|
|
50
|
+
|
|
51
|
+
// Convert hex string coordinates to BigInt and create point
|
|
52
|
+
let pubKeyPoint = p256.ProjectivePoint.fromAffine({
|
|
53
|
+
x: BigInt('0x' + publicKey.x),
|
|
54
|
+
y: BigInt('0x' + publicKey.y)
|
|
55
|
+
})
|
|
56
|
+
let pubKeyBytes = pubKeyPoint.toRawBytes(false)
|
|
57
|
+
|
|
58
|
+
// Create signature from r, s components
|
|
59
|
+
let signature = new p256.Signature(
|
|
60
|
+
BigInt('0x' + sig.r),
|
|
61
|
+
BigInt('0x' + sig.s)
|
|
62
|
+
)
|
|
63
|
+
let sigBytes = signature.toCompactRawBytes()
|
|
64
|
+
|
|
65
|
+
// Verify signature
|
|
66
|
+
return p256.verify(sigBytes, msgHashBytes, pubKeyBytes, { prehash: true })
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
decrypt (hexKey, cipherText) {
|
|
70
|
+
let key = Buffer.from(hexKey, 'hex').slice(0, 32)
|
|
71
|
+
let keyArr = [...key]
|
|
72
|
+
|
|
73
|
+
let cipherBytes = Buffer.from(cipherText, 'hex')
|
|
74
|
+
let iv = cipherBytes.slice(0, 16)
|
|
75
|
+
|
|
76
|
+
var aesCbc = new aesjs.ModeOfOperation.cbc(keyArr, iv)
|
|
77
|
+
|
|
78
|
+
let cipher = cipherBytes.slice(16, cipherBytes.length)
|
|
79
|
+
let cipherArr = [...cipher]
|
|
80
|
+
let decryptedBytes = aesjs.padding.pkcs7.strip(aesCbc.decrypt(cipherArr))
|
|
81
|
+
|
|
82
|
+
return aesjs.utils.utf8.fromBytes(decryptedBytes)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
generateNonce () {
|
|
86
|
+
return base32.encode(randomBytes(32)).toUpperCase()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
generateIsoTimestamp () {
|
|
90
|
+
return moment().utc().format('YYYY-MM-DDTHH:mm:ss') + 'Z'
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
var CryptoUtils = new BlockChypCrypto()
|
|
95
|
+
export default CryptoUtils
|
package/src/global.js
ADDED
package/src/mappers.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2019-2026 BlockChyp, Inc. All rights reserved. Use of this code is governed
|
|
3
|
+
* by a license that can be found in the LICENSE file.
|
|
4
|
+
*
|
|
5
|
+
* This file was generated automatically by the BlockChyp SDK Generator. Changes to this
|
|
6
|
+
* file will be lost every time the code is regenerated.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Maps a Stax Payments charge or preauth request onto the BlockChyp wire model. Fields not
|
|
11
|
+
* listed here carry the same name on both sides and are matched by name; the generated
|
|
12
|
+
* mapper spells every one of them out.
|
|
13
|
+
*/
|
|
14
|
+
export function authRequestMapper (src) {
|
|
15
|
+
let dst = {}
|
|
16
|
+
|
|
17
|
+
dst.tipAmount = src.tipAmount
|
|
18
|
+
dst.taxAmount = src.taxAmount
|
|
19
|
+
dst.terminalName = src.terminalName
|
|
20
|
+
dst.amount = src.amount
|
|
21
|
+
dst.currencyCode = src.currencyCode
|
|
22
|
+
dst.promptForTip = src.promptForTip
|
|
23
|
+
dst.test = src.test
|
|
24
|
+
dst.enroll = src.enroll
|
|
25
|
+
dst.externalPartnerMetadata = src.externalPartnerMetadata
|
|
26
|
+
/**
|
|
27
|
+
* The caller's own reference rides out as externalTransactionRef. BlockChyp's own
|
|
28
|
+
* transactionRef is a different thing: it drives duplicate detection and transaction
|
|
29
|
+
* recall, and carries the Stax transaction id.
|
|
30
|
+
*/
|
|
31
|
+
dst.externalTransactionRef = src.transactionRef
|
|
32
|
+
|
|
33
|
+
return dst
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Maps a BlockChyp charge or preauth response onto the Stax Payments model. Fields not
|
|
38
|
+
* listed here are matched by name.
|
|
39
|
+
*/
|
|
40
|
+
export function authResponseMapper (src) {
|
|
41
|
+
let dst = {}
|
|
42
|
+
|
|
43
|
+
dst.success = src.success
|
|
44
|
+
dst.error = src.error
|
|
45
|
+
dst.responseDescription = src.responseDescription
|
|
46
|
+
/**
|
|
47
|
+
* The Stax transaction id comes back in the transaction ref. BlockChyp's
|
|
48
|
+
* transactionId is BlockChyp's own id and is deliberately not surfaced.
|
|
49
|
+
*/
|
|
50
|
+
dst.transactionId = src.transactionRef
|
|
51
|
+
dst.approved = src.approved
|
|
52
|
+
dst.authCode = src.authCode
|
|
53
|
+
dst.requestedAmount = src.requestedAmount
|
|
54
|
+
dst.authorizedAmount = src.authorizedAmount
|
|
55
|
+
dst.currencyCode = src.currencyCode
|
|
56
|
+
dst.entryMethod = src.entryMethod
|
|
57
|
+
dst.maskedPan = src.maskedPan
|
|
58
|
+
dst.network = src.network
|
|
59
|
+
dst.timestamp = src.timestamp
|
|
60
|
+
dst.status = src.status
|
|
61
|
+
dst.cardMetadata = src.cardMetadata
|
|
62
|
+
dst.receiptSuggestions = src.receiptSuggestions
|
|
63
|
+
dst.test = src.test
|
|
64
|
+
/**
|
|
65
|
+
* The caller's own reference comes back from externalTransactionRef, not from
|
|
66
|
+
* BlockChyp's transactionRef, which carries the Stax transaction id and is surfaced
|
|
67
|
+
* as transactionId.
|
|
68
|
+
*/
|
|
69
|
+
dst.transactionRef = src.externalTransactionRef
|
|
70
|
+
|
|
71
|
+
return dst
|
|
72
|
+
}
|
package/src/payments.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2019-2026 BlockChyp, Inc. All rights reserved. Use of this code is governed
|
|
3
|
+
* by a license that can be found in the LICENSE file.
|
|
4
|
+
*
|
|
5
|
+
* This file was generated automatically by the BlockChyp SDK Generator. Changes to this
|
|
6
|
+
* file will be lost every time the code is regenerated.
|
|
7
|
+
*/
|
|
8
|
+
import * as Mappers from './mappers'
|
|
9
|
+
|
|
10
|
+
// PaymentsClient exposes the Payment Endpoints for the Stax Payments
|
|
11
|
+
// API. It is constructed by the root StaxPaymentsClient with a shared transport
|
|
12
|
+
// (StaxPaymentsBaseClient), so every namespace shares one transient-credential
|
|
13
|
+
// cache rather than exchanging credentials per namespace.
|
|
14
|
+
export class PaymentsClient {
|
|
15
|
+
constructor (base) {
|
|
16
|
+
this.base = base
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Executes a standard direct preauth and capture.
|
|
21
|
+
*/
|
|
22
|
+
// Takes and returns the Stax Payments models. The BlockChyp wire models are
|
|
23
|
+
// an implementation detail: the request is mapped on the way out and the
|
|
24
|
+
// reply on the way back.
|
|
25
|
+
async charge (request) {
|
|
26
|
+
let response = await this.base.routeTransaction('post', Mappers.authRequestMapper(request), '/api/charge', '/api/charge')
|
|
27
|
+
|
|
28
|
+
return Mappers.authResponseMapper(response.data)
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Executes a preauthorization intended to be captured later.
|
|
32
|
+
*/
|
|
33
|
+
// Takes and returns the Stax Payments models. The BlockChyp wire models are
|
|
34
|
+
// an implementation detail: the request is mapped on the way out and the
|
|
35
|
+
// reply on the way back.
|
|
36
|
+
async preauth (request) {
|
|
37
|
+
let response = await this.base.routeTransaction('post', Mappers.authRequestMapper(request), '/api/preauth', '/api/preauth')
|
|
38
|
+
|
|
39
|
+
return Mappers.authResponseMapper(response.data)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2019-2026 BlockChyp, Inc. All rights reserved. Use of this code is governed
|
|
3
|
+
* by a license that can be found in the LICENSE file.
|
|
4
|
+
*
|
|
5
|
+
* This file was generated automatically by the BlockChyp SDK Generator. Changes to this
|
|
6
|
+
* file will be lost every time the code is regenerated.
|
|
7
|
+
*/
|
|
8
|
+
import {StaxPaymentsBaseClient} from './client'
|
|
9
|
+
import {PaymentsClient} from './payments'
|
|
10
|
+
import {TerminalsClient} from './terminals'
|
|
11
|
+
|
|
12
|
+
// StaxPaymentsClient is the root Stax Payments client. It builds the shared
|
|
13
|
+
// transport (StaxPaymentsBaseClient) once and exposes each API namespace
|
|
14
|
+
// (e.g. payments, terminals) as a property, so a single set of transient
|
|
15
|
+
// credentials is fetched, cached, and refreshed across every namespace rather
|
|
16
|
+
// than per namespace.
|
|
17
|
+
export class StaxPaymentsClient {
|
|
18
|
+
// Construct the root client with your Stax bearer token.
|
|
19
|
+
constructor (creds, opts = {}) {
|
|
20
|
+
this.base = new StaxPaymentsBaseClient(creds, opts)
|
|
21
|
+
this.payments = new PaymentsClient(this.base)
|
|
22
|
+
this.terminals = new TerminalsClient(this.base)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// heartbeat checks connectivity with the Stax Payments gateway.
|
|
26
|
+
heartbeat () {
|
|
27
|
+
return this.base.heartbeat()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Host configuration is shared across every namespace.
|
|
31
|
+
setGatewayHost (host) {
|
|
32
|
+
this.base.setGatewayHost(host)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
getGatewayHost () {
|
|
36
|
+
return this.base.getGatewayHost()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
setTestGatewayHost (host) {
|
|
40
|
+
this.base.setTestGatewayHost(host)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
setDashboardHost (host) {
|
|
44
|
+
this.base.setDashboardHost(host)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
getDashboardHost () {
|
|
48
|
+
return this.base.getDashboardHost()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
setCoreHost (host) {
|
|
52
|
+
this.base.setCoreHost(host)
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/terminals.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2019-2026 BlockChyp, Inc. All rights reserved. Use of this code is governed
|
|
3
|
+
* by a license that can be found in the LICENSE file.
|
|
4
|
+
*
|
|
5
|
+
* This file was generated automatically by the BlockChyp SDK Generator. Changes to this
|
|
6
|
+
* file will be lost every time the code is regenerated.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// TerminalsClient exposes the Terminal Management Endpoints for the Stax Payments
|
|
10
|
+
// API. It is constructed by the root StaxPaymentsClient with a shared transport
|
|
11
|
+
// (StaxPaymentsBaseClient), so every namespace shares one transient-credential
|
|
12
|
+
// cache rather than exchanging credentials per namespace.
|
|
13
|
+
export class TerminalsClient {
|
|
14
|
+
constructor (base) {
|
|
15
|
+
this.base = base
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Tests connectivity with a payment terminal.
|
|
20
|
+
*/
|
|
21
|
+
async ping (request) {
|
|
22
|
+
return this.base.routeTransaction('post', request, '/api/test', '/api/terminal-test')
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Returns routing and location data for a payment terminal.
|
|
26
|
+
*/
|
|
27
|
+
locate (request) {
|
|
28
|
+
return this.base._gatewayRequest('post', '/api/terminal-locate', request)
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Clears the line item display and any in progress transaction.
|
|
32
|
+
*/
|
|
33
|
+
async clear (request) {
|
|
34
|
+
return this.base.routeTransaction('post', request, '/api/clear', '/api/terminal-clear')
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Returns the current status of a terminal.
|
|
38
|
+
*/
|
|
39
|
+
async terminalStatus (request) {
|
|
40
|
+
return this.base.routeTransaction('post', request, '/api/terminal-status', '/api/terminal-status')
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Captures and returns a signature.
|
|
44
|
+
*/
|
|
45
|
+
async captureSignature (request) {
|
|
46
|
+
return this.base.routeTransaction('post', request, '/api/capture-signature', '/api/capture-signature')
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Displays a new transaction on the terminal.
|
|
50
|
+
*/
|
|
51
|
+
async newTransactionDisplay (request) {
|
|
52
|
+
return this.base.routeTransaction('post', request, '/api/txdisplay', '/api/terminal-txdisplay')
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Appends items to an existing transaction display. Subtotal, Tax, and Total are
|
|
56
|
+
* overwritten by the request. Items with the same description are combined into
|
|
57
|
+
* groups.
|
|
58
|
+
*/
|
|
59
|
+
async updateTransactionDisplay (request) {
|
|
60
|
+
return this.base.routeTransaction('put', request, '/api/txdisplay', '/api/terminal-txdisplay')
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Displays a short message on the terminal.
|
|
64
|
+
*/
|
|
65
|
+
async message (request) {
|
|
66
|
+
return this.base.routeTransaction('post', request, '/api/message', '/api/message')
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Asks the consumer a yes/no question.
|
|
70
|
+
*/
|
|
71
|
+
async booleanPrompt (request) {
|
|
72
|
+
return this.base.routeTransaction('post', request, '/api/boolean-prompt', '/api/boolean-prompt')
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Asks the consumer a text based question.
|
|
76
|
+
*/
|
|
77
|
+
async textPrompt (request) {
|
|
78
|
+
return this.base.routeTransaction('post', request, '/api/text-prompt', '/api/text-prompt')
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Returns all terminals associated with the merchant account.
|
|
82
|
+
*/
|
|
83
|
+
terminals (request) {
|
|
84
|
+
return this.base._dashboardRequest('get', '/api/terminals', request)
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Deactivates a terminal.
|
|
88
|
+
*/
|
|
89
|
+
deactivateTerminal (request) {
|
|
90
|
+
return this.base._dashboardRequest('delete', '/api/terminal/' + request.terminalId, request)
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Activates a terminal.
|
|
94
|
+
*/
|
|
95
|
+
async activateTerminal (request) {
|
|
96
|
+
return this.base._coreRequest('post', '/terminals', request)
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Reboot a payment terminal.
|
|
100
|
+
*/
|
|
101
|
+
async reboot (request) {
|
|
102
|
+
return this.base.routeTransaction('post', request, '/api/reboot', '/api/terminal-reboot')
|
|
103
|
+
}
|
|
104
|
+
}
|