quickpos
Version:
<div align="center"> <h1>💳 QuickPos 🚀</h1> <p><strong>A powerful, multi-gateway payment integration module for Node.js</strong></p> <p>Seamlessly integrate with 50+ payment providers worldwide</p>
121 lines (100 loc) • 4.67 kB
JavaScript
const crypto = require('crypto');
class TwoCheckoutClient {
constructor(config) {
const requiredFields = ['merchantCode', 'secretWord'];
for (let field of requiredFields) {
if (!config[field]) throw new Error(`Missing required field: ${field}`);
}
this.merchantCode = config.merchantCode;
this.secretWord = config.secretWord;
this.sandbox = config.sandbox || false;
}
generateHash(params, algo = 'md5') {
let signatureString = '';
Object.keys(params).forEach(key => {
const value = String(params[key]); // Değer string olmalı
if (value.length > 0) { // Boş değerler bazen hash'e katılmaz
signatureString += value.length + value;
}
});
return crypto
.createHmac(algo, this.secretWord)
.update(signatureString)
.digest('hex');
}
createPaymentUrl(options) {
const orderId = options.orderId || `ORDER-${Date.now()}`;
const params = {
'merchant': this.merchantCode,
'dynamic': '1', // Dinamik ürün modu
'prod-name[]': options.name || 'Payment',
'prod-type[]': 'GLOBAL_SERVICE', // Ürün tipi
'prod-price[]': parseFloat(options.amount).toFixed(2),
'prod-qty[]': '1',
'currency': options.currency || 'USD',
'return-type': 'redirect',
'return-url': options.callbackUrl,
'expiration': Math.floor(Date.now() / 1000) + 3600, // 1 saat geçerli
'order-ext-ref': orderId,
'customer-ref': options.customerId || '',
'customer-email': options.email || ''
};
let signatureData = '';
const keysToSign = [
'merchant', 'dynamic', 'prod-name[]', 'prod-type[]', 'prod-price[]',
'prod-qty[]', 'currency', 'return-type', 'return-url', 'expiration',
'order-ext-ref', 'customer-ref', 'customer-email'
];
keysToSign.forEach(key => {
const val = String(params[key] || '');
if(val) signatureData += val.length + val;
});
const signature = crypto.createHmac('md5', this.secretWord).update(signatureData).digest('hex');
params['signature'] = signature;
// URL Parametrelerini oluştur
const queryParams = new URLSearchParams();
Object.keys(params).forEach(key => queryParams.append(key, params[key]));
return `https://secure.2checkout.com/order/checkout.php?${queryParams.toString()}`;
}
/**
* IPN (Callback) Doğrulama
* Bu kısım, sunucunuza gelen POST isteğini doğrular.
*/
verifyCallback(postData) {
try {
// Gelen veriden HASH'i ayıralım
const receivedHash = postData['HASH'];
if (!receivedHash) {
return { status: false, message: 'No hash found' };
}
let hashString = '';
// 2Checkout, HASH parametresi hariç tüm parametreleri gönderdiği sırayla kullanır.
for (let key in postData) {
if (key !== 'HASH') {
const val = String(postData[key]);
hashString += val.length + val;
}
}
const calculatedHash = crypto
.createHmac('md5', this.secretWord)
.update(hashString)
.digest('hex');
if (calculatedHash === receivedHash) {
const date = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '');
const responseHash = crypto.createHmac('md5', this.secretWord).update(postData.IPN_PID[0].length + postData.IPN_PID[0] + postData.IPN_PNAME[0].length + postData.IPN_PNAME[0] + postData.IPN_DATE.length + postData.IPN_DATE + date.length + date).digest('hex');
return {
status: true,
transactionId: postData.REFNO,
orderStatus: postData.ORDERSTATUS,
raw: postData
};
} else {
console.error("Hash Mismatch. Calculated:", calculatedHash, "Received:", receivedHash);
return { status: false, message: 'Invalid hash signature' };
}
} catch (error) {
return { status: false, message: error.message };
}
}
}
module.exports = TwoCheckoutClient;