@adriantombu/paybox-system
Version:
A simple implementation of the Paybox System payment solution
163 lines (162 loc) • 6.2 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Paybox = void 0;
const querystring_1 = __importDefault(require("querystring"));
const axios_1 = __importDefault(require("axios"));
const crypto_1 = __importDefault(require("crypto"));
const errors_1 = __importDefault(require("./errors"));
__exportStar(require("./types"), exports);
class Paybox {
constructor(params) {
this.sandbox = params.payboxSandbox;
this.request = {
PBX_SITE: params.payboxSite,
PBX_RANG: params.payboxRang,
PBX_IDENTIFIANT: params.payboxIdentifiant,
PBX_ARCHIVAGE: this.archivage(),
PBX_HMAC: params.payboxHmac,
PBX_TOTAL: this.formatAmount(params.amount),
PBX_DEVISE: '978',
PBX_CMD: params.reference,
PBX_PORTEUR: params.email,
PBX_RETOUR: this.setReturnVars(),
PBX_RUF1: 'POST',
PBX_TIME: this.getTime(),
PBX_HASH: 'SHA512',
PBX_EFFECTUE: params.payboxEffectue,
PBX_REFUSE: params.payboxRefuse,
PBX_ANNULE: params.payboxAnnule,
PBX_ATTENTE: params.payboxAttente,
PBX_REPONDRE_A: params.payboxRepondreA,
};
this.computeHMAC();
}
static create(params) {
return new Paybox(params);
}
static getError(code) {
if (code.startsWith('001')) {
return 'Paiement refusé par le centre d’autorisation';
}
if (code in errors_1.default) {
return errors_1.default[code];
}
return `Erreur ${code}`;
}
static isValid(result, amount) {
return (!!result.authorizationId &&
result.error === '00000' &&
parseInt(result.amount, 10) === amount &&
this.signatureIsValid(result));
}
static signatureIsValid(result) {
const signature = new Buffer(result.signature || '', 'base64');
delete result.signature;
if (signature.length !== 128) {
return false;
}
const message = querystring_1.default.stringify(result);
const publicKey = crypto_1.default.createPublicKey(payboxPublicKey);
return crypto_1.default.createVerify('SHA1').update(message).verify(publicKey, signature);
}
async form() {
return {
url: await this.getUrl(),
method: this.request.PBX_RUF1,
form: this.getFormElements()
.map((e) => `<input type="hidden" name="${e.name}" value="${e.value}" />`)
.join(''),
elements: this.getFormElements(),
};
}
archivage() {
return Date.now().toString().substr(-12);
}
formatAmount(amount) {
return `${parseInt(amount.toString(), 10)}`.padStart(10, '0');
}
setReturnVars() {
let vars = '';
for (const key of Object.keys(returnVars)) {
vars += `${returnVars[key]}:${key};`;
}
return vars;
}
getTime() {
const now = new Date();
const day = now.getDay().toString().padStart(2, '0');
const month = (now.getMonth() + 1).toString().padStart(2, '0');
const year = now.getFullYear();
const hour = now.getHours().toString().padStart(2, '0');
const minute = now.getMinutes().toString().padStart(2, '0');
const second = now.getSeconds().toString().padStart(2, '0');
return `${day}${month}${year}${hour}${minute}${second}`;
}
computeHMAC() {
if (this.request.PBX_HMAC) {
const elements = this.getFormElements();
const hmac = Buffer.from(this.request.PBX_HMAC, 'hex');
const chain = elements
.filter((e) => e.name !== 'PBX_HMAC')
.map((e) => `${e.name}=${e.value}`)
.join('&');
this.request.PBX_HMAC = crypto_1.default.createHmac('sha512', hmac).update(chain).digest('hex').toUpperCase();
}
}
async getUrl() {
const urls = this.sandbox ? baseUrls.sandbox : baseUrls.prod;
const res = await axios_1.default.get(`${urls.main}/load.html`);
return `${res.data.includes('>OK<') ? urls.main : urls.fallback}/cgi/MYchoix_pagepaiement.cgi`;
}
getFormElements() {
const elements = [];
for (const key of Object.keys(this.request)) {
elements.push({
name: key,
value: this.request[key],
});
}
return elements;
}
}
exports.Paybox = Paybox;
const returnVars = {
M: 'amount',
R: 'paymentId',
T: 'transactionId',
A: 'authorizationId',
P: 'cardType',
N: 'cardNumber',
D: 'cardExpiration',
E: 'error',
S: 'payboxRef',
K: 'signature',
};
const baseUrls = {
prod: {
main: 'https://tpeweb.paybox.com',
fallback: 'https://tpeweb1.paybox.com',
},
sandbox: {
main: 'https://preprod-tpeweb.paybox.com',
fallback: 'https://preprod-tpeweb.paybox.com',
},
};
const payboxPublicKey = '-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDe+hkicNP7ROHUssGNtHwiT2Ew\nHFrSk/qwrcq8v5metRtTTFPE/nmzSkRnTs3GMpi57rBdxBBJW5W9cpNyGUh0jNXc\nVrOSClpD5Ri2hER/GcNrxVRP7RlWOqB1C03q4QYmwjHZ+zlM4OUhCCAtSWflB4wC\nKa1g88CjFwRw/PB9kwIDAQAB\n-----END PUBLIC KEY-----';