refs #5122 Hotfix: Signature verification
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Juan Ferrer 2023-01-30 17:33:15 +01:00
parent 109556ae2e
commit 5744759d53
3 changed files with 85 additions and 8 deletions

View File

@ -1,3 +1,6 @@
const crypto = require('crypto');
const UserError = require('vn-loopback/util/user-error');
const base64url = require('base64url');
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('confirm', { Self.remoteMethod('confirm', {
@ -7,7 +10,7 @@ module.exports = Self => {
{ {
arg: 'Ds_SignatureVersion', arg: 'Ds_SignatureVersion',
type: 'string', type: 'string',
required: true, required: false,
}, { }, {
arg: 'Ds_MerchantParameters', arg: 'Ds_MerchantParameters',
type: 'string', type: 'string',
@ -28,15 +31,64 @@ module.exports = Self => {
} }
}); });
/*
* Source: https://github.com/santiperez/node-redsys-api
*/
Self.confirm = async(signatureVersion, merchantParameters, signature) => { Self.confirm = async(signatureVersion, merchantParameters, signature) => {
const buffer = Buffer.from(merchantParameters, 'base64'); const $ = Self.app.models;
const params = JSON.parse(buffer.toString());
console.debug('Payment confirmation received:', params); const decodedParams = JSON.parse(
base64url.decode(merchantParameters, 'utf8'));
const params = {};
for (const param in decodedParams)
params[param] = decodeURIComponent(decodedParams[param]);
console.debug('Payment confirmation received:', {
signatureVersion,
merchantParameters,
signature,
params
});
const orderId = params['Ds_Order'];
const merchantId = parseInt(params['Ds_MerchantCode']);
if (!orderId)
throw new UserError('Order id not found');
if (!merchantId)
throw new UserError('Mechant id not found');
const merchant = await $.TpvMerchant.findById(merchantId, {
fields: ['id', 'secretKey']
});
const secretKey = Buffer.from(merchant.secretKey, 'base64');
const iv = Buffer.alloc(8, 0);
const cipher = crypto.createDecipheriv('des-ede3-cbc', secretKey, iv);
cipher.setAutoPadding(false);
const orderKey = cipher.update(zeroPad(str, 8), 'utf8', 'base64')
+ cipher.final('utf8');
const res = crypto.createHmac('sha256', Buffer.from(orderKey, 'base64'))
.update(merchantParameters)
.digest('base64');
const base64Res = base64url.encode(res, 'base64');
// if (base64Res !== signature)
// throw new UserError('Invalid signature');
console.debug('Payment signature:', {
res,
base64Res
});
await Self.rawSql( await Self.rawSql(
'CALL hedera.tpvTransaction_confirm(?, ?, ?, ?, ?, ?)', [ 'CALL hedera.tpvTransaction_confirm(?, ?, ?, ?, ?, ?)', [
params['Ds_Amount'], params['Ds_Amount'],
params['Ds_Order'], orderId,
params['Ds_MerchantCode'], merchantId,
params['Ds_Currency'], params['Ds_Currency'],
params['Ds_Response'], params['Ds_Response'],
params['Ds_ErrorCode'] params['Ds_ErrorCode']
@ -44,4 +96,14 @@ module.exports = Self => {
); );
return true; return true;
}; };
function zeroPad(buf, blocksize) {
const buffer = typeof buf === 'string' ? Buffer.from(buf, 'utf8') : buf;
const pad = Buffer.alloc((blocksize - (buffer.length % blocksize)) % blocksize, 0);
return Buffer.concat([buffer, pad]);
}
function base64UrlDecode() {
}
}; };

18
package-lock.json generated
View File

@ -1,15 +1,16 @@
{ {
"name": "salix-back", "name": "salix-back",
"version": "9.0.0", "version": "23.02.03",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "salix-back", "name": "salix-back",
"version": "9.0.0", "version": "23.02.03",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"axios": "^1.2.2", "axios": "^1.2.2",
"base64url": "^3.0.1",
"bcrypt": "^5.0.1", "bcrypt": "^5.0.1",
"bmp-js": "^0.1.0", "bmp-js": "^0.1.0",
"compression": "^1.7.3", "compression": "^1.7.3",
@ -4200,6 +4201,14 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/base64url": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz",
"integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/batch": { "node_modules/batch": {
"version": "0.6.1", "version": "0.6.1",
"dev": true, "dev": true,
@ -29057,6 +29066,11 @@
"base64-js": { "base64-js": {
"version": "1.0.2" "version": "1.0.2"
}, },
"base64url": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz",
"integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A=="
},
"batch": { "batch": {
"version": "0.6.1", "version": "0.6.1",
"dev": true "dev": true

View File

@ -13,6 +13,7 @@
}, },
"dependencies": { "dependencies": {
"axios": "^1.2.2", "axios": "^1.2.2",
"base64url": "^3.0.1",
"bcrypt": "^5.0.1", "bcrypt": "^5.0.1",
"bmp-js": "^0.1.0", "bmp-js": "^0.1.0",
"compression": "^1.7.3", "compression": "^1.7.3",