All files / src/routes webhooks.js

0% Statements 0/58
0% Branches 0/27
0% Functions 0/6
0% Lines 0/52

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91                                                                                                                                                                                     
/**
 * Routes Webhooks — CRUD des webhooks de notification.
 *
 * @module routes/webhooks
 */
 
const express = require('express');
const { pool: db } = require('../db');
const { requireAuth } = require('../middleware/auth');
const { checkQuota } = require('../middleware/planLimits');
const { validatePublicUrl } = require('../utils/networkValidator');
const { VALID_PLATFORMS, VALID_EVENTS } = require('../helpers/webhookConstants');
const { requireGroupContext, requireGroupPermission } = require('../middleware/groupContext');
const router = express.Router();
 
router.use(requireAuth);
router.use(requireGroupContext());
 
router.get('/', requireGroupPermission('webhooks', 'read'), async (req, res, next) => {
  try {
    const { rows } = await db.query('SELECT * FROM webhooks WHERE user_id = $1 ORDER BY created_at DESC', [req.user.id]);
    res.json(rows);
  } catch (err) { next(err); }
});
 
router.post('/', requireGroupPermission('webhooks', 'read'), checkQuota('webhooks', 'webhooks'), async (req, res, next) => {
  try {
    const { label, url, platform = 'discord', events } = req.body;
    if (!label || !url) return res.status(400).json({ error: 'label et url sont requis.' });
    if (!VALID_PLATFORMS.includes(platform)) return res.status(400).json({ error: `Platform invalide. Valeurs: ${VALID_PLATFORMS.join(', ')}` });
 
    // Protection SSRF : bloquer les IPs privees
    const urlCheck = await validatePublicUrl(url);
    if (!urlCheck.valid) {
      return res.status(400).json({ error: urlCheck.reason });
    }
 
    const filteredEvents = (events || VALID_EVENTS).filter((e) => VALID_EVENTS.includes(e));
 
    const { rows } = await db.query(
      `INSERT INTO webhooks (user_id, label, url, platform, events) VALUES ($1, $2, $3, $4, $5) RETURNING *`,
      [req.user.id, label, url, platform, filteredEvents],
    );
    res.status(201).json(rows[0]);
  } catch (err) { next(err); }
});
 
router.patch('/:id', requireGroupPermission('webhooks', 'read'), async (req, res, next) => {
  try {
    const { label, url, platform, events, enabled } = req.body;
    const existing = await db.query('SELECT * FROM webhooks WHERE id = $1 AND user_id = $2', [req.params.id, req.user.id]);
    if (existing.rows.length === 0) return res.status(404).json({ error: 'Webhook introuvable.' });
 
    const w = existing.rows[0];
    const { rows } = await db.query(
      'UPDATE webhooks SET label=$1, url=$2, platform=$3, events=$4, enabled=$5 WHERE id=$6 AND user_id=$7 RETURNING *',
      [label ?? w.label, url ?? w.url, platform ?? w.platform, events ?? w.events, enabled == null ? w.enabled : Boolean(enabled), req.params.id, req.user.id],
    );
    res.json(rows[0]);
  } catch (err) { next(err); }
});
 
router.delete('/:id', requireGroupPermission('webhooks', 'read'), async (req, res, next) => {
  try {
    const result = await db.query('DELETE FROM webhooks WHERE id = $1 AND user_id = $2 RETURNING id', [req.params.id, req.user.id]);
    if (result.rows.length === 0) return res.status(404).json({ error: 'Webhook introuvable.' });
    res.json({ message: 'Webhook supprimé.' });
  } catch (err) { next(err); }
});
 
// Test : envoie un message de test au webhook
router.post('/:id/test', requireGroupPermission('webhooks', 'read'), async (req, res, next) => {
  try {
    const { rows } = await db.query('SELECT * FROM webhooks WHERE id = $1 AND user_id = $2', [req.params.id, req.user.id]);
    if (rows.length === 0) return res.status(404).json({ error: 'Webhook introuvable.' });
 
    const { notify } = require('../services/webhookNotifier');
    // Envoyer directement au webhook spécifique
    const wh = rows[0];
    await notify(req.user.id, 'server_alert', {
      title: 'Test IliaCloud',
      message: `Webhook "${wh.label}" fonctionne correctement !`,
      fields: [{ name: 'Plateforme', value: wh.platform, inline: true }],
    });
 
    res.json({ ok: true, message: 'Message de test envoyé.' });
  } catch (err) { next(err); }
});
 
module.exports = router;