GTARH_Fonctionnel_V1
This commit is contained in:
111
Backend/webhook-utils.js
Normal file
111
Backend/webhook-utils.js
Normal file
@@ -0,0 +1,111 @@
|
||||
// webhook-utils.js (VERSION COMMONJS)
|
||||
const axios = require('axios');
|
||||
const crypto = require('crypto');
|
||||
|
||||
class WebhookManager {
|
||||
constructor(secretKey) {
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Génère une signature HMAC SHA-256 pour sécuriser le webhook
|
||||
* @param {Object} payload - Les données à signer
|
||||
* @returns {string} La signature hexadécimale
|
||||
*/
|
||||
generateSignature(payload) {
|
||||
return crypto
|
||||
.createHmac('sha256', this.secretKey)
|
||||
.update(JSON.stringify(payload))
|
||||
.digest('hex');
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie la signature d'un webhook reçu
|
||||
* @param {Object} payload - Les données reçues
|
||||
* @param {string} receivedSignature - La signature reçue dans le header
|
||||
* @returns {boolean} True si la signature est valide
|
||||
*/
|
||||
verifySignature(payload, receivedSignature) {
|
||||
if (!receivedSignature) {
|
||||
console.error('❌ Aucune signature fournie');
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const expectedSignature = this.generateSignature(payload);
|
||||
return crypto.timingSafeEqual(
|
||||
Buffer.from(expectedSignature),
|
||||
Buffer.from(receivedSignature)
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('❌ Erreur vérification signature:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Envoie un webhook à une URL cible avec retry automatique
|
||||
* @param {string} targetUrl - URL du serveur cible
|
||||
* @param {string} eventType - Type d'événement (ex: 'demande.validated')
|
||||
* @param {Object} data - Données de l'événement
|
||||
* @param {number} retries - Nombre de tentatives (défaut: 3)
|
||||
* @returns {Promise<Object>} La réponse du serveur
|
||||
*/
|
||||
async sendWebhook(targetUrl, eventType, data, retries = 3) {
|
||||
const payload = {
|
||||
event: eventType,
|
||||
data: data,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
const signature = this.generateSignature(payload);
|
||||
|
||||
for (let attempt = 1; attempt <= retries; attempt++) {
|
||||
try {
|
||||
console.log(`📤 Envoi webhook: ${eventType} vers ${targetUrl} (tentative ${attempt}/${retries})`);
|
||||
|
||||
const response = await axios.post(
|
||||
`${targetUrl}/api/webhook/receive`,
|
||||
payload,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Webhook-Signature': signature
|
||||
},
|
||||
timeout: 5000
|
||||
}
|
||||
);
|
||||
|
||||
console.log(`✅ Webhook envoyé avec succès: ${eventType}`);
|
||||
return response.data;
|
||||
|
||||
} catch (error) {
|
||||
console.error(`❌ Erreur envoi webhook (tentative ${attempt}/${retries}):`, error.message);
|
||||
|
||||
if (attempt === retries) {
|
||||
console.error(`❌ Échec définitif du webhook après ${retries} tentatives`);
|
||||
throw error;
|
||||
}
|
||||
|
||||
const waitTime = 1000 * attempt;
|
||||
console.log(`⏳ Nouvelle tentative dans ${waitTime}ms...`);
|
||||
await new Promise(resolve => setTimeout(resolve, waitTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Envoie un webhook sans attendre la réponse (fire and forget)
|
||||
* @param {string} targetUrl - URL du serveur cible
|
||||
* @param {string} eventType - Type d'événement
|
||||
* @param {Object} data - Données de l'événement
|
||||
*/
|
||||
sendWebhookAsync(targetUrl, eventType, data) {
|
||||
this.sendWebhook(targetUrl, eventType, data)
|
||||
.catch(error => {
|
||||
console.error('❌ Webhook async échoué (non bloquant):', error.message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = WebhookManager;
|
||||
Reference in New Issue
Block a user