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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | /** * API v1 — SSL Certificats (read-only) * * GET /api/v1/ssl — Liste des certificats surveilles * GET /api/v1/ssl/:id — Detail d'un certificat * * @module routes/api/v1/ssl */ const express = require('express'); const { pool: db } = require('../../../db'); const { requireScope } = require('../../../middleware/apiAuth'); const { checkQuota } = require('../../../middleware/planLimits'); const { apiSuccess, apiPaginated, apiError, parsePagination, makeApiDeleteHandler } = require('../../../helpers/apiResponse'); const DOMAIN_REGEX = /^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$/; const router = express.Router(); // ─── GET /ssl ─────────────────────────────────────────────────────────────── router.get('/', requireScope('read'), async (req, res, next) => { try { const { page, perPage, offset } = parsePagination(req.query); const [{ rows }, { rows: countRows }] = await Promise.all([ db.query( `SELECT id, domain, port, issuer, subject, valid_from, valid_to, alert_days, enabled, last_check, last_status, last_error, created_at FROM ssl_certificates WHERE user_id = $1 ORDER BY created_at LIMIT $2 OFFSET $3`, [req.user.id, perPage, offset], ), db.query('SELECT COUNT(*) FROM ssl_certificates WHERE user_id = $1', [req.user.id]), ]); // Calculer days_remaining const now = new Date(); const data = rows.map(cert => ({ ...cert, days_remaining: cert.valid_to ? Math.ceil((new Date(cert.valid_to) - now) / (1000 * 60 * 60 * 24)) : null, })); apiPaginated(res, data, { page, per_page: perPage, total: Number.parseInt(countRows[0].count) }); } catch (err) { next(err); } }); // ─── GET /ssl/:id ─────────────────────────────────────────────────────────── router.get('/:id', requireScope('read'), async (req, res, next) => { try { const { rows } = await db.query( `SELECT id, domain, port, issuer, subject, valid_from, valid_to, alert_days, enabled, last_check, last_status, last_error, created_at FROM ssl_certificates WHERE id = $1 AND user_id = $2`, [req.params.id, req.user.id], ); if (rows.length === 0) { return apiError(res, 404, 'NOT_FOUND', 'Certificat introuvable.'); } const cert = rows[0]; cert.days_remaining = cert.valid_to ? Math.ceil((new Date(cert.valid_to) - Date.now()) / (1000 * 60 * 60 * 24)) : null; apiSuccess(res, cert); } catch (err) { next(err); } }); // ─── POST /ssl ────────────────────────────────────────────────────────────── router.post('/', requireScope('write'), checkQuota('ssl_certificates', 'ssl_certificates'), async (req, res, next) => { try { const { domain, port = 443, alert_days = 30 } = req.body; if (!domain) { return apiError(res, 400, 'VALIDATION_ERROR', 'domain est requis.'); } if (domain.length > 253 || !DOMAIN_REGEX.test(domain)) { return apiError(res, 400, 'VALIDATION_ERROR', 'Nom de domaine invalide.'); } const p = Number.parseInt(port); if (p < 1 || p > 65535) { return apiError(res, 400, 'VALIDATION_ERROR', 'Port invalide (1-65535).'); } const ad = Number.parseInt(alert_days); if (ad < 1 || ad > 365) { return apiError(res, 400, 'VALIDATION_ERROR', 'alert_days invalide (1-365).'); } // Doublon const { rows: dup } = await db.query( 'SELECT id FROM ssl_certificates WHERE user_id = $1 AND domain = $2 AND port = $3', [req.user.id, domain, p], ); if (dup.length > 0) { return apiError(res, 409, 'DUPLICATE', 'Ce domaine:port est deja surveille.'); } const { rows } = await db.query( `INSERT INTO ssl_certificates (user_id, domain, port, alert_days) VALUES ($1, $2, $3, $4) RETURNING id, domain, port, alert_days, enabled, last_status, created_at`, [req.user.id, domain, p, ad], ); apiSuccess(res, rows[0], 201); } catch (err) { next(err); } }); // ─── DELETE /ssl/:id ──────────────────────────────────────────────────────── router.delete('/:id', requireScope('write'), makeApiDeleteHandler('ssl_certificates', 'Certificat introuvable.')); module.exports = router; |