simplepay-js-sdk 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -3
- package/dist/index.d.ts +47 -19
- package/dist/index.js +127 -68
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
- package/src/index.ts +8 -158
- package/src/oneTime.spec.ts +97 -0
- package/src/oneTime.ts +33 -0
- package/src/recurring.spec.ts +71 -0
- package/src/recurring.ts +77 -0
- package/src/types.ts +57 -12
- package/src/{index.spec.ts → utils.spec.ts} +6 -70
- package/src/utils.ts +142 -0
package/src/utils.ts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import crypto from 'crypto'
|
|
2
|
+
import { CURRENCIES, Currency, ISO8601DateString, SimplePayAPIResult, SimplePayRecurringRequestBody, SimplePayRecurringResponse, SimplePayRequestBody, SimplePayResponse, SimplePayResult, SimplePayTokenRequestBody, SimplePayTokenResponse } from "./types"
|
|
3
|
+
|
|
4
|
+
export const simplepayLogger = (...args: any[]) => {
|
|
5
|
+
if (process.env.SIMPLEPAY_LOGGER !== 'true') {
|
|
6
|
+
return
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
console.log('👉 ', ...args)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const getSimplePayConfig = (currency: Currency) => {
|
|
13
|
+
if (!CURRENCIES.includes(currency)) {
|
|
14
|
+
throw new Error(`Unsupported currency: ${currency}`)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const SIMPLEPAY_API_URL = 'https://secure.simplepay.hu/payment/v2'
|
|
18
|
+
const SIMPLEPAY_SANDBOX_URL = 'https://sandbox.simplepay.hu/payment/v2/start'
|
|
19
|
+
const SDK_VERSION = 'SimplePayV2.1_Rrd_0.6.1'
|
|
20
|
+
const MERCHANT_KEY = process.env[`SIMPLEPAY_MERCHANT_KEY_${currency}`]
|
|
21
|
+
const MERCHANT_ID = process.env[`SIMPLEPAY_MERCHANT_ID_${currency}`]
|
|
22
|
+
const API_URL = process.env.SIMPLEPAY_PRODUCTION === 'true' ? SIMPLEPAY_API_URL : SIMPLEPAY_SANDBOX_URL
|
|
23
|
+
const API_URL_RECURRING = process.env.SIMPLEPAY_PRODUCTION === 'true' ? SIMPLEPAY_API_URL : 'https://sandbox.simplepay.hu/payment/v2/dorecurring'
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
MERCHANT_KEY,
|
|
27
|
+
MERCHANT_ID,
|
|
28
|
+
API_URL,
|
|
29
|
+
API_URL_RECURRING,
|
|
30
|
+
SDK_VERSION
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// escaping slashes for the request body to prevent strange SimplePay API errors (eg Missing Signature)
|
|
35
|
+
export const prepareRequestBody = (body: any) =>
|
|
36
|
+
JSON.stringify(body).replace(/\//g, '\\/')
|
|
37
|
+
|
|
38
|
+
export const generateSignature = (body: string, merchantKey: string) => {
|
|
39
|
+
const hmac = crypto.createHmac('sha384', merchantKey.trim())
|
|
40
|
+
hmac.update(body, 'utf8')
|
|
41
|
+
return hmac.digest('base64')
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const checkSignature = (responseText: string, signature: string, merchantKey: string) =>
|
|
45
|
+
signature === generateSignature(responseText, merchantKey)
|
|
46
|
+
|
|
47
|
+
export const toISO8601DateString = (date: Date): ISO8601DateString => date.toISOString().replace(/\.\d{3}Z$/, '+00:00')
|
|
48
|
+
|
|
49
|
+
export const getCurrencyFromMerchantId = (merchantId: string) => {
|
|
50
|
+
const currency = Object.entries(process.env)
|
|
51
|
+
.find(([key, value]) =>
|
|
52
|
+
key.startsWith('SIMPLEPAY_MERCHANT_ID_') && value === merchantId
|
|
53
|
+
)?.[0]?.replace('SIMPLEPAY_MERCHANT_ID_', '') as Currency
|
|
54
|
+
if (!currency) {
|
|
55
|
+
throw new Error(`Merchant id not found in the environment: ${merchantId}`)
|
|
56
|
+
}
|
|
57
|
+
return currency
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const makeSimplePayRequest = async (apiUrl: string, requestBody: SimplePayRequestBody, merchantKey: string) => {
|
|
61
|
+
return makeRequest(apiUrl, requestBody, merchantKey, 'oneTime') as Promise<SimplePayResponse>
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const makeSimplePayRecurringRequest = async (apiUrl: string, requestBody: SimplePayRecurringRequestBody, merchantKey: string) => {
|
|
65
|
+
return makeRequest(apiUrl, requestBody, merchantKey, 'recurring') as Promise<SimplePayRecurringResponse>
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const makeSimplePayTokenRequest = async (apiUrl: string, requestBody: SimplePayTokenRequestBody, merchantKey: string) => {
|
|
69
|
+
return makeRequest(apiUrl, requestBody, merchantKey, 'token') as Promise<SimplePayTokenResponse>
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const makeRequest = async (apiUrl: string, requestBody: SimplePayRequestBody | SimplePayRecurringRequestBody | SimplePayTokenRequestBody, merchantKey: string, type: 'oneTime' | 'recurring' | 'token') => {
|
|
73
|
+
const bodyString = prepareRequestBody(requestBody)
|
|
74
|
+
const signature = generateSignature(bodyString, merchantKey)
|
|
75
|
+
simplepayLogger({ function: `SimplePay/makeRequest/${type}`, bodyString, signature })
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
const response = await fetch(apiUrl, {
|
|
79
|
+
method: 'POST',
|
|
80
|
+
headers: {
|
|
81
|
+
'Content-Type': 'application/json',
|
|
82
|
+
'Signature': signature,
|
|
83
|
+
},
|
|
84
|
+
body: bodyString,
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
simplepayLogger({ function: `SimplePay/makeRequest/${type}`, response })
|
|
88
|
+
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
throw new Error(`SimplePay API error: ${response.status}`)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const responseSignature = response.headers.get('Signature')
|
|
94
|
+
simplepayLogger({ function: `SimplePay/makeRequest/${type}`, responseSignature })
|
|
95
|
+
if (!responseSignature) {
|
|
96
|
+
throw new Error('Missing response signature')
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const responseText = await response.text()
|
|
100
|
+
const responseJSON = JSON.parse(responseText) as { errorCodes?: string[] }
|
|
101
|
+
simplepayLogger({ function: `SimplePay/makeRequest/${type}`, responseText, responseJSON })
|
|
102
|
+
|
|
103
|
+
if (responseJSON.errorCodes) {
|
|
104
|
+
throw new Error(`SimplePay API error: ${responseJSON.errorCodes}`)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!checkSignature(responseText, responseSignature, merchantKey)) {
|
|
108
|
+
throw new Error('Invalid response signature')
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return responseJSON
|
|
112
|
+
|
|
113
|
+
} catch (error) {
|
|
114
|
+
throw error
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export const getPaymentResponse = (r: string, signature: string) => {
|
|
119
|
+
simplepayLogger({ function: 'SimplePay/getPaymentResponse', r, signature })
|
|
120
|
+
signature = decodeURIComponent(signature)
|
|
121
|
+
const rDecoded = Buffer.from(r, 'base64').toString('utf-8')
|
|
122
|
+
const rDecodedJSON = JSON.parse(rDecoded) as SimplePayAPIResult
|
|
123
|
+
const currency = getCurrencyFromMerchantId(rDecodedJSON.m)
|
|
124
|
+
const { MERCHANT_KEY } = getSimplePayConfig(currency as Currency)
|
|
125
|
+
|
|
126
|
+
if (!checkSignature(rDecoded, signature, MERCHANT_KEY || '')) {
|
|
127
|
+
simplepayLogger({ function: 'SimplePay/getPaymentResponse', rDecoded, signature })
|
|
128
|
+
throw new Error('Invalid response signature')
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const responseJson = JSON.parse(rDecoded)
|
|
132
|
+
const response: SimplePayResult = {
|
|
133
|
+
responseCode: responseJson.r,
|
|
134
|
+
transactionId: responseJson.t,
|
|
135
|
+
event: responseJson.e,
|
|
136
|
+
merchantId: responseJson.m,
|
|
137
|
+
orderRef: responseJson.o,
|
|
138
|
+
tokens: responseJson.tokens,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return response
|
|
142
|
+
}
|