node-paytmpg 5.3.1 → 5.4.2

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.
@@ -0,0 +1,251 @@
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' });
227
+ res.write(`<html>
228
+
229
+ <head>
230
+ <title>Merchant Checkout Error</title>
231
+ </head>
232
+
233
+ <body>
234
+ <center>
235
+ <h1>Something went wrong. Please wait you will be redirected automatically...</h1>
236
+ </center>
237
+ <form method="post" action="${params['CALLBACK_URL']}" name="f1">${formFields}</form>
238
+ <script type="text/javascript">document.f1.submit();</script>
239
+ </body>
240
+
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;
@@ -1,154 +1,154 @@
1
- "use strict";
2
-
3
- var crypt = require('./crypt');
4
- var util = require('util');
5
- var crypto = require('crypto');
6
- const PaytmChecksum = require('./PaytmChecksum.js');
7
-
8
- //mandatory flag: when it set, only mandatory parameters are added to checksum
9
-
10
- function paramsToString(params, mandatoryflag) {
11
- var data = '';
12
- var tempKeys = Object.keys(params);
13
- tempKeys.sort();
14
- tempKeys.forEach(function (key) {
15
- if (!params[key]) {
16
- return
17
- }
18
- try {
19
- var n = params[key].includes("REFUND");
20
- var m = params[key].includes("|");
21
- if (n == true) {
22
- params[key] = "";
23
- }
24
- if (m == true) {
25
- params[key] = "";
26
- }
27
- } catch (e) {
28
- params[key] = "";
29
- console.log(e)
30
- }
31
-
32
-
33
- if (key !== 'CHECKSUMHASH') {
34
- if (params[key] === 'null') params[key] = '';
35
- if (!mandatoryflag || mandatoryParams.indexOf(key) !== -1) {
36
- data += (params[key] + '|');
37
- }
38
- }
39
- });
40
- return data;
41
- }
42
-
43
-
44
- function genchecksum(params, key, cb) {
45
- let checksumPromise = PaytmChecksum.generateSignature(params, key).then(checksum => {
46
- cb(undefined, checksum)
47
- })
48
- return checksumPromise;
49
- var data = paramsToString(params);
50
- crypt.gen_salt(4, function (err, salt) {
51
- var sha256 = crypto.createHash('sha256').update(data + salt).digest('hex');
52
- var check_sum = sha256 + salt;
53
- var encrypted = crypt.encrypt(check_sum, key);
54
- cb(undefined, encrypted);
55
- });
56
- }
57
- function genchecksumbystring(params, key, cb) {
58
-
59
- crypt.gen_salt(4, function (err, salt) {
60
- var sha256 = crypto.createHash('sha256').update(params + '|' + salt).digest('hex');
61
- var check_sum = sha256 + salt;
62
- var encrypted = crypt.encrypt(check_sum, key);
63
-
64
- var CHECKSUMHASH = encodeURIComponent(encrypted);
65
- CHECKSUMHASH = encrypted;
66
- cb(undefined, CHECKSUMHASH);
67
- });
68
- }
69
-
70
- function verifychecksum(params, key, checksumhash) {
71
- return PaytmChecksum.verifySignature(params, key, checksumhash)
72
- var data = paramsToString(params, false);
73
-
74
- //TODO: after PG fix on thier side remove below two lines
75
- if (typeof checksumhash !== "undefined") {
76
- checksumhash = checksumhash.replace('\n', '');
77
- checksumhash = checksumhash.replace('\r', '');
78
- var temp = decodeURIComponent(checksumhash);
79
- var checksum = crypt.decrypt(temp, key);
80
- var salt = checksum.substr(checksum.length - 4);
81
- var sha256 = checksum.substr(0, checksum.length - 4);
82
- var hash = crypto.createHash('sha256').update(data + salt).digest('hex');
83
- if (hash === sha256) {
84
- return true;
85
- } else {
86
- util.log("checksum is wrong");
87
- return false;
88
- }
89
- } else {
90
- util.log("checksum not found");
91
- return false;
92
- }
93
- }
94
-
95
- function verifychecksumbystring(params, key, checksumhash) {
96
-
97
- var checksum = crypt.decrypt(checksumhash, key);
98
- var salt = checksum.substr(checksum.length - 4);
99
- var sha256 = checksum.substr(0, checksum.length - 4);
100
- var hash = crypto.createHash('sha256').update(params + '|' + salt).digest('hex');
101
- if (hash === sha256) {
102
- return true;
103
- } else {
104
- util.log("checksum is wrong");
105
- return false;
106
- }
107
- }
108
-
109
- function genchecksumforrefund(params, key, cb) {
110
- var data = paramsToStringrefund(params);
111
- crypt.gen_salt(4, function (err, salt) {
112
- var sha256 = crypto.createHash('sha256').update(data + salt).digest('hex');
113
- var check_sum = sha256 + salt;
114
- var encrypted = crypt.encrypt(check_sum, key);
115
- params.CHECKSUM = encodeURIComponent(encrypted);
116
- cb(undefined, params);
117
- });
118
- }
119
-
120
- function paramsToStringrefund(params, mandatoryflag) {
121
- var data = '';
122
- var tempKeys = Object.keys(params);
123
- tempKeys.sort();
124
- tempKeys.forEach(function (key) {
125
- var m = params[key].includes("|");
126
- if (m == true) {
127
- params[key] = "";
128
- }
129
- if (key !== 'CHECKSUMHASH') {
130
- if (params[key] === 'null') params[key] = '';
131
- if (!mandatoryflag || mandatoryParams.indexOf(key) !== -1) {
132
- data += (params[key] + '|');
133
- }
134
- }
135
- });
136
- return data;
137
- }
138
-
139
- function checkRazorSignature(razorpayOrderId, razorpayPaymentId, secret, razorpay_signature) {
140
- const hmac = crypto.createHmac('sha256', secret);
141
-
142
- hmac.update(razorpayOrderId + "|" + razorpayPaymentId);
143
- let generatedSignature = hmac.digest('hex');
144
-
145
- let isSignatureValid = generatedSignature == razorpay_signature;
146
- return isSignatureValid
147
- }
148
-
149
- module.exports.genchecksum = genchecksum;
150
- module.exports.verifychecksum = verifychecksum;
151
- module.exports.verifychecksumbystring = verifychecksumbystring;
152
- module.exports.genchecksumbystring = genchecksumbystring;
153
- module.exports.genchecksumforrefund = genchecksumforrefund;
154
- module.exports.checkRazorSignature = checkRazorSignature;
1
+ "use strict";
2
+
3
+ var crypt = require('./crypt');
4
+ var util = require('util');
5
+ var crypto = require('crypto');
6
+ const PaytmChecksum = require('./PaytmChecksum.js');
7
+
8
+ //mandatory flag: when it set, only mandatory parameters are added to checksum
9
+
10
+ function paramsToString(params, mandatoryflag) {
11
+ var data = '';
12
+ var tempKeys = Object.keys(params);
13
+ tempKeys.sort();
14
+ tempKeys.forEach(function (key) {
15
+ if (!params[key]) {
16
+ return
17
+ }
18
+ try {
19
+ var n = params[key].includes("REFUND");
20
+ var m = params[key].includes("|");
21
+ if (n == true) {
22
+ params[key] = "";
23
+ }
24
+ if (m == true) {
25
+ params[key] = "";
26
+ }
27
+ } catch (e) {
28
+ params[key] = "";
29
+ console.log(e)
30
+ }
31
+
32
+
33
+ if (key !== 'CHECKSUMHASH') {
34
+ if (params[key] === 'null') params[key] = '';
35
+ if (!mandatoryflag || mandatoryParams.indexOf(key) !== -1) {
36
+ data += (params[key] + '|');
37
+ }
38
+ }
39
+ });
40
+ return data;
41
+ }
42
+
43
+
44
+ function genchecksum(params, key, cb) {
45
+ let checksumPromise = PaytmChecksum.generateSignature(params, key).then(checksum => {
46
+ cb(undefined, checksum)
47
+ })
48
+ return checksumPromise;
49
+ var data = paramsToString(params);
50
+ crypt.gen_salt(4, function (err, salt) {
51
+ var sha256 = crypto.createHash('sha256').update(data + salt).digest('hex');
52
+ var check_sum = sha256 + salt;
53
+ var encrypted = crypt.encrypt(check_sum, key);
54
+ cb(undefined, encrypted);
55
+ });
56
+ }
57
+ function genchecksumbystring(params, key, cb) {
58
+
59
+ crypt.gen_salt(4, function (err, salt) {
60
+ var sha256 = crypto.createHash('sha256').update(params + '|' + salt).digest('hex');
61
+ var check_sum = sha256 + salt;
62
+ var encrypted = crypt.encrypt(check_sum, key);
63
+
64
+ var CHECKSUMHASH = encodeURIComponent(encrypted);
65
+ CHECKSUMHASH = encrypted;
66
+ cb(undefined, CHECKSUMHASH);
67
+ });
68
+ }
69
+
70
+ function verifychecksum(params, key, checksumhash) {
71
+ return PaytmChecksum.verifySignature(params, key, checksumhash)
72
+ var data = paramsToString(params, false);
73
+
74
+ //TODO: after PG fix on thier side remove below two lines
75
+ if (typeof checksumhash !== "undefined") {
76
+ checksumhash = checksumhash.replace('\n', '');
77
+ checksumhash = checksumhash.replace('\r', '');
78
+ var temp = decodeURIComponent(checksumhash);
79
+ var checksum = crypt.decrypt(temp, key);
80
+ var salt = checksum.substr(checksum.length - 4);
81
+ var sha256 = checksum.substr(0, checksum.length - 4);
82
+ var hash = crypto.createHash('sha256').update(data + salt).digest('hex');
83
+ if (hash === sha256) {
84
+ return true;
85
+ } else {
86
+ util.log("checksum is wrong");
87
+ return false;
88
+ }
89
+ } else {
90
+ util.log("checksum not found");
91
+ return false;
92
+ }
93
+ }
94
+
95
+ function verifychecksumbystring(params, key, checksumhash) {
96
+
97
+ var checksum = crypt.decrypt(checksumhash, key);
98
+ var salt = checksum.substr(checksum.length - 4);
99
+ var sha256 = checksum.substr(0, checksum.length - 4);
100
+ var hash = crypto.createHash('sha256').update(params + '|' + salt).digest('hex');
101
+ if (hash === sha256) {
102
+ return true;
103
+ } else {
104
+ util.log("checksum is wrong");
105
+ return false;
106
+ }
107
+ }
108
+
109
+ function genchecksumforrefund(params, key, cb) {
110
+ var data = paramsToStringrefund(params);
111
+ crypt.gen_salt(4, function (err, salt) {
112
+ var sha256 = crypto.createHash('sha256').update(data + salt).digest('hex');
113
+ var check_sum = sha256 + salt;
114
+ var encrypted = crypt.encrypt(check_sum, key);
115
+ params.CHECKSUM = encodeURIComponent(encrypted);
116
+ cb(undefined, params);
117
+ });
118
+ }
119
+
120
+ function paramsToStringrefund(params, mandatoryflag) {
121
+ var data = '';
122
+ var tempKeys = Object.keys(params);
123
+ tempKeys.sort();
124
+ tempKeys.forEach(function (key) {
125
+ var m = params[key].includes("|");
126
+ if (m == true) {
127
+ params[key] = "";
128
+ }
129
+ if (key !== 'CHECKSUMHASH') {
130
+ if (params[key] === 'null') params[key] = '';
131
+ if (!mandatoryflag || mandatoryParams.indexOf(key) !== -1) {
132
+ data += (params[key] + '|');
133
+ }
134
+ }
135
+ });
136
+ return data;
137
+ }
138
+
139
+ function checkRazorSignature(razorpayOrderId, razorpayPaymentId, secret, razorpay_signature) {
140
+ const hmac = crypto.createHmac('sha256', secret);
141
+
142
+ hmac.update(razorpayOrderId + "|" + razorpayPaymentId);
143
+ let generatedSignature = hmac.digest('hex');
144
+
145
+ let isSignatureValid = generatedSignature == razorpay_signature;
146
+ return isSignatureValid
147
+ }
148
+
149
+ module.exports.genchecksum = genchecksum;
150
+ module.exports.verifychecksum = verifychecksum;
151
+ module.exports.verifychecksumbystring = verifychecksumbystring;
152
+ module.exports.genchecksumbystring = genchecksumbystring;
153
+ module.exports.genchecksumforrefund = genchecksumforrefund;
154
+ module.exports.checkRazorSignature = checkRazorSignature;