first commit

This commit is contained in:
tusuii
2026-02-19 17:25:38 +05:30
commit 09ea6d4efb
72 changed files with 24296 additions and 0 deletions

34
src/utils/mailer.js Normal file
View File

@@ -0,0 +1,34 @@
const nodemailer = require('nodemailer');
const ejs = require('ejs');
const path = require('path');
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS,
},
});
const sendEmail = async (to, subject, templateName, templateData) => {
// Render EJS template
const templatePath = path.join(__dirname, '../views/emails', `${templateName}.ejs`);
const html = await ejs.renderFile(templatePath, templateData);
const mailOptions = {
from: `"VC E-Commerce" <${process.env.EMAIL_USER}>`,
to,
subject,
html,
};
try {
await transporter.sendMail(mailOptions);
console.log('Email sent to', to);
} catch (err) {
console.error('Error sending email', err);
throw new Error('Failed to send email');
}
};
module.exports = sendEmail;

315
src/utils/paytm.js Normal file
View File

@@ -0,0 +1,315 @@
// utils/paytm.js
const https = require('https');
const crypto = require('crypto');
/**
* Paytm Configuration
* Add these to your .env file:
* PAYTM_MERCHANT_ID=your_merchant_id
* PAYTM_MERCHANT_KEY=your_merchant_key
* PAYTM_WEBSITE=WEBSTAGING (for staging) or your website name
* PAYTM_CHANNEL_ID=WEB
* PAYTM_INDUSTRY_TYPE=Retail
* PAYTM_HOST=securegw-stage.paytm.in (for staging) or securegw.paytm.in (for production)
*/
const PaytmConfig = {
mid: process.env.PAYTM_MERCHANT_ID,
key: process.env.PAYTM_MERCHANT_KEY,
website: process.env.PAYTM_WEBSITE || 'WEBSTAGING',
channelId: process.env.PAYTM_CHANNEL_ID || 'WEB',
industryType: process.env.PAYTM_INDUSTRY_TYPE || 'Retail',
host: process.env.PAYTM_HOST || 'securegw-stage.paytm.in',
callbackUrl: process.env.PAYTM_CALLBACK_URL || 'http://localhost:3000/api/payments/paytm/callback',
};
console.log(
'Merchant Key Length:',
process.env.PAYTM_MERCHANT_KEY.length
);
/**
* Generate Paytm Checksum
*/
const generateChecksum = (params, merchantKey) => {
return new Promise((resolve, reject) => {
try {
const data = JSON.stringify(params);
const salt = crypto.randomBytes(4).toString('hex');
const hash = crypto
.createHash('sha256')
.update(data + salt)
.digest('hex');
const checksum = hash + salt;
const encryptedChecksum = encrypt(checksum, merchantKey);
resolve(encryptedChecksum);
} catch (err) {
reject(err);
}
});
};
/**
* Verify Paytm Checksum
*/
const verifyChecksum = (params, merchantKey, checksumHash) => {
return new Promise((resolve, reject) => {
try {
const decrypted = decrypt(checksumHash, merchantKey);
const salt = decrypted.slice(-8);
const hash = crypto
.createHash('sha256')
.update(JSON.stringify(params) + salt)
.digest('hex');
resolve(hash + salt === decrypted);
} catch (err) {
reject(err);
}
});
};
/**
* Encrypt data using AES-128-CBC (Paytm standard)
*/
const encrypt = (data, key) => {
if (key.length !== 16) {
throw new Error('Paytm Merchant Key must be exactly 16 characters');
}
const iv = Buffer.from('@@@@&&&&####$$$$'); // Paytm fixed IV
const cipher = crypto.createCipheriv(
'aes-128-cbc',
Buffer.from(key, 'utf8'),
iv
);
let encrypted = cipher.update(data, 'utf8', 'base64');
encrypted += cipher.final('base64');
return encrypted;
};
/**
* Decrypt data using AES-128-CBC
*/
const decrypt = (encryptedData, key) => {
const iv = Buffer.from('@@@@&&&&####$$$$');
const decipher = crypto.createDecipheriv(
'aes-128-cbc',
Buffer.from(key, 'utf8'),
iv
);
let decrypted = decipher.update(encryptedData, 'base64', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
};
/**
* Initiate Paytm Transaction
*/
const initiateTransaction = async (orderId, amount, customerId, email, mobile) => {
const paytmParams = {
body: {
requestType: 'Payment',
mid: PaytmConfig.mid,
websiteName: PaytmConfig.website,
orderId: orderId,
callbackUrl: PaytmConfig.callbackUrl,
txnAmount: {
value: amount.toString(),
currency: 'INR',
},
userInfo: {
custId: customerId,
email: email,
mobile: mobile,
},
},
};
const checksum = await generateChecksum(
JSON.stringify(paytmParams.body),
PaytmConfig.key
);
paytmParams.head = {
signature: checksum,
};
return new Promise((resolve, reject) => {
const options = {
hostname: PaytmConfig.host,
port: 443,
path: `/theia/api/v1/initiateTransaction?mid=${PaytmConfig.mid}&orderId=${orderId}`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const response = JSON.parse(data);
resolve({
success: true,
txnToken: response.body.txnToken,
orderId: orderId,
amount: amount,
...response,
});
} catch (error) {
reject(error);
}
});
});
req.on('error', (error) => {
reject(error);
});
req.write(JSON.stringify(paytmParams));
req.end();
});
};
/**
* Check Transaction Status
*/
const checkTransactionStatus = async (orderId) => {
const paytmParams = {
body: {
mid: PaytmConfig.mid,
orderId: orderId,
},
};
const checksum = await generateChecksum(
JSON.stringify(paytmParams.body),
PaytmConfig.key
);
paytmParams.head = {
signature: checksum,
};
return new Promise((resolve, reject) => {
const options = {
hostname: PaytmConfig.host,
port: 443,
path: `/v3/order/status`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const response = JSON.parse(data);
resolve(response);
} catch (error) {
reject(error);
}
});
});
req.on('error', (error) => {
reject(error);
});
req.write(JSON.stringify(paytmParams));
req.end();
});
};
/**
* Process Refund
*/
const processRefund = async (orderId, refId, txnId, amount) => {
const paytmParams = {
body: {
mid: PaytmConfig.mid,
orderId: orderId,
refId: refId,
txnId: txnId,
txnType: 'REFUND',
refundAmount: amount.toString(),
},
};
const checksum = await generateChecksum(
JSON.stringify(paytmParams.body),
PaytmConfig.key
);
paytmParams.head = {
signature: checksum,
};
return new Promise((resolve, reject) => {
const options = {
hostname: PaytmConfig.host,
port: 443,
path: `/refund/apply`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const response = JSON.parse(data);
resolve(response);
} catch (error) {
reject(error);
}
});
});
req.on('error', (error) => {
reject(error);
});
req.write(JSON.stringify(paytmParams));
req.end();
});
};
module.exports = {
PaytmConfig,
generateChecksum,
verifyChecksum,
initiateTransaction,
checkTransactionStatus,
processRefund,
};

23
src/utils/uploadToS3.js Normal file
View File

@@ -0,0 +1,23 @@
const { PutObjectCommand } = require("@aws-sdk/client-s3");
const s3 = require("../config/s3");
const { v4: uuidv4 } = require("uuid");
const uploadToS3 = async (file, folder = "products") => {
const ext = file.originalname.split(".").pop();
const key = `${folder}/${uuidv4()}.${ext}`;
await s3.send(
new PutObjectCommand({
Bucket: process.env.AWS_S3_BUCKET,
Key: key,
Body: file.buffer,
ContentType: file.mimetype,
})
);
// return `${process.env.AWS_ENDPOINT}/${process.env.AWS_S3_BUCKET}/${key}`;
return `https://${process.env.AWS_ENDPOINT}/${process.env.AWS_S3_BUCKET}/${key}`;
};
module.exports = uploadToS3;