node-paytmpg 6.4.7 → 7.0.1

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.
Files changed (58) hide show
  1. package/README.MD +132 -182
  2. package/app/views/layouts/index.hbs +7 -7
  3. package/app/views/result.hbs +1 -1
  4. package/dist/app/controllers/adapters/open_money.js +400 -0
  5. package/dist/app/controllers/adapters/paytm.js +34 -0
  6. package/{app → dist/app}/controllers/adapters/payu.js +208 -239
  7. package/dist/app/controllers/checksum/PaytmChecksum.js +118 -0
  8. package/dist/app/controllers/checksum/checksum.js +158 -0
  9. package/dist/app/controllers/checksum/crypt.js +117 -0
  10. package/dist/app/controllers/checksum/server.js +130 -0
  11. package/dist/app/controllers/payment.controller.js +985 -0
  12. package/dist/app/controllers/static/loadingsvg.js +54 -0
  13. package/dist/app/controllers/user.controller.js +53 -0
  14. package/dist/app/models/index.js +2 -0
  15. package/dist/app/routes/payment_route.js +46 -0
  16. package/dist/app/utils/buildConfig.js +210 -0
  17. package/dist/app/utils/utils.js +20 -0
  18. package/dist/app/views/home.hbs +22 -0
  19. package/dist/app/views/init.hbs +98 -0
  20. package/dist/app/views/layouts/index.hbs +53 -0
  21. package/dist/app/views/result.hbs +33 -0
  22. package/dist/index.js +119 -0
  23. package/dist/package.json +67 -0
  24. package/dist/public/css/style.css +455 -0
  25. package/dist/public/js/index.js +283 -0
  26. package/dist/public/layer_checkout.js +38 -0
  27. package/dist/public/pay.png +0 -0
  28. package/dist/public/start.png +0 -0
  29. package/dist/public/start2.png +0 -0
  30. package/dist/public/stat.png +0 -0
  31. package/dist/public/test.html +24 -0
  32. package/dist/public/test.html~ +24 -0
  33. package/package.json +29 -6
  34. package/public/test.html~ +24 -0
  35. package/.github/workflows/codeql-analysis.yml +0 -71
  36. package/.github/workflows/nodejs.yml +0 -24
  37. package/.github/workflows/npm-publish.yml +0 -23
  38. package/Dockerfile +0 -9
  39. package/app/controllers/adapters/open_money.js +0 -515
  40. package/app/controllers/checksum/PaytmChecksum.js +0 -94
  41. package/app/controllers/checksum/checksum.js +0 -154
  42. package/app/controllers/checksum/crypt.js +0 -98
  43. package/app/controllers/checksum/server.js +0 -132
  44. package/app/controllers/np_user.controller.js +0 -89
  45. package/app/controllers/payment_controller.js +0 -1295
  46. package/app/models/np_multidbplugin.js +0 -111
  47. package/app/models/np_transaction.model.js +0 -16
  48. package/app/models/np_user.model.js +0 -12
  49. package/app/routes/payment_route.js +0 -73
  50. package/app.yaml +0 -18
  51. package/example.js +0 -34
  52. package/index.js +0 -90
  53. package/lib/config/buildConfig.js +0 -113
  54. package/lib/config/defaults.js +0 -37
  55. package/lib/config/validator.js +0 -103
  56. package/lib/services/database.service.js +0 -153
  57. package/lib/utils/id-generator.js +0 -30
  58. package/lib/utils/sanitizer.js +0 -25
@@ -1,229 +1,199 @@
1
- const crypto = require('crypto');
2
- const axios = require('axios');
3
-
4
- class PayU {
5
- config
6
- constructor(npconfig) {
7
- const baseUrl = (npconfig.payu_url || '').replace(/\/$/, '');
8
- const isSandbox = baseUrl.indexOf('test.payu.in') > -1;
9
- const verifyUrl = npconfig.payu_verify_url || (isSandbox
10
- ? 'https://test.payu.in/merchant/postservice.php?form=2'
11
- : 'https://info.payu.in/merchant/postservice.php?form=2');
12
- this.config = {
13
- key: npconfig.KEY,
14
- salt: npconfig.SECRET,
15
- baseUrl: baseUrl,
16
- paymentUrl: npconfig.payu_payment_url || (baseUrl ? baseUrl + '/_payment' : ''),
17
- verifyUrl: verifyUrl
18
- };
19
- }
20
-
21
- normalizeAmount(amount) {
22
- const value = parseFloat(amount || 0);
23
- return value.toFixed(2);
24
- }
25
-
26
- buildRequestHash(payload) {
27
- const parts = [
28
- payload.key,
29
- payload.txnid,
30
- this.normalizeAmount(payload.amount),
31
- payload.productinfo,
32
- payload.firstname,
33
- payload.email,
34
- payload.udf1 || '',
35
- payload.udf2 || '',
36
- payload.udf3 || '',
37
- payload.udf4 || '',
38
- payload.udf5 || '',
39
- payload.udf6 || '',
40
- payload.udf7 || '',
41
- payload.udf8 || '',
42
- payload.udf9 || '',
43
- payload.udf10 || '',
44
- this.config.salt
45
- ];
46
- return crypto.createHash('sha512').update(parts.join('|')).digest('hex');
47
- }
48
-
49
- buildResponseHash(data) {
50
- const amount = this.normalizeAmount(data.amount);
51
- const sequence = [
52
- data.additionalCharges || null,
53
- this.config.salt,
54
- data.status || '',
55
- '', '', '', '', '', '', '', '', '', '',
56
- data.udf5 || '',
57
- data.udf4 || '',
58
- data.udf3 || '',
59
- data.udf2 || '',
60
- data.udf1 || '',
61
- data.email || '',
62
- data.firstname || '',
63
- data.productinfo || '',
64
- amount,
65
- data.txnid || '',
66
- data.key || ''
67
- ];
68
- const filtered = sequence.filter((v) => v !== null);
69
- return crypto.createHash('sha512').update(filtered.join('|')).digest('hex');
70
- }
71
-
72
- generatePaymentRequest(params) {
73
- const payload = {
74
- key: this.config.key,
75
- txnid: params['ORDER_ID'],
76
- amount: this.normalizeAmount(params['TXN_AMOUNT']),
77
- productinfo: params['PRODUCT_NAME'],
78
- firstname: params['NAME'],
79
- email: params['EMAIL'],
80
- phone: params['MOBILE_NO'],
81
- surl: params['CALLBACK_URL'],
82
- furl: params['CALLBACK_URL'],
83
- udf1: params['CUST_ID'] || '',
84
- udf2: params['ORDER_ID'] || '',
85
- service_provider: 'payu_paisa'
86
- };
87
-
88
- payload.hash = this.buildRequestHash(payload);
89
-
90
- const formFields = Object.keys(payload).map((key) => {
91
- return "<input type='hidden' name='" + key + "' value='" + payload[key] + "' />";
92
- }).join('');
93
- const html = `<form action='${this.config.paymentUrl}' method='post' id='payu_payment_form' style='display:none'>${formFields}</form><script>document.getElementById('payu_payment_form').submit();</script>`;
94
-
95
- return { html: html, payload: payload };
96
- }
97
- decodeTransactionResponse(txnDataBase64FromPayu) {
98
- const txnDataJson = Buffer.from(txnDataBase64FromPayu, 'base64').toString('utf-8');
99
- return JSON.parse(txnDataJson);
100
- }
101
- async verifyResult(req) {
102
- const originalBody = req.body || {};
103
- const lookupId = originalBody.txnid || req.query.order_id;
104
- const statusResp = await this.checkBqrTxnStatus(lookupId);
105
-
106
- let resData = null;
107
- if (!resData && statusResp && statusResp.transaction_details) {
108
- const td = statusResp.transaction_details;
109
- // try direct lookup by lookupId
110
- if (td[lookupId]) {
111
- resData = td[lookupId];
112
- }
113
- else {
114
- // find entry where txnid matches lookupId or key ends with lookupId
115
- for (const k of Object.keys(td)) {
116
- const t = td[k];
117
- if (!t) continue;
118
- if ((t.txnid && t.txnid.toString() === lookupId) || k.toString().endsWith(lookupId)) {
119
- resData = t;
120
- break;
121
- }
122
- }
123
- }
124
- }
125
-
126
- // Determine source for status and mapping (prefer decoded resData)
127
- const source = resData || (statusResp || {}) || originalBody;
128
-
129
- const msg = (statusResp?.msg || '').toString();
130
- const statusText = (source.status || source.unmappedstatus || msg || '').toString().toLowerCase();
131
- let status = 'TXN_FAILURE';
132
- if (statusText.includes('success') || statusText.includes('completed') || statusText.includes('captured')) {
133
- status = 'TXN_SUCCESS';
134
- }
135
- else if (statusText.includes('pending')) {
136
- status = 'TXN_PENDING';
137
- }
138
-
139
- const orderId = (source.udf2 || source.order_id || source.txnid || lookupId).toString();
140
- const txnId = source.mihpayid || source.txnid || null;
141
-
142
- return {
143
- STATUS: status,
144
- ORDERID: orderId,
145
- TXNID: txnId,
146
- data: resData || statusResp || originalBody,
147
- cancelled: source.unmappedstatus?.toLowerCase()?.includes('cancelled') || false
148
- };
149
- }
150
-
151
- async getPaymentStatus(txnId) {
152
- const verifyPayload = new URLSearchParams();
153
- verifyPayload.append('key', this.config.key || '');
154
- verifyPayload.append('command', 'verify_payment');
155
- verifyPayload.append('var1', txnId || '');
156
- const hashString = [this.config.key, 'verify_payment', txnId, this.config.salt].join('|');
157
- verifyPayload.append('hash', crypto.createHash('sha512').update(hashString).digest('hex'));
158
-
159
- try {
160
- const response = await axios.post(this.config.verifyUrl, verifyPayload.toString(), {
161
- headers: {
162
- 'Content-Type': 'application/x-www-form-urlencoded'
163
- }
164
- });
165
- return response.data;
166
- }
167
- catch (e) {
168
- return { error: e.message };
169
- }
170
- }
171
-
172
- async postCommand(command, transactionId) {
173
- const payload = new URLSearchParams();
174
- payload.append('key', this.config.key || '');
175
- payload.append('command', command || '');
176
- payload.append('var1', transactionId || '');
177
-
178
- // build hash: key|command|var1...|salt
179
- const hashParts = [this.config.key, command, transactionId, this.config.salt];
180
- const hashString = hashParts.join('|');
181
- payload.append('hash', crypto.createHash('sha512').update(hashString).digest('hex'));
182
-
183
- try {
184
- const response = await axios.post(this.config.verifyUrl, payload.toString(), {
185
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
186
- });
187
- return response.data;
188
- }
189
- catch (e) {
190
- return { error: e.message };
191
- }
192
- }
193
-
194
- /**
195
- * https://docs.payu.in/reference/transaction-status-check-api-2#sample-request
196
- * @param {*} transactionId mandatory
197
- * @param {*} paymentmode optional
198
- * @param {*} productype optional
199
- * @returns
200
- */
201
- async checkBqrTxnStatus(transactionId) {
202
- return this.postCommand('verify_payment', transactionId);
203
- }
204
-
205
- renderProcessingPage(params, paymentReq, res, loadingSVG) {
206
- res.writeHead(200, { 'Content-Type': 'text/html' });
207
- res.write(`<html><head><title>Merchant Checkout Page</title></head><body><center><h1>Processing ! Please do not refresh this page...</h1><br>${paymentReq.html}<br><br>${loadingSVG}</center></body></html>`);
208
- res.end();
209
- }
210
-
211
- renderError(params, error, res) {
212
- console.log('ERROR:::', error, '\n');
213
- res.status(500);
214
- let formFields = '';
215
- const errorResp = {
216
- TXNID: 'na',
217
- STATUS: 'TXN_FAILURE',
218
- CANCELLED: 'cancelled',
219
- ORDERID: params['ORDER_ID']
220
- };
221
- Object.keys(errorResp).forEach((key) => {
222
- formFields += "<input type='hidden' name='" + key + "' value='" + errorResp[key] + "' >";
223
- });
224
- formFields += "<input type='hidden' name='CHECKSUMHASH' value='" + (params['CHECKSUM'] || '') + "' >";
225
-
226
- res.writeHead(200, { 'Content-Type': 'text/html' });
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const crypto_1 = __importDefault(require("crypto"));
7
+ const axios_1 = __importDefault(require("axios"));
8
+ class PayU {
9
+ constructor(npconfig) {
10
+ const baseUrl = (npconfig.payu_url || '').replace(/\/$/, '');
11
+ const isSandbox = baseUrl.indexOf('test.payu.in') > -1;
12
+ const verifyUrl = npconfig.payu_verify_url || (isSandbox
13
+ ? 'https://test.payu.in/merchant/postservice.php?form=2'
14
+ : 'https://info.payu.in/merchant/postservice.php?form=2');
15
+ this.config = {
16
+ key: npconfig.KEY,
17
+ salt: npconfig.SECRET,
18
+ baseUrl,
19
+ paymentUrl: npconfig.payu_payment_url || (baseUrl ? `${baseUrl}/_payment` : ''),
20
+ verifyUrl,
21
+ };
22
+ }
23
+ normalizeAmount(amount) {
24
+ const value = parseFloat(amount || 0);
25
+ return value.toFixed(2);
26
+ }
27
+ buildRequestHash(payload) {
28
+ const parts = [
29
+ payload.key,
30
+ payload.txnid,
31
+ this.normalizeAmount(payload.amount),
32
+ payload.productinfo,
33
+ payload.firstname,
34
+ payload.email,
35
+ payload.udf1 || '',
36
+ payload.udf2 || '',
37
+ payload.udf3 || '',
38
+ payload.udf4 || '',
39
+ payload.udf5 || '',
40
+ payload.udf6 || '',
41
+ payload.udf7 || '',
42
+ payload.udf8 || '',
43
+ payload.udf9 || '',
44
+ payload.udf10 || '',
45
+ this.config.salt,
46
+ ];
47
+ return crypto_1.default.createHash('sha512').update(parts.join('|')).digest('hex');
48
+ }
49
+ buildResponseHash(data) {
50
+ const amount = this.normalizeAmount(data.amount);
51
+ const sequence = [
52
+ data.additionalCharges || null,
53
+ this.config.salt,
54
+ data.status || '',
55
+ '', '', '', '', '', '', '', '', '', '',
56
+ data.udf5 || '',
57
+ data.udf4 || '',
58
+ data.udf3 || '',
59
+ data.udf2 || '',
60
+ data.udf1 || '',
61
+ data.email || '',
62
+ data.firstname || '',
63
+ data.productinfo || '',
64
+ amount,
65
+ data.txnid || '',
66
+ data.key || '',
67
+ ];
68
+ const filtered = sequence.filter((value) => value !== null);
69
+ return crypto_1.default.createHash('sha512').update(filtered.join('|')).digest('hex');
70
+ }
71
+ generatePaymentRequest(params) {
72
+ const payload = {
73
+ key: this.config.key,
74
+ txnid: params.ORDER_ID,
75
+ amount: this.normalizeAmount(params.TXN_AMOUNT),
76
+ productinfo: params.PRODUCT_NAME,
77
+ firstname: params.NAME,
78
+ email: params.EMAIL,
79
+ phone: params.MOBILE_NO,
80
+ surl: params.CALLBACK_URL,
81
+ furl: params.CALLBACK_URL,
82
+ udf1: params.CUST_ID || '',
83
+ udf2: params.ORDER_ID || '',
84
+ service_provider: 'payu_paisa',
85
+ };
86
+ payload.hash = this.buildRequestHash(payload);
87
+ const formFields = Object.keys(payload)
88
+ .map((key) => `<input type='hidden' name='${key}' value='${payload[key]}' />`)
89
+ .join('');
90
+ const html = `<form action='${this.config.paymentUrl}' method='post' id='payu_payment_form' style='display:none'>${formFields}</form><script>document.getElementById('payu_payment_form').submit();</script>`;
91
+ return { html, payload };
92
+ }
93
+ decodeTransactionResponse(txnDataBase64FromPayu) {
94
+ const txnDataJson = Buffer.from(txnDataBase64FromPayu, 'base64').toString('utf-8');
95
+ return JSON.parse(txnDataJson);
96
+ }
97
+ async verifyResult(req) {
98
+ var _a, _b, _c;
99
+ const originalBody = req.body || {};
100
+ const lookupId = originalBody.txnid || ((_a = req.query) === null || _a === void 0 ? void 0 : _a.order_id);
101
+ const statusResp = await this.checkBqrTxnStatus(lookupId);
102
+ let resData = null;
103
+ if (!resData && statusResp && statusResp.transaction_details) {
104
+ const td = statusResp.transaction_details;
105
+ if (td[lookupId]) {
106
+ resData = td[lookupId];
107
+ }
108
+ else {
109
+ for (const key of Object.keys(td)) {
110
+ const txn = td[key];
111
+ if (!txn)
112
+ continue;
113
+ if ((txn.txnid && txn.txnid.toString() === lookupId) || key.toString().endsWith(lookupId)) {
114
+ resData = txn;
115
+ break;
116
+ }
117
+ }
118
+ }
119
+ }
120
+ const source = resData || statusResp || originalBody;
121
+ const msg = ((statusResp === null || statusResp === void 0 ? void 0 : statusResp.msg) || '').toString();
122
+ const statusText = (source.status || source.unmappedstatus || msg || '').toString().toLowerCase();
123
+ let status = 'TXN_FAILURE';
124
+ if (statusText.includes('success') || statusText.includes('completed') || statusText.includes('captured')) {
125
+ status = 'TXN_SUCCESS';
126
+ }
127
+ else if (statusText.includes('pending')) {
128
+ status = 'TXN_PENDING';
129
+ }
130
+ const orderId = (source.udf2 || source.order_id || source.txnid || lookupId).toString();
131
+ const txnId = source.mihpayid || source.txnid || null;
132
+ return {
133
+ STATUS: status,
134
+ ORDERID: orderId,
135
+ TXNID: txnId,
136
+ data: resData || statusResp || originalBody,
137
+ cancelled: ((_c = (_b = source.unmappedstatus) === null || _b === void 0 ? void 0 : _b.toLowerCase) === null || _c === void 0 ? void 0 : _c.call(_b).includes('cancelled')) || false,
138
+ };
139
+ }
140
+ async getPaymentStatus(txnId) {
141
+ const verifyPayload = new URLSearchParams();
142
+ verifyPayload.append('key', this.config.key || '');
143
+ verifyPayload.append('command', 'verify_payment');
144
+ verifyPayload.append('var1', txnId || '');
145
+ const hashString = [this.config.key, 'verify_payment', txnId, this.config.salt].join('|');
146
+ verifyPayload.append('hash', crypto_1.default.createHash('sha512').update(hashString).digest('hex'));
147
+ try {
148
+ const response = await axios_1.default.post(this.config.verifyUrl, verifyPayload.toString(), {
149
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
150
+ });
151
+ return response.data;
152
+ }
153
+ catch (error) {
154
+ return { error: error.message };
155
+ }
156
+ }
157
+ async postCommand(command, transactionId) {
158
+ const payload = new URLSearchParams();
159
+ payload.append('key', this.config.key || '');
160
+ payload.append('command', command || '');
161
+ payload.append('var1', transactionId || '');
162
+ const hashString = [this.config.key, command, transactionId, this.config.salt].join('|');
163
+ payload.append('hash', crypto_1.default.createHash('sha512').update(hashString).digest('hex'));
164
+ try {
165
+ const response = await axios_1.default.post(this.config.verifyUrl, payload.toString(), {
166
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
167
+ });
168
+ return response.data;
169
+ }
170
+ catch (error) {
171
+ return { error: error.message };
172
+ }
173
+ }
174
+ async checkBqrTxnStatus(transactionId) {
175
+ return this.postCommand('verify_payment', transactionId);
176
+ }
177
+ renderProcessingPage(params, paymentReq, res, loadingSVG) {
178
+ res.writeHead(200, { 'Content-Type': 'text/html' });
179
+ res.write(`<html><head><title>Merchant Checkout Page</title></head><body><center><h1>Processing ! Please do not refresh this page...</h1><br>${paymentReq.html}<br><br>${loadingSVG}</center></body></html>`);
180
+ res.end();
181
+ }
182
+ renderError(params, error, res) {
183
+ console.log('ERROR:::', error, '\n');
184
+ res.status(500);
185
+ let formFields = '';
186
+ const errorResp = {
187
+ TXNID: 'na',
188
+ STATUS: 'TXN_FAILURE',
189
+ CANCELLED: 'cancelled',
190
+ ORDERID: params.ORDER_ID,
191
+ };
192
+ Object.keys(errorResp).forEach((key) => {
193
+ formFields += `<input type='hidden' name='${key}' value='${errorResp[key]}' >`;
194
+ });
195
+ formFields += `<input type='hidden' name='CHECKSUMHASH' value='${params.CHECKSUM || ''}' >`;
196
+ res.writeHead(200, { 'Content-Type': 'text/html' });
227
197
  res.write(`<html>
228
198
 
229
199
  <head>
@@ -234,18 +204,17 @@ class PayU {
234
204
  <center>
235
205
  <h1>Something went wrong. Please wait you will be redirected automatically...</h1>
236
206
  </center>
237
- <form method="post" action="${params['CALLBACK_URL']}" name="f1">${formFields}</form>
238
- <script type="text/javascript">document.f1.submit();</script>
207
+ <form method='post' action='${params.CALLBACK_URL}' name='f1'>${formFields}</form>
208
+ <script type='text/javascript'>document.f1.submit();</script>
239
209
  </body>
240
210
 
241
- </html>`);
242
- res.end();
243
- }
244
-
245
- processWebhook(req, res) {
246
- res.status(201);
247
- res.send({ message: 'Webhook not implemented for PayU' });
248
- }
249
- }
250
-
251
- module.exports = PayU;
211
+ </html>`);
212
+ res.end();
213
+ }
214
+ processWebhook(req, res, updateTransaction) {
215
+ res.status(201);
216
+ res.send({ message: 'Webhook not implemented for PayU' });
217
+ }
218
+ }
219
+ exports.default = PayU;
220
+ module.exports = PayU;
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const crypto = __importStar(require("crypto"));
37
+ class PaytmChecksum {
38
+ static encrypt(input, key) {
39
+ const cipher = crypto.createCipheriv('AES-128-CBC', key, PaytmChecksum.iv);
40
+ let encrypted = cipher.update(input, 'binary', 'base64');
41
+ encrypted += cipher.final('base64');
42
+ return encrypted;
43
+ }
44
+ static decrypt(encrypted, key) {
45
+ const decipher = crypto.createDecipheriv('AES-128-CBC', key, PaytmChecksum.iv);
46
+ let decrypted = decipher.update(encrypted, 'base64', 'binary');
47
+ try {
48
+ decrypted += decipher.final('binary');
49
+ }
50
+ catch (e) {
51
+ console.log(e);
52
+ }
53
+ return decrypted;
54
+ }
55
+ static generateSignature(params, key) {
56
+ if (typeof params !== 'object' && typeof params !== 'string') {
57
+ const error = 'string or object expected, ' + (typeof params) + ' given.';
58
+ return Promise.reject(error);
59
+ }
60
+ if (typeof params !== 'string') {
61
+ params = PaytmChecksum.getStringByParams(params);
62
+ }
63
+ return PaytmChecksum.generateSignatureByString(params, key);
64
+ }
65
+ static verifySignature(params, key, checksum) {
66
+ if (typeof params !== 'object' && typeof params !== 'string') {
67
+ const error = 'string or object expected, ' + (typeof params) + ' given.';
68
+ return Promise.reject(error);
69
+ }
70
+ if (typeof params !== 'string') {
71
+ if (params.hasOwnProperty('CHECKSUMHASH')) {
72
+ delete params.CHECKSUMHASH;
73
+ }
74
+ params = PaytmChecksum.getStringByParams(params);
75
+ }
76
+ return PaytmChecksum.verifySignatureByString(params, key, checksum);
77
+ }
78
+ static async generateSignatureByString(params, key) {
79
+ const salt = await PaytmChecksum.generateRandomString(4);
80
+ return PaytmChecksum.calculateChecksum(params, key, salt);
81
+ }
82
+ static verifySignatureByString(params, key, checksum) {
83
+ const paytm_hash = PaytmChecksum.decrypt(checksum, key);
84
+ const salt = paytm_hash.substr(paytm_hash.length - 4);
85
+ return (paytm_hash === PaytmChecksum.calculateHash(params, salt));
86
+ }
87
+ static generateRandomString(length) {
88
+ return new Promise(function (resolve, reject) {
89
+ crypto.randomBytes((length * 3.0) / 4.0, function (err, buf) {
90
+ if (!err) {
91
+ const salt = buf.toString('base64');
92
+ resolve(salt);
93
+ }
94
+ else {
95
+ console.log('error occurred in generateRandomString: ' + err);
96
+ reject(err);
97
+ }
98
+ });
99
+ });
100
+ }
101
+ static getStringByParams(params) {
102
+ const data = {};
103
+ Object.keys(params).sort().forEach(function (key) {
104
+ data[key] = (params[key] !== null && String(params[key]).toLowerCase() !== 'null') ? params[key] : '';
105
+ });
106
+ return Object.values(data).join('|');
107
+ }
108
+ static calculateHash(params, salt) {
109
+ const finalString = params + '|' + salt;
110
+ return crypto.createHash('sha256').update(finalString).digest('hex') + salt;
111
+ }
112
+ static calculateChecksum(params, key, salt) {
113
+ const hashString = PaytmChecksum.calculateHash(params, salt);
114
+ return PaytmChecksum.encrypt(hashString, key);
115
+ }
116
+ }
117
+ PaytmChecksum.iv = '@@@@&&&&####$$$$';
118
+ exports.default = PaytmChecksum;