node-paytmpg 3.0.4 → 4.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/.github/workflows/codeql-analysis.yml +71 -0
- package/.github/workflows/npm-publish.yml +23 -0
- package/README.MD +24 -1
- package/app/controllers/checksum/PaytmChecksum.js +94 -0
- package/app/controllers/np_user.controller.js +5 -2
- package/app/controllers/payment_controller.js +346 -47
- package/app/routes/payment_route.js +9 -7
- package/app/views/home.hbs +0 -3
- package/example.js +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# For most projects, this workflow file will not need changing; you simply need
|
|
2
|
+
# to commit it to your repository.
|
|
3
|
+
#
|
|
4
|
+
# You may wish to alter this file to override the set of languages analyzed,
|
|
5
|
+
# or to provide custom queries or build logic.
|
|
6
|
+
#
|
|
7
|
+
# ******** NOTE ********
|
|
8
|
+
# We have attempted to detect the languages in your repository. Please check
|
|
9
|
+
# the `language` matrix defined below to confirm you have the correct set of
|
|
10
|
+
# supported CodeQL languages.
|
|
11
|
+
#
|
|
12
|
+
name: "CodeQL"
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
push:
|
|
16
|
+
branches: [ master ]
|
|
17
|
+
pull_request:
|
|
18
|
+
# The branches below must be a subset of the branches above
|
|
19
|
+
branches: [ master ]
|
|
20
|
+
schedule:
|
|
21
|
+
- cron: '16 23 * * 4'
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
analyze:
|
|
25
|
+
name: Analyze
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
permissions:
|
|
28
|
+
actions: read
|
|
29
|
+
contents: read
|
|
30
|
+
security-events: write
|
|
31
|
+
|
|
32
|
+
strategy:
|
|
33
|
+
fail-fast: false
|
|
34
|
+
matrix:
|
|
35
|
+
language: [ 'javascript' ]
|
|
36
|
+
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
|
37
|
+
# Learn more:
|
|
38
|
+
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- name: Checkout repository
|
|
42
|
+
uses: actions/checkout@v2
|
|
43
|
+
|
|
44
|
+
# Initializes the CodeQL tools for scanning.
|
|
45
|
+
- name: Initialize CodeQL
|
|
46
|
+
uses: github/codeql-action/init@v1
|
|
47
|
+
with:
|
|
48
|
+
languages: ${{ matrix.language }}
|
|
49
|
+
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
50
|
+
# By default, queries listed here will override any specified in a config file.
|
|
51
|
+
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
52
|
+
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
|
53
|
+
|
|
54
|
+
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
|
55
|
+
# If this step fails, then you should remove it and run the build manually (see below)
|
|
56
|
+
- name: Autobuild
|
|
57
|
+
uses: github/codeql-action/autobuild@v1
|
|
58
|
+
|
|
59
|
+
# ℹ️ Command-line programs to run using the OS shell.
|
|
60
|
+
# 📚 https://git.io/JvXDl
|
|
61
|
+
|
|
62
|
+
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
|
63
|
+
# and modify them (or add more) to build your code if your project
|
|
64
|
+
# uses a compiled language
|
|
65
|
+
|
|
66
|
+
#- run: |
|
|
67
|
+
# make bootstrap
|
|
68
|
+
# make release
|
|
69
|
+
|
|
70
|
+
- name: Perform CodeQL Analysis
|
|
71
|
+
uses: github/codeql-action/analyze@v1
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
|
|
2
|
+
# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
|
|
3
|
+
|
|
4
|
+
name: Node.js Package
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
release:
|
|
8
|
+
types: [created]
|
|
9
|
+
push:
|
|
10
|
+
branches: [ master ]
|
|
11
|
+
jobs:
|
|
12
|
+
publish:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v1
|
|
16
|
+
- uses: actions/setup-node@v1
|
|
17
|
+
with:
|
|
18
|
+
node-version: 10
|
|
19
|
+
- run: npm install
|
|
20
|
+
- run: npm test
|
|
21
|
+
- uses: JS-DevTools/npm-publish@v1
|
|
22
|
+
with:
|
|
23
|
+
token: ${{ secrets.NPM_TOKEN }}
|
package/README.MD
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
## Node JS Payments Easy Integration
|
|
2
|
+
|
|
3
|
+
[](https://github.com/shiveshnavin/node_paytm/actions/workflows/npm-publish.yml)
|
|
4
|
+
[](https://github.com/shiveshnavin/node_paytm/actions/workflows/nodejs.yml)
|
|
5
|
+
|
|
2
6
|
Support for :
|
|
3
7
|
- Paytm
|
|
4
8
|
- RazorPay
|
|
5
9
|
|
|
6
|
-
Does all the hardwork for you while integrating
|
|
10
|
+
Does all the hardwork for you while integrating payments in any express app. Comes with inbuilt UI and REST APIs for lightning fast development and prototyping .
|
|
7
11
|
|
|
8
12
|
## Example
|
|
9
13
|
|
|
@@ -198,6 +202,25 @@ var User=PayTMPG.User;
|
|
|
198
202
|
|
|
199
203
|
```
|
|
200
204
|
|
|
205
|
+
### Webhooks
|
|
206
|
+
|
|
207
|
+
Webhooks can issued at at `/_pay/api/webhook` and are useful for payments captured late.
|
|
208
|
+
|
|
209
|
+
If you are using `bodyparser` , make sure to remove these from your express app since the body parsers will be already added with the library .
|
|
210
|
+
```
|
|
211
|
+
Comment these if present in your app
|
|
212
|
+
app.use(bodyParser.json());
|
|
213
|
+
app.use(bodyParser.urlencoded({ extended: true }));
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### For razorpay webhook
|
|
217
|
+
Make sure to use the same secret in your webhook as the merchant secret.
|
|
218
|
+
https://razorpay.com/docs/webhooks/
|
|
219
|
+
|
|
220
|
+
#### For paytm
|
|
221
|
+
Nothing extra needed
|
|
222
|
+
https://developer.paytm.com/docs/callback-and-webhook/?ref=callbackWebhook
|
|
223
|
+
|
|
201
224
|
|
|
202
225
|
|
|
203
226
|
License : GPL
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var crypto = require('crypto');
|
|
4
|
+
|
|
5
|
+
class PaytmChecksum {
|
|
6
|
+
|
|
7
|
+
static encrypt(input, key) {
|
|
8
|
+
var cipher = crypto.createCipheriv('AES-128-CBC', key, PaytmChecksum.iv);
|
|
9
|
+
var encrypted = cipher.update(input, 'binary', 'base64');
|
|
10
|
+
encrypted += cipher.final('base64');
|
|
11
|
+
return encrypted;
|
|
12
|
+
}
|
|
13
|
+
static decrypt(encrypted, key) {
|
|
14
|
+
var decipher = crypto.createDecipheriv('AES-128-CBC', key, PaytmChecksum.iv);
|
|
15
|
+
var decrypted = decipher.update(encrypted, 'base64', 'binary');
|
|
16
|
+
try {
|
|
17
|
+
decrypted += decipher.final('binary');
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
console.log(e);
|
|
21
|
+
}
|
|
22
|
+
return decrypted;
|
|
23
|
+
}
|
|
24
|
+
static generateSignature(params, key) {
|
|
25
|
+
if (typeof params !== "object" && typeof params !== "string") {
|
|
26
|
+
var error = "string or object expected, " + (typeof params) + " given.";
|
|
27
|
+
return Promise.reject(error);
|
|
28
|
+
}
|
|
29
|
+
if (typeof params !== "string"){
|
|
30
|
+
params = PaytmChecksum.getStringByParams(params);
|
|
31
|
+
}
|
|
32
|
+
return PaytmChecksum.generateSignatureByString(params, key);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
static verifySignature(params, key, checksum) {
|
|
37
|
+
if (typeof params !== "object" && typeof params !== "string") {
|
|
38
|
+
var error = "string or object expected, " + (typeof params) + " given.";
|
|
39
|
+
return Promise.reject(error);
|
|
40
|
+
}
|
|
41
|
+
if(params.hasOwnProperty("CHECKSUMHASH")){
|
|
42
|
+
delete params.CHECKSUMHASH
|
|
43
|
+
}
|
|
44
|
+
if (typeof params !== "string"){
|
|
45
|
+
params = PaytmChecksum.getStringByParams(params);
|
|
46
|
+
}
|
|
47
|
+
return PaytmChecksum.verifySignatureByString(params, key, checksum);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static async generateSignatureByString(params, key) {
|
|
51
|
+
var salt = await PaytmChecksum.generateRandomString(4);
|
|
52
|
+
return PaytmChecksum.calculateChecksum(params, key, salt);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static verifySignatureByString(params, key, checksum) {
|
|
56
|
+
var paytm_hash = PaytmChecksum.decrypt(checksum, key);
|
|
57
|
+
var salt = paytm_hash.substr(paytm_hash.length - 4);
|
|
58
|
+
return (paytm_hash === PaytmChecksum.calculateHash(params, salt));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static generateRandomString(length) {
|
|
62
|
+
return new Promise(function (resolve, reject) {
|
|
63
|
+
crypto.randomBytes((length * 3.0) / 4.0, function (err, buf) {
|
|
64
|
+
if (!err) {
|
|
65
|
+
var salt = buf.toString("base64");
|
|
66
|
+
resolve(salt);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
console.log("error occurred in generateRandomString: " + err);
|
|
70
|
+
reject(err);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static getStringByParams(params) {
|
|
77
|
+
var data = {};
|
|
78
|
+
Object.keys(params).sort().forEach(function(key,value) {
|
|
79
|
+
data[key] = (params[key] !== null && params[key].toLowerCase() !== "null") ? params[key] : "";
|
|
80
|
+
});
|
|
81
|
+
return Object.values(data).join('|');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
static calculateHash(params, salt) {
|
|
85
|
+
var finalString = params + "|" + salt;
|
|
86
|
+
return crypto.createHash('sha256').update(finalString).digest('hex') + salt;
|
|
87
|
+
}
|
|
88
|
+
static calculateChecksum(params, key, salt) {
|
|
89
|
+
var hashString = PaytmChecksum.calculateHash(params, salt);
|
|
90
|
+
return PaytmChecksum.encrypt(hashString,key);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
PaytmChecksum.iv = '@@@@&&&&####$$$$';
|
|
94
|
+
module.exports = PaytmChecksum;
|
|
@@ -15,14 +15,17 @@ module.exports = function (app, callbacks) {
|
|
|
15
15
|
var module = {};
|
|
16
16
|
var config = (app.get('np_config'))
|
|
17
17
|
|
|
18
|
+
let usingMultiDbOrm = false;
|
|
18
19
|
if (config.db_url) {
|
|
19
20
|
User = require('../models/np_user.model.js');
|
|
21
|
+
usingMultiDbOrm = false;
|
|
20
22
|
} else if (app.multidborm) {
|
|
21
23
|
User = require('../models/np_multidbplugin.js')('npusers',app.multidborm);
|
|
22
24
|
User.db=app.multidborm;
|
|
23
25
|
User.modelname='npusers'
|
|
24
26
|
User.idFieldName='id'
|
|
25
27
|
app.NPUser = User;
|
|
28
|
+
usingMultiDbOrm = true;
|
|
26
29
|
}
|
|
27
30
|
module.create = (userData, cb) => {
|
|
28
31
|
|
|
@@ -55,7 +58,7 @@ module.exports = function (app, callbacks) {
|
|
|
55
58
|
|
|
56
59
|
// console.log("User New : ",userData.name);
|
|
57
60
|
|
|
58
|
-
userData.id = makeid(IDLEN);
|
|
61
|
+
userData.id = "user_"+makeid(IDLEN);
|
|
59
62
|
var userTask = new User(userData);
|
|
60
63
|
userTask.save()
|
|
61
64
|
.then(user => {
|
|
@@ -69,7 +72,7 @@ module.exports = function (app, callbacks) {
|
|
|
69
72
|
|
|
70
73
|
}
|
|
71
74
|
|
|
72
|
-
},User);
|
|
75
|
+
},usingMultiDbOrm ? User : undefined);
|
|
73
76
|
|
|
74
77
|
};
|
|
75
78
|
return module;
|
|
@@ -5,6 +5,9 @@ var Transaction;
|
|
|
5
5
|
var IDLEN = 10;
|
|
6
6
|
var nodeBase64 = require('nodejs-base64-converter');
|
|
7
7
|
var RazorPay = require('razorpay');
|
|
8
|
+
const PaytmChecksum = require('./checksum/PaytmChecksum.js');
|
|
9
|
+
const { stat } = require('fs');
|
|
10
|
+
|
|
8
11
|
|
|
9
12
|
function sanitizeRequest(body) {
|
|
10
13
|
|
|
@@ -21,14 +24,19 @@ module.exports = function (app, callbacks) {
|
|
|
21
24
|
if (config.razor_url)
|
|
22
25
|
var razorPayInstance = new RazorPay({ key_id: config.KEY, key_secret: config.SECRET })
|
|
23
26
|
|
|
27
|
+
let usingMultiDbOrm = false;
|
|
24
28
|
if (config.db_url) {
|
|
25
29
|
Transaction = require('../models/np_transaction.model.js');
|
|
30
|
+
usingMultiDbOrm = false;
|
|
31
|
+
|
|
26
32
|
} else if (app.multidborm) {
|
|
27
33
|
Transaction = require('../models/np_multidbplugin.js')('nptransactions', app.multidborm);
|
|
28
34
|
Transaction.db = app.multidborm;
|
|
29
35
|
Transaction.modelname = 'nptransactions'
|
|
30
36
|
Transaction.idFieldName = 'orderId'
|
|
31
37
|
app.NPTransaction = Transaction;
|
|
38
|
+
usingMultiDbOrm = true;
|
|
39
|
+
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
var module = {};
|
|
@@ -101,7 +109,7 @@ module.exports = function (app, callbacks) {
|
|
|
101
109
|
params['ORDER_ID'] = req.body.ORDER_ID;
|
|
102
110
|
params['CUST_ID'] = req.body.CUST_ID;
|
|
103
111
|
params['TXN_AMOUNT'] = req.body.TXN_AMOUNT;
|
|
104
|
-
params['CALLBACK_URL'] = req.body.CALLBACK_URL;
|
|
112
|
+
params['CALLBACK_URL'] = req.body.CALLBACK_URL + "?order_id=" + req.body.ORDER_ID;
|
|
105
113
|
params['EMAIL'] = req.body.EMAIL;
|
|
106
114
|
params['MOBILE_NO'] = req.body.MOBILE_NO;
|
|
107
115
|
params['PRODUCT_NAME'] = req.body.PRODUCT_NAME;
|
|
@@ -109,24 +117,244 @@ module.exports = function (app, callbacks) {
|
|
|
109
117
|
|
|
110
118
|
if (config.paytm_url) {
|
|
111
119
|
|
|
120
|
+
let initTxnbody = {
|
|
121
|
+
"requestType": "Payment",
|
|
122
|
+
"mid": params['MID'],
|
|
123
|
+
"websiteName": params['WEBSITE'],
|
|
124
|
+
"orderId": params['ORDER_ID'],
|
|
125
|
+
"callbackUrl": params['CALLBACK_URL'],
|
|
126
|
+
"txnAmount": {
|
|
127
|
+
"value": params['TXN_AMOUNT'],
|
|
128
|
+
"currency": params['CURRENCY'] || "INR",
|
|
129
|
+
},
|
|
130
|
+
"userInfo": {
|
|
131
|
+
"custId": params['CUST_ID'],
|
|
132
|
+
"mobile": params['MOBILE_NO'],
|
|
133
|
+
"firstName": params['NAME'],
|
|
134
|
+
"email": params['EMAIL']
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
let checksum = await PaytmChecksum.generateSignature(JSON.stringify(initTxnbody), config.KEY)
|
|
138
|
+
let initTxnUrl = config.paytm_url + `/theia/api/v1/initiateTransaction?mid=${params['MID']}&orderId=${params['ORDER_ID']}`;
|
|
139
|
+
|
|
140
|
+
request.post(
|
|
141
|
+
initTxnUrl,
|
|
142
|
+
{
|
|
143
|
+
json: {
|
|
144
|
+
"body": initTxnbody,
|
|
145
|
+
"head": {
|
|
146
|
+
"signature": checksum,
|
|
147
|
+
"channelId": params['CHANNEL_ID']
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
function (error, response, body) {
|
|
112
152
|
|
|
113
|
-
|
|
153
|
+
if (!error && response.statusCode != undefined
|
|
154
|
+
&& response.statusCode != NaN &&
|
|
155
|
+
response.statusCode == 200 &&
|
|
156
|
+
body.body &&
|
|
157
|
+
body.body.resultInfo &&
|
|
158
|
+
body.body.resultInfo.resultStatus == "S") {
|
|
114
159
|
|
|
115
160
|
|
|
116
|
-
|
|
161
|
+
let paytmJsCheckouHtml = `<html>
|
|
162
|
+
<head>
|
|
163
|
+
<title>Merchant Checkout</title>
|
|
164
|
+
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0"/>
|
|
165
|
+
|
|
166
|
+
</head>
|
|
167
|
+
<body>
|
|
168
|
+
<center>
|
|
169
|
+
<h1>Please donot close this page or press the back button. Processing...</h1>
|
|
170
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin:auto;background:#fff;display:block;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
|
|
171
|
+
<g transform="rotate(0 50 50)">
|
|
172
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#fe718d">
|
|
173
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.9166666666666666s" repeatCount="indefinite"></animate>
|
|
174
|
+
</rect>
|
|
175
|
+
</g><g transform="rotate(30 50 50)">
|
|
176
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#fe718d">
|
|
177
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.8333333333333334s" repeatCount="indefinite"></animate>
|
|
178
|
+
</rect>
|
|
179
|
+
</g><g transform="rotate(60 50 50)">
|
|
180
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#fe718d">
|
|
181
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.75s" repeatCount="indefinite"></animate>
|
|
182
|
+
</rect>
|
|
183
|
+
</g><g transform="rotate(90 50 50)">
|
|
184
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#fe718d">
|
|
185
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.6666666666666666s" repeatCount="indefinite"></animate>
|
|
186
|
+
</rect>
|
|
187
|
+
</g><g transform="rotate(120 50 50)">
|
|
188
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#fe718d">
|
|
189
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.5833333333333334s" repeatCount="indefinite"></animate>
|
|
190
|
+
</rect>
|
|
191
|
+
</g><g transform="rotate(150 50 50)">
|
|
192
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#fe718d">
|
|
193
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.5s" repeatCount="indefinite"></animate>
|
|
194
|
+
</rect>
|
|
195
|
+
</g><g transform="rotate(180 50 50)">
|
|
196
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#fe718d">
|
|
197
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.4166666666666667s" repeatCount="indefinite"></animate>
|
|
198
|
+
</rect>
|
|
199
|
+
</g><g transform="rotate(210 50 50)">
|
|
200
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#fe718d">
|
|
201
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.3333333333333333s" repeatCount="indefinite"></animate>
|
|
202
|
+
</rect>
|
|
203
|
+
</g><g transform="rotate(240 50 50)">
|
|
204
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#fe718d">
|
|
205
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.25s" repeatCount="indefinite"></animate>
|
|
206
|
+
</rect>
|
|
207
|
+
</g><g transform="rotate(270 50 50)">
|
|
208
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#fe718d">
|
|
209
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.16666666666666666s" repeatCount="indefinite"></animate>
|
|
210
|
+
</rect>
|
|
211
|
+
</g><g transform="rotate(300 50 50)">
|
|
212
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#fe718d">
|
|
213
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.08333333333333333s" repeatCount="indefinite"></animate>
|
|
214
|
+
</rect>
|
|
215
|
+
</g><g transform="rotate(330 50 50)">
|
|
216
|
+
<rect x="47" y="24" rx="3" ry="6" width="6" height="12" fill="#fe718d">
|
|
217
|
+
<animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="0s" repeatCount="indefinite"></animate>
|
|
218
|
+
</rect>
|
|
219
|
+
</g>
|
|
220
|
+
</svg>
|
|
221
|
+
</center>
|
|
222
|
+
<form id="cancelform" action="${params['CALLBACK_URL']}" method="post">
|
|
223
|
+
<input type="hidden" name="TXNID" value="na"/>
|
|
224
|
+
<input type="hidden" name="STATUS" value="TXN_FAILURE"/>
|
|
225
|
+
<input type="hidden" name="CANCELLED" value="cancelled"/>
|
|
226
|
+
<input id="RESPMSG" type="hidden" name="RESPMSG" value=""/>
|
|
227
|
+
<input type="hidden" name="ORDERID" value="${params["ORDER_ID"]}"/>
|
|
228
|
+
</form>
|
|
229
|
+
|
|
117
230
|
|
|
118
|
-
|
|
119
|
-
var form_fields = "";
|
|
120
|
-
for (var x in params) {
|
|
121
|
-
form_fields += "<input type='hidden' name='" + x + "' value='" + params[x] + "' >";
|
|
122
|
-
}
|
|
123
|
-
form_fields += "<input type='hidden' name='CHECKSUMHASH' value='" + checksum + "' >";
|
|
231
|
+
<script>
|
|
124
232
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
233
|
+
function getBodyColor(color){
|
|
234
|
+
const hex = color.replace('#', '');
|
|
235
|
+
const c_r = parseInt(hex.substr(0, 2), 16);
|
|
236
|
+
const c_g = parseInt(hex.substr(2, 2), 16);
|
|
237
|
+
const c_b = parseInt(hex.substr(4, 2), 16);
|
|
238
|
+
const brightness = ((c_r * 299) + (c_g * 587) + (c_b * 114)) / 1000;
|
|
239
|
+
// console.log(brightness , brightness > 155 ? "#fff" : "#1a1a1c")
|
|
240
|
+
return brightness > 155 ? "#1a1a1c" : "#ffffff";
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function shadeColor(color, percent) {
|
|
244
|
+
|
|
245
|
+
var R = parseInt(color.substring(1,3),16);
|
|
246
|
+
var G = parseInt(color.substring(3,5),16);
|
|
247
|
+
var B = parseInt(color.substring(5,7),16);
|
|
248
|
+
|
|
249
|
+
R = parseInt(R * (100 + percent) / 100);
|
|
250
|
+
G = parseInt(G * (100 + percent) / 100);
|
|
251
|
+
B = parseInt(B * (100 + percent) / 100);
|
|
252
|
+
|
|
253
|
+
R = (R<255)?R:255;
|
|
254
|
+
G = (G<255)?G:255;
|
|
255
|
+
B = (B<255)?B:255;
|
|
256
|
+
|
|
257
|
+
var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16));
|
|
258
|
+
var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16));
|
|
259
|
+
var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16));
|
|
260
|
+
|
|
261
|
+
return "#"+RR+GG+BB;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function failTxn(reason) {
|
|
265
|
+
var form = document.getElementById("cancelform");
|
|
266
|
+
var element2 = document.getElementById("RESPMSG");
|
|
267
|
+
element2.value=reason;
|
|
268
|
+
form.submit();
|
|
269
|
+
}
|
|
270
|
+
function onScriptLoad(){
|
|
271
|
+
var config = {
|
|
272
|
+
"root": "",
|
|
273
|
+
"flow": "DEFAULT",
|
|
274
|
+
"style": {
|
|
275
|
+
// "bodyColor": shadeColor("${config.theme_color}",+40),
|
|
276
|
+
"themeBackgroundColor": "${config.theme_color}",
|
|
277
|
+
"themeColor": getBodyColor("${config.theme_color}"),
|
|
278
|
+
"headerBackgroundColor": "${config.theme_color}",
|
|
279
|
+
"headerColor": getBodyColor("${config.theme_color}")
|
|
280
|
+
},
|
|
281
|
+
"data": {
|
|
282
|
+
"orderId": "${params['ORDER_ID']}", /* update order id */
|
|
283
|
+
"token": "${body.body.txnToken}", /* update token value */
|
|
284
|
+
"tokenType": "TXN_TOKEN",
|
|
285
|
+
"amount": "${params['TXN_AMOUNT']}" /* update amount */
|
|
286
|
+
},
|
|
287
|
+
"handler": {
|
|
288
|
+
"notifyMerchant": function(eventName,data){
|
|
289
|
+
// console.log("notifyMerchant handler function called");
|
|
290
|
+
// console.log("eventName => ",eventName);
|
|
291
|
+
// console.log("data => ",data);
|
|
292
|
+
if(eventName == "APP_CLOSED"){
|
|
293
|
+
failTxn(eventName)
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
if(window.Paytm && window.Paytm.CheckoutJS){
|
|
300
|
+
window.Paytm.CheckoutJS.onLoad(function excecuteAfterCompleteLoad() {
|
|
301
|
+
// initialze configuration using init method
|
|
302
|
+
window.Paytm.CheckoutJS.init(config).then(function onSuccess() {
|
|
303
|
+
// after successfully updating configuration, invoke JS Checkout
|
|
304
|
+
window.Paytm.CheckoutJS.invoke();
|
|
305
|
+
}).catch(function onError(error){
|
|
306
|
+
// console.log("error => ",error);
|
|
307
|
+
failTxn(error.message)
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
</script>
|
|
313
|
+
<script type="application/javascript" crossorigin="anonymous" src="${config.paytm_url}/merchantpgpui/checkoutjs/merchants/${params['MID']}.js" onload="onScriptLoad();" crossorigin="anonymous"></script>
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
</body>
|
|
317
|
+
</html>`
|
|
318
|
+
return res.send(paytmJsCheckouHtml)
|
|
319
|
+
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
console.log('ERROR:::', error, '\n', body);
|
|
323
|
+
res.status(500)
|
|
324
|
+
var form_fields = "";
|
|
325
|
+
let errorResp = {
|
|
326
|
+
TXNID: "na",
|
|
327
|
+
STATUS: "TXN_FAILURE",
|
|
328
|
+
CANCELLED: "cancelled",
|
|
329
|
+
ORDERID: params["ORDER_ID"]
|
|
330
|
+
}
|
|
331
|
+
for (var x in errorResp) {
|
|
332
|
+
form_fields += "<input type='hidden' name='" + x + "' value='" + errorResp[x] + "' >";
|
|
333
|
+
}
|
|
334
|
+
form_fields += "<input type='hidden' name='CHECKSUMHASH' value='" + checksum + "' >";
|
|
335
|
+
|
|
336
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
337
|
+
res.write(`<html>
|
|
338
|
+
|
|
339
|
+
<head>
|
|
340
|
+
<title>Merchant Checkout Error</title>
|
|
341
|
+
</head>
|
|
342
|
+
|
|
343
|
+
<body>
|
|
344
|
+
<center>
|
|
345
|
+
<h1>Something went wrong. Please wait you will be redirected automatically...</h1>
|
|
346
|
+
</center>
|
|
347
|
+
<form method="post" action="${params['CALLBACK_URL']}" name="f1">${form_fields}</form>
|
|
348
|
+
<script type="text/javascript">document.f1.submit();</script>
|
|
349
|
+
</body>
|
|
350
|
+
|
|
351
|
+
</html>`);
|
|
352
|
+
res.end();
|
|
353
|
+
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
);
|
|
128
357
|
|
|
129
|
-
});
|
|
130
358
|
}
|
|
131
359
|
else if (config.razor_url) {
|
|
132
360
|
|
|
@@ -246,7 +474,7 @@ module.exports = function (app, callbacks) {
|
|
|
246
474
|
|
|
247
475
|
onTxn(objForUpdate);
|
|
248
476
|
|
|
249
|
-
}, Transaction);
|
|
477
|
+
}, usingMultiDbOrm ? Transaction : undefined);
|
|
250
478
|
|
|
251
479
|
|
|
252
480
|
|
|
@@ -261,6 +489,7 @@ module.exports = function (app, callbacks) {
|
|
|
261
489
|
orderId: orderId,
|
|
262
490
|
cusId: user.id,
|
|
263
491
|
time: Date.now(),
|
|
492
|
+
timeStamp: Date.now(),
|
|
264
493
|
status: 'INITIATED',
|
|
265
494
|
name: user.name,
|
|
266
495
|
email: user.email,
|
|
@@ -282,7 +511,7 @@ module.exports = function (app, callbacks) {
|
|
|
282
511
|
|
|
283
512
|
let orderId;
|
|
284
513
|
if (config.paytm_url) {
|
|
285
|
-
orderId = makeid(config.id_length || IDLEN)
|
|
514
|
+
orderId = "pay_" + makeid(config.id_length || IDLEN)
|
|
286
515
|
onOrder(orderId)
|
|
287
516
|
}
|
|
288
517
|
else if (config.razor_url) {
|
|
@@ -296,7 +525,7 @@ module.exports = function (app, callbacks) {
|
|
|
296
525
|
|
|
297
526
|
razorPayInstance.orders.create(options, function (err, order) {
|
|
298
527
|
if (err) {
|
|
299
|
-
res.send({ message: "An error occurred ! " + err.
|
|
528
|
+
res.send({ message: "An error occurred ! " + err.description })
|
|
300
529
|
return;
|
|
301
530
|
}
|
|
302
531
|
orderId = order.id
|
|
@@ -346,6 +575,44 @@ module.exports = function (app, callbacks) {
|
|
|
346
575
|
|
|
347
576
|
}
|
|
348
577
|
|
|
578
|
+
function updateTransaction(req, res) {
|
|
579
|
+
var myquery = { orderId: req.body.ORDERID };
|
|
580
|
+
|
|
581
|
+
Transaction.findOne(myquery, function (err, objForUpdate) {
|
|
582
|
+
|
|
583
|
+
if (err) {
|
|
584
|
+
res.send({ message: "Transaction Not Found !", ORDERID: req.body.ORDERID, TXNID: req.body.TXNID })
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
if (objForUpdate.status != ("INITIATED") && objForUpdate.status != ("TXN_PENDING")) {
|
|
588
|
+
res.send({ message: "Transaction already processed", status: objForUpdate.status, ORDERID: objForUpdate.orderId, TXNID: objForUpdate.TXNID, TXNID: req.body.TXNID })
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
if (req.body.status == "paid" && !req.body.STATUS) {
|
|
592
|
+
req.body.STATUS = "TXN_SUCCESS"
|
|
593
|
+
}
|
|
594
|
+
objForUpdate.status = req.body.STATUS;
|
|
595
|
+
objForUpdate.TXNID = req.body.TXNID;
|
|
596
|
+
objForUpdate.extra = JSON.stringify(req.body);
|
|
597
|
+
|
|
598
|
+
var newvalues = { $set: objForUpdate };
|
|
599
|
+
Transaction.updateOne(myquery, newvalues, function (err, saveRes) {
|
|
600
|
+
|
|
601
|
+
if (err) {
|
|
602
|
+
res.send({ message: "Error Occured !", ORDERID: req.body.ORDERID, TXNID: req.body.TXNID })
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
|
|
606
|
+
if (callbacks !== undefined)
|
|
607
|
+
callbacks.onFinish(req.body.ORDERID, req.body);
|
|
608
|
+
objForUpdate.readonly = "readonly"
|
|
609
|
+
objForUpdate.action = config.homepage
|
|
610
|
+
res.render(vp + "result.hbs", objForUpdate);
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
}, usingMultiDbOrm ? Transaction : undefined)
|
|
615
|
+
}
|
|
349
616
|
|
|
350
617
|
module.callback = (req, res) => {
|
|
351
618
|
|
|
@@ -354,6 +621,10 @@ module.exports = function (app, callbacks) {
|
|
|
354
621
|
if (config.paytm_url) {
|
|
355
622
|
var checksumhash = req.body.CHECKSUMHASH;
|
|
356
623
|
result = checksum_lib.verifychecksum(req.body, config.KEY, checksumhash);
|
|
624
|
+
if (req.body.STATUS == 'TXN_FAILURE' && req.body.CANCELLED == "cancelled" && req.body.TXNID) {
|
|
625
|
+
isCancelled = true;
|
|
626
|
+
}
|
|
627
|
+
|
|
357
628
|
}
|
|
358
629
|
else if (config.razor_url) {
|
|
359
630
|
|
|
@@ -374,7 +645,7 @@ module.exports = function (app, callbacks) {
|
|
|
374
645
|
req.body.razorpay_order_id = orderId
|
|
375
646
|
}
|
|
376
647
|
req.body.STATUS = 'TXN_FAILURE'
|
|
377
|
-
req.body.ORDERID = req.body.razorpay_order_id
|
|
648
|
+
req.body.ORDERID = req.body.razorpay_order_id || req.query.order_id
|
|
378
649
|
isCancelled = true;
|
|
379
650
|
}
|
|
380
651
|
}
|
|
@@ -385,34 +656,7 @@ module.exports = function (app, callbacks) {
|
|
|
385
656
|
|
|
386
657
|
if (result || isCancelled) {
|
|
387
658
|
|
|
388
|
-
|
|
389
|
-
Transaction.findOne(myquery, function (err, objForUpdate) {
|
|
390
|
-
|
|
391
|
-
if (err) {
|
|
392
|
-
res.send({ message: "Transaction Not Found !", ORDERID: req.body.ORDERID, TXNID: req.body.TXNID })
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
objForUpdate.status = req.body.STATUS;
|
|
396
|
-
objForUpdate.TXNID = req.body.TXNID;
|
|
397
|
-
objForUpdate.extra = JSON.stringify(req.body);
|
|
398
|
-
|
|
399
|
-
var newvalues = { $set: objForUpdate };
|
|
400
|
-
Transaction.updateOne(myquery, newvalues, function (err, saveRes) {
|
|
401
|
-
|
|
402
|
-
if (err) {
|
|
403
|
-
res.send({ message: "Error Occured !", ORDERID: req.body.ORDERID, TXNID: req.body.TXNID })
|
|
404
|
-
}
|
|
405
|
-
else {
|
|
406
|
-
|
|
407
|
-
if (callbacks !== undefined)
|
|
408
|
-
callbacks.onFinish(req.body.ORDERID, req.body);
|
|
409
|
-
objForUpdate.readonly = "readonly"
|
|
410
|
-
objForUpdate.action = config.homepage
|
|
411
|
-
res.render(vp + "result.hbs", objForUpdate);
|
|
412
|
-
}
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
}, Transaction)
|
|
659
|
+
updateTransaction(req, res);
|
|
416
660
|
|
|
417
661
|
}
|
|
418
662
|
else {
|
|
@@ -423,6 +667,61 @@ module.exports = function (app, callbacks) {
|
|
|
423
667
|
|
|
424
668
|
}
|
|
425
669
|
|
|
670
|
+
module.webhook = (req, res) => {
|
|
671
|
+
if (config.paytm_url) {
|
|
672
|
+
module.callback(req, res)
|
|
673
|
+
}
|
|
674
|
+
else if (config.razor_url) {
|
|
675
|
+
let events = ["payment.captured", "payment.pending", "payment.failed"]
|
|
676
|
+
if (req.body.event && events.indexOf(req.body.event) > -1) {
|
|
677
|
+
if (req.body.payload &&
|
|
678
|
+
req.body.payload.payment &&
|
|
679
|
+
req.body.payload.payment.entity) {
|
|
680
|
+
|
|
681
|
+
let entity = req.body.payload.payment.entity;
|
|
682
|
+
let razorpay_order_id = entity.order_id;
|
|
683
|
+
let razorpay_payment_id = entity.id;
|
|
684
|
+
let status = entity.status;
|
|
685
|
+
let event = req.body.event;
|
|
686
|
+
console.log(`Razorpay webhook payment order=${razorpay_order_id} payid=${razorpay_payment_id} status=${status}`)
|
|
687
|
+
|
|
688
|
+
let reqBody = req.rawBody, signature = req.headers["x-razorpay-signature"];
|
|
689
|
+
|
|
690
|
+
result = RazorPay.validateWebhookSignature(reqBody, req.headers['x-razorpay-signature'], config.SECRET)
|
|
691
|
+
req.signatureVerified = result;
|
|
692
|
+
if (true) {
|
|
693
|
+
if (event == events[0]) {
|
|
694
|
+
req.body.STATUS = "TXN_SUCCESS";
|
|
695
|
+
}
|
|
696
|
+
else if (event == events[1]) { //pending
|
|
697
|
+
req.body.STATUS = "TXN_PENDING";
|
|
698
|
+
}
|
|
699
|
+
else { // failed
|
|
700
|
+
req.body.STATUS = "TXN_FAILURE";
|
|
701
|
+
}
|
|
702
|
+
req.body.ORDERID = razorpay_order_id;
|
|
703
|
+
req.body.TXNID = razorpay_payment_id;
|
|
704
|
+
setTimeout(() => {
|
|
705
|
+
updateTransaction(req, res)
|
|
706
|
+
}, 3000)
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
res.status(401)
|
|
710
|
+
res.send({ message: "Invalid Rzpay signature" })
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
else {
|
|
714
|
+
res.status(400)
|
|
715
|
+
res.send({ message: "Invalid Payload" })
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
else {
|
|
719
|
+
res.status(400)
|
|
720
|
+
res.send({ message: "Unsupported event : " + req.body.event })
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
426
725
|
module.createTxn = (req, res) => {
|
|
427
726
|
|
|
428
727
|
|
|
@@ -432,7 +731,7 @@ module.exports = function (app, callbacks) {
|
|
|
432
731
|
|
|
433
732
|
let id;
|
|
434
733
|
if (config.paytm_url) {
|
|
435
|
-
id = makeid(config.id_length || IDLEN)
|
|
734
|
+
id = "pay_" + makeid(config.id_length || IDLEN)
|
|
436
735
|
}
|
|
437
736
|
else if (config.razor_url) {
|
|
438
737
|
|
|
@@ -575,7 +874,7 @@ module.exports = function (app, callbacks) {
|
|
|
575
874
|
}
|
|
576
875
|
|
|
577
876
|
|
|
578
|
-
}, Transaction);
|
|
877
|
+
}, usingMultiDbOrm ? Transaction : undefined);
|
|
579
878
|
|
|
580
879
|
|
|
581
880
|
}
|
|
@@ -49,19 +49,21 @@ module.exports = (app, express, callbacks) => {
|
|
|
49
49
|
|
|
50
50
|
app.set('view engine', 'handlebars');
|
|
51
51
|
|
|
52
|
+
let saveRawBody = function (req, res, buf, encoding) {
|
|
53
|
+
req.rawBody = buf.toString();
|
|
54
|
+
}
|
|
52
55
|
app.use(bodyParser.urlencoded({ extended: true }))
|
|
53
|
-
app.use(bodyParser.json())
|
|
56
|
+
app.use(bodyParser.json({ verify: saveRawBody }))
|
|
57
|
+
|
|
54
58
|
app.use("/" + config.path_prefix, express.static(path.join(__dirname, '../../public')));
|
|
55
59
|
app.use('/' + config.path_prefix, router);
|
|
56
60
|
|
|
57
|
-
router.all('/',
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
});
|
|
61
|
+
router.all('/', pc.init);
|
|
62
|
+
router.all('/init', pc.init);
|
|
61
63
|
|
|
62
|
-
router.all('/home', pc.home)
|
|
63
|
-
router.all('/init', pc.init)
|
|
64
|
+
// router.all('/home', pc.home)
|
|
64
65
|
router.all('/callback', pc.callback)
|
|
66
|
+
router.all('/api/webhook', pc.webhook)
|
|
65
67
|
router.all('/api/status', pc.status)
|
|
66
68
|
router.all('/api/createTxn', pc.createTxn)
|
|
67
69
|
|
package/app/views/home.hbs
CHANGED
package/example.js
CHANGED
package/package.json
CHANGED