simplepay-js-sdk 0.1.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 ADDED
@@ -0,0 +1,38 @@
1
+ # SimplePay Node.js Utility
2
+
3
+ A lightweight utility for integrating SimplePay payments in Node.js applications.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install simplepay-js-sdk
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { startPayment, getPaymentResponse } from 'simplepay-nodejs-utility'
15
+
16
+ // Start a payment
17
+ const paymentResponse = await startPayment({
18
+ orderRef: 'unique-order-reference',
19
+ total: 1000,
20
+ customerEmail: 'customer@example.com',
21
+ })
22
+
23
+ // Handle payment response
24
+ const result = getPaymentResponse(encodedResponse, signature)
25
+ ```
26
+
27
+ ## Configuration
28
+
29
+ Set the following environment variables:
30
+
31
+ - `SIMPLEPAY_MERCHANT_KEY`
32
+ - `SIMPLEPAY_MERCHANT_ID`
33
+ - `SIMPLEPAY_PRODUCTION`
34
+ - `SIMPLEPAY_REDIRECT_URL`
35
+
36
+ ## License
37
+
38
+ MIT
@@ -0,0 +1,12 @@
1
+ import { PaymentData, SimplePayResponse } from './types';
2
+ declare const generateSignature: (body: string, merchantKey: string) => string;
3
+ declare const checkSignature: (responseText: string, signature: string, merchantKey: string) => boolean;
4
+ declare const startPayment: (paymentData: PaymentData) => Promise<SimplePayResponse>;
5
+ declare const getPaymentResponse: (r: string, signature: string) => {
6
+ responseCode: number;
7
+ transactionId: string;
8
+ event: "success" | "fail" | "timeout" | "cancel";
9
+ merchantId: string;
10
+ orderId: string;
11
+ };
12
+ export { startPayment, generateSignature, checkSignature, getPaymentResponse };
package/dist/index.js ADDED
@@ -0,0 +1,99 @@
1
+ import crypto from 'crypto';
2
+ // Existing interfaces remain the same
3
+ const simplepayLogger = (...args) => {
4
+ if (process.env.SIMPLEPAY_LOGGER !== 'true') {
5
+ return;
6
+ }
7
+ console.log(...args);
8
+ };
9
+ const generateSignature = (body, merchantKey) => {
10
+ const hmac = crypto.createHmac('sha384', merchantKey.trim());
11
+ hmac.update(body, 'utf8');
12
+ return hmac.digest('base64');
13
+ };
14
+ const checkSignature = (responseText, signature, merchantKey) => signature === generateSignature(responseText, merchantKey);
15
+ // escaping slashes for the request body to prevent strange SimplePay API errors (eg Missing Signature)
16
+ const prepareRequestBody = (body) => JSON.stringify(body).replace(/\//g, '\\/');
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.1.0';
20
+ const startPayment = async (paymentData) => {
21
+ const MERCHANT_KEY = process.env.SIMPLEPAY_MERCHANT_KEY;
22
+ const MERCHANT_ID = process.env.SIMPLEPAY_MERCHANT_ID;
23
+ const API_URL = process.env.SIMPLEPAY_PRODUCTION === 'true' ? SIMPLEPAY_API_URL : SIMPLEPAY_SANDBOX_URL;
24
+ simplepayLogger({ MERCHANT_KEY, MERCHANT_ID, API_URL });
25
+ if (!MERCHANT_KEY || !MERCHANT_ID) {
26
+ throw new Error('Missing SimplePay configuration');
27
+ }
28
+ const requestBody = {
29
+ salt: crypto.randomBytes(16).toString('hex'),
30
+ merchant: MERCHANT_ID,
31
+ orderRef: paymentData.orderRef,
32
+ currency: paymentData.currency || 'HUF',
33
+ customerEmail: paymentData.customerEmail,
34
+ language: paymentData.language || 'HU',
35
+ sdkVersion: SDK_VERSION,
36
+ methods: ['CARD'],
37
+ total: String(paymentData.total),
38
+ timeout: new Date(Date.now() + 30 * 60 * 1000)
39
+ .toISOString()
40
+ .replace(/\.\d{3}Z$/, '+00:00'),
41
+ url: process.env.SIMPLEPAY_REDIRECT_URL || 'http://url.to.redirect',
42
+ invoice: paymentData.invoice,
43
+ };
44
+ const bodyString = prepareRequestBody(requestBody);
45
+ const signature = generateSignature(bodyString, MERCHANT_KEY);
46
+ simplepayLogger({ bodyString, signature });
47
+ try {
48
+ const response = await fetch(API_URL, {
49
+ method: 'POST',
50
+ headers: {
51
+ 'Content-Type': 'application/json',
52
+ 'Signature': signature,
53
+ },
54
+ body: bodyString,
55
+ });
56
+ simplepayLogger({ response });
57
+ if (!response.ok) {
58
+ throw new Error(`SimplePay API error: ${response.status}`);
59
+ }
60
+ const responseSignature = response.headers.get('Signature');
61
+ simplepayLogger({ responseSignature });
62
+ if (!responseSignature) {
63
+ throw new Error('Missing response signature');
64
+ }
65
+ const responseText = await response.text();
66
+ const responseJSON = JSON.parse(responseText);
67
+ simplepayLogger({ responseText, responseJSON });
68
+ if (responseJSON.errorCodes) {
69
+ throw new Error(`SimplePay API error: ${responseJSON.errorCodes}`);
70
+ }
71
+ if (!checkSignature(responseText, responseSignature, MERCHANT_KEY)) {
72
+ throw new Error('Invalid response signature');
73
+ }
74
+ return responseJSON;
75
+ }
76
+ catch (error) {
77
+ console.error('SimplePay payment start error:', error);
78
+ throw error;
79
+ }
80
+ };
81
+ const getPaymentResponse = (r, signature) => {
82
+ // Note: Replaced atob with Buffer for ESM
83
+ const rDecoded = Buffer.from(r, 'base64').toString('utf-8');
84
+ if (!checkSignature(rDecoded, signature, process.env.SIMPLEPAY_MERCHANT_KEY || '')) {
85
+ simplepayLogger({ rDecoded, signature });
86
+ throw new Error('Invalid response signature');
87
+ }
88
+ const responseJson = JSON.parse(rDecoded);
89
+ const response = {
90
+ responseCode: responseJson.r,
91
+ transactionId: responseJson.t,
92
+ event: responseJson.e,
93
+ merchantId: responseJson.m,
94
+ orderId: responseJson.o,
95
+ };
96
+ return response;
97
+ };
98
+ export { startPayment, generateSignature, checkSignature, getPaymentResponse };
99
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ interface PaymentData {
2
+ orderRef: string;
3
+ total: number | string;
4
+ customerEmail: string;
5
+ currency?: string;
6
+ language?: string;
7
+ invoice?: {
8
+ name: string;
9
+ country: string;
10
+ state: string;
11
+ city: string;
12
+ zip: string;
13
+ address: string;
14
+ address2?: string;
15
+ phone?: string;
16
+ };
17
+ }
18
+ interface SimplePayRequestBody extends Omit<PaymentData, 'total'> {
19
+ total: string;
20
+ salt: string;
21
+ merchant: string;
22
+ sdkVersion: string;
23
+ methods: ['CARD'];
24
+ timeout: string;
25
+ url: string;
26
+ }
27
+ interface SimplePayResponse {
28
+ salt: string;
29
+ merchant: string;
30
+ orderRef: string;
31
+ currency: string;
32
+ transactionId: string;
33
+ timeout: string;
34
+ total: string;
35
+ paymentUrl: string;
36
+ errorCodes?: string[];
37
+ }
38
+ interface SimplepayResult {
39
+ r: number;
40
+ t: string;
41
+ e: 'success' | 'fail' | 'timeout' | 'cancel';
42
+ m: string;
43
+ o: string;
44
+ }
45
+ export { PaymentData, SimplePayRequestBody, SimplePayResponse, SimplepayResult };
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "simplepay-js-sdk",
3
+ "version": "0.1.0",
4
+ "description": "A Node.js utility for SimplePay payment integration",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/rrd108/simplepay-js-sdk"
8
+ },
9
+ "type": "module",
10
+ "main": "dist/index.js",
11
+ "exports": {
12
+ ".": "./dist/index.js",
13
+ "./types": "./dist/types.js"
14
+ },
15
+ "types": "dist/index.d.ts",
16
+ "files": [
17
+ "dist",
18
+ "src"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsc",
22
+ "prepare": "npm run build",
23
+ "test": "vitest"
24
+ },
25
+ "keywords": [
26
+ "simplepay",
27
+ "payment",
28
+ "nodejs",
29
+ "typescript"
30
+ ],
31
+ "author": "Radharadhya Dasa",
32
+ "license": "MIT",
33
+ "devDependencies": {
34
+ "@types/node": "^20.0.0",
35
+ "typescript": "^5.0.0",
36
+ "vitest": "^2.1.6"
37
+ },
38
+ "engines": {
39
+ "node": ">=18.0.0"
40
+ }
41
+ }
@@ -0,0 +1,51 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { checkSignature, generateSignature } from './index'
3
+
4
+ describe('generateSignature', () => {
5
+ it('should generate correct signature for sample payload from documentation', () => {
6
+ const merchantKey = 'FxDa5w314kLlNseq2sKuVwaqZshZT5d6'
7
+ const body = {
8
+ salt: 'c1ca1d0e9fc2323b3dda7cf145e36f5e',
9
+ merchant: 'PUBLICTESTHUF',
10
+ orderRef: '101010516348232058105',
11
+ currency: 'HUF',
12
+ customerEmail: 'sdk_test@otpmobil.com',
13
+ language: 'HU',
14
+ sdkVersion: 'SimplePayV2.1_Payment_PHP_SDK_2.0.7_190701:dd236896400d7463677a82a47f53e36e',
15
+ methods: ['CARD'],
16
+ total: '25',
17
+ timeout: '2021-10-30T12:30:11+00:00',
18
+ url: 'https://sdk.simplepay.hu/back.php',
19
+ }
20
+
21
+ let bodyString = JSON.stringify(body)
22
+ // after stringify we should insert backslashes for the url
23
+ bodyString = bodyString.replace(/\//g, '\\/')
24
+
25
+ const result = generateSignature(bodyString, merchantKey)
26
+
27
+ const expectedSignature = 'gcDJ8J7TyT1rC/Ygj/8CihXaLwniMWRav09QSEMQUnv5TbYaEDvQAuBE1mW3plvZ'
28
+ expect(result).toBe(expectedSignature)
29
+ })
30
+ })
31
+
32
+
33
+ describe('checkSignature', () => {
34
+ it('should generate correct signature for the response', () => {
35
+ const merchantKey = 'P085602'
36
+ const response = {
37
+ transactionId: '504226393',
38
+ orderRef: 'ORDER124',
39
+ merchant: merchantKey,
40
+ timeout: '2024-11-29T13:29:17+01:00',
41
+ total: '1000',
42
+ paymentUrl: 'https://sb-checkout.simplepay.hu/trx/cJZs3UUc48FlGu7Mfa1M0tcTWO53oA5RxS0OUMPqA17Fe3HGBr',
43
+ currency: 'HUF',
44
+ salt: 'R0ZBm2gdCXuTmxpOkqB4s0aAhZxZwSWG'
45
+ }
46
+
47
+ const expectedSignature = 'W98O/EdHobsWJTw2U1xUuUWXtCaJnTnzq5Na8ddCKE4gm2IW7vro33tGAW55YPf6'
48
+ const result = checkSignature(JSON.stringify(response).replace(/\//g, '\\/'), expectedSignature, merchantKey)
49
+ expect(result).toBeTruthy()
50
+ })
51
+ })
package/src/index.ts ADDED
@@ -0,0 +1,124 @@
1
+ import crypto from 'crypto'
2
+ import { PaymentData, SimplePayRequestBody, SimplePayResponse, SimplepayResult } from './types'
3
+
4
+ // Existing interfaces remain the same
5
+
6
+ const simplepayLogger = (...args: any[]) => {
7
+ if (process.env.SIMPLEPAY_LOGGER !== 'true') {
8
+ return
9
+ }
10
+ console.log(...args)
11
+ }
12
+
13
+ const generateSignature = (body: string, merchantKey: string) => {
14
+ const hmac = crypto.createHmac('sha384', merchantKey.trim())
15
+ hmac.update(body, 'utf8')
16
+ return hmac.digest('base64')
17
+ }
18
+
19
+ const checkSignature = (responseText: string, signature: string, merchantKey: string) =>
20
+ signature === generateSignature(responseText, merchantKey)
21
+
22
+ // escaping slashes for the request body to prevent strange SimplePay API errors (eg Missing Signature)
23
+ const prepareRequestBody = (body: SimplePayRequestBody) =>
24
+ JSON.stringify(body).replace(/\//g, '\\/')
25
+
26
+ const SIMPLEPAY_API_URL = 'https://secure.simplepay.hu/payment/v2'
27
+ const SIMPLEPAY_SANDBOX_URL = 'https://sandbox.simplepay.hu/payment/v2/start'
28
+ const SDK_VERSION = 'SimplePayV2.1_Rrd_0.1.0'
29
+
30
+ const startPayment = async (paymentData: PaymentData) => {
31
+ const MERCHANT_KEY = process.env.SIMPLEPAY_MERCHANT_KEY
32
+ const MERCHANT_ID = process.env.SIMPLEPAY_MERCHANT_ID
33
+ const API_URL = process.env.SIMPLEPAY_PRODUCTION === 'true' ? SIMPLEPAY_API_URL : SIMPLEPAY_SANDBOX_URL
34
+ simplepayLogger({ MERCHANT_KEY, MERCHANT_ID, API_URL })
35
+
36
+ if (!MERCHANT_KEY || !MERCHANT_ID) {
37
+ throw new Error('Missing SimplePay configuration')
38
+ }
39
+
40
+ const requestBody: SimplePayRequestBody = {
41
+ salt: crypto.randomBytes(16).toString('hex'),
42
+ merchant: MERCHANT_ID,
43
+ orderRef: paymentData.orderRef,
44
+ currency: paymentData.currency || 'HUF',
45
+ customerEmail: paymentData.customerEmail,
46
+ language: paymentData.language || 'HU',
47
+ sdkVersion: SDK_VERSION,
48
+ methods: ['CARD'],
49
+ total: String(paymentData.total),
50
+ timeout: new Date(Date.now() + 30 * 60 * 1000)
51
+ .toISOString()
52
+ .replace(/\.\d{3}Z$/, '+00:00'),
53
+ url: process.env.SIMPLEPAY_REDIRECT_URL || 'http://url.to.redirect',
54
+ invoice: paymentData.invoice,
55
+ }
56
+
57
+ const bodyString = prepareRequestBody(requestBody)
58
+ const signature = generateSignature(bodyString, MERCHANT_KEY)
59
+ simplepayLogger({ bodyString, signature })
60
+
61
+ try {
62
+ const response = await fetch(API_URL, {
63
+ method: 'POST',
64
+ headers: {
65
+ 'Content-Type': 'application/json',
66
+ 'Signature': signature,
67
+ },
68
+ body: bodyString,
69
+ })
70
+
71
+ simplepayLogger({ response })
72
+
73
+ if (!response.ok) {
74
+ throw new Error(`SimplePay API error: ${response.status}`)
75
+ }
76
+
77
+ const responseSignature = response.headers.get('Signature')
78
+ simplepayLogger({ responseSignature })
79
+ if (!responseSignature) {
80
+ throw new Error('Missing response signature')
81
+ }
82
+
83
+ const responseText = await response.text()
84
+ const responseJSON = JSON.parse(responseText) as SimplePayResponse
85
+ simplepayLogger({ responseText, responseJSON })
86
+
87
+ if (responseJSON.errorCodes) {
88
+ throw new Error(`SimplePay API error: ${responseJSON.errorCodes}`)
89
+ }
90
+
91
+ if (!checkSignature(responseText, responseSignature, MERCHANT_KEY)) {
92
+ throw new Error('Invalid response signature')
93
+ }
94
+
95
+ return responseJSON
96
+
97
+ } catch (error) {
98
+ console.error('SimplePay payment start error:', error)
99
+ throw error
100
+ }
101
+ }
102
+
103
+ const getPaymentResponse = (r: string, signature: string) => {
104
+ // Note: Replaced atob with Buffer for ESM
105
+ const rDecoded = Buffer.from(r, 'base64').toString('utf-8')
106
+
107
+ if (!checkSignature(rDecoded, signature, process.env.SIMPLEPAY_MERCHANT_KEY || '')) {
108
+ simplepayLogger({ rDecoded, signature })
109
+ throw new Error('Invalid response signature')
110
+ }
111
+
112
+ const responseJson: SimplepayResult = JSON.parse(rDecoded)
113
+ const response = {
114
+ responseCode: responseJson.r,
115
+ transactionId: responseJson.t,
116
+ event: responseJson.e,
117
+ merchantId: responseJson.m,
118
+ orderId: responseJson.o,
119
+ }
120
+
121
+ return response
122
+ }
123
+
124
+ export { startPayment, generateSignature, checkSignature, getPaymentResponse }
package/src/types.ts ADDED
@@ -0,0 +1,49 @@
1
+ interface PaymentData {
2
+ orderRef: string
3
+ total: number | string
4
+ customerEmail: string
5
+ currency?: string
6
+ language?: string
7
+ invoice?: {
8
+ name: string
9
+ country: string
10
+ state: string
11
+ city: string
12
+ zip: string
13
+ address: string
14
+ address2?: string
15
+ phone?: string
16
+ }
17
+ }
18
+
19
+ interface SimplePayRequestBody extends Omit<PaymentData, 'total'> {
20
+ total: string
21
+ salt: string
22
+ merchant: string
23
+ sdkVersion: string
24
+ methods: ['CARD']
25
+ timeout: string
26
+ url: string
27
+ }
28
+
29
+ interface SimplePayResponse {
30
+ salt: string
31
+ merchant: string
32
+ orderRef: string
33
+ currency: string
34
+ transactionId: string
35
+ timeout: string
36
+ total: string
37
+ paymentUrl: string
38
+ errorCodes?: string[]
39
+ }
40
+
41
+ interface SimplepayResult {
42
+ r: number // response code
43
+ t: string // transaction id
44
+ e: 'success' | 'fail' | 'timeout' | 'cancel' // event
45
+ m: string // merchant id
46
+ o: string // order id
47
+ }
48
+
49
+ export { PaymentData, SimplePayRequestBody, SimplePayResponse, SimplepayResult }