From 6b13981dad56717448309110c4137980930aa219 Mon Sep 17 00:00:00 2001 From: Benoit Date: Wed, 27 May 2026 15:36:52 +0200 Subject: [PATCH] feat: support HTTPS en mode production MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ajout support HTTPS au serveur Express avec certificats auto-signés - Variable d'environnement ENABLE_HTTPS pour activer/désactiver HTTPS - start.sh active automatiquement HTTPS en mode production (pas --dev) - Messages d'aide clarifiés avec URLs HTTPS et avertissement certificat - WebSocket Audio Levels supporte wss:// en mode HTTPS Mode dev : HTTPS sur port 5173 (Vite) + HTTP API sur 3000 Mode prod : HTTPS sur port 3000 (Express sert client + API) --- server/index.js | 85 +++++++++++++++++++++++++++++++++---------------- start.sh | 29 +++++++++++------ 2 files changed, 77 insertions(+), 37 deletions(-) diff --git a/server/index.js b/server/index.js index 47ecde4..dd58b58 100644 --- a/server/index.js +++ b/server/index.js @@ -2,6 +2,8 @@ import 'dotenv/config'; import express from 'express'; +import https from 'https'; +import http from 'http'; import { spawn } from 'child_process'; import { readFileSync, existsSync } from 'fs'; import { fileURLToPath } from 'url'; @@ -67,6 +69,7 @@ const LIVEKIT_API_SECRET = process.env.LIVEKIT_API_SECRET || 'secret'; const USE_LOCAL_LIVEKIT = process.env.USE_LOCAL_LIVEKIT === 'true'; const SERVER_PORT = parseInt(process.env.PORT || config.server.port, 10); const SERVER_HOST = config.server.host; +const ENABLE_HTTPS = process.env.ENABLE_HTTPS === 'true'; // Configuration URL LiveKit let LIVEKIT_URL = process.env.LIVEKIT_URL || config.server.livekit.url; @@ -181,18 +184,13 @@ app.use((req, res, next) => { next(); }); -// Middleware redirection HTTP → HTTPS (développement uniquement) -// En développement, redirige vers le serveur Vite HTTPS (5173) -// En production réelle, utiliser nginx/caddy pour HTTPS +// Middleware redirection HTTP → HTTPS (si activé) app.use((req, res, next) => { - const clientDistPath = join(__dirname, '..', 'client', 'dist'); - const isProd = existsSync(clientDistPath); - - // Mode dev : rediriger HTTP → HTTPS (Vite) - if (!isProd && req.protocol === 'http' && req.hostname !== 'localhost') { - const devHttpsUrl = `https://${req.hostname}:5173${req.url}`; - log('debug', `↪️ Redirection dev HTTPS: ${devHttpsUrl}`); - return res.redirect(301, devHttpsUrl); + // Si HTTPS activé et requête en HTTP, rediriger + if (ENABLE_HTTPS && req.protocol === 'http' && req.hostname !== 'localhost') { + const httpsUrl = `https://${req.hostname}:${SERVER_PORT}${req.url}`; + log('debug', `↪️ Redirection HTTPS: ${httpsUrl}`); + return res.redirect(301, httpsUrl); } next(); @@ -409,31 +407,62 @@ async function start() { log('warn', '⚠️ Pour utiliser LiveKit local, définir USE_LOCAL_LIVEKIT=true dans .env'); } - // 2. Démarrer API REST - const server = app.listen(SERVER_PORT, SERVER_HOST, () => { - log('info', `✓ API REST démarrée sur http://${SERVER_HOST}:${SERVER_PORT}`); - log('info', ''); - log('info', 'Serveur prêt !'); - log('info', `Groupes configurés: ${config.groups.map(g => g.name).join(', ')}`); - log('info', ''); + // 2. Démarrer API REST (HTTP ou HTTPS selon config) + let server; - // Afficher URLs d'accès avec QR code - if (networkIP && networkIP !== 'localhost') { - const clientUrl = `https://${networkIP}:5173`; // Dev mode - const prodUrl = `http://${networkIP}:${SERVER_PORT}`; // Prod mode (redirigera vers HTTPS) + if (ENABLE_HTTPS) { + // Charger certificats SSL (mêmes que Vite) + const certPath = join(__dirname, '..', 'client'); + const httpsOptions = { + key: readFileSync(join(certPath, 'localhost+3-key.pem')), + cert: readFileSync(join(certPath, 'localhost+3.pem')) + }; - log('info', '📱 Accès réseau WiFi :'); + server = https.createServer(httpsOptions, app); + server.listen(SERVER_PORT, SERVER_HOST, () => { + log('info', `✓ API REST démarrée sur https://${SERVER_HOST}:${SERVER_PORT}`); log('info', ''); - log('info', ` Dev : ${clientUrl}`); - log('info', ` Prod : ${prodUrl} (redirige → HTTPS)`); + log('info', 'Serveur prêt !'); + log('info', `Groupes configurés: ${config.groups.map(g => g.name).join(', ')}`); log('info', ''); - } - }); + + // Afficher URLs d'accès + if (networkIP && networkIP !== 'localhost') { + const prodUrl = `https://${networkIP}:${SERVER_PORT}`; + log('info', '📱 Accès réseau WiFi :'); + log('info', ''); + log('info', ` Prod : ${prodUrl}`); + log('info', ''); + } + }); + } else { + server = http.createServer(app); + server.listen(SERVER_PORT, SERVER_HOST, () => { + log('info', `✓ API REST démarrée sur http://${SERVER_HOST}:${SERVER_PORT}`); + log('info', ''); + log('info', 'Serveur prêt !'); + log('info', `Groupes configurés: ${config.groups.map(g => g.name).join(', ')}`); + log('info', ''); + + // Afficher URLs d'accès + if (networkIP && networkIP !== 'localhost') { + const clientUrl = `https://${networkIP}:5173`; // Dev mode + const prodUrl = `http://${networkIP}:${SERVER_PORT}`; // Prod mode HTTP + + log('info', '📱 Accès réseau WiFi :'); + log('info', ''); + log('info', ` Dev : ${clientUrl}`); + log('info', ` Prod : ${prodUrl}`); + log('info', ''); + } + }); + } // 2.5 Démarrer WebSocket Audio Levels (même port que l'API) const audioLevelsServer = new AudioLevelsServer({ server }); audioLevelsServer.start(); - log('info', `✓ WebSocket Audio Levels démarré sur ws://${SERVER_HOST}:${SERVER_PORT}`); + const wsProtocol = ENABLE_HTTPS ? 'wss' : 'ws'; + log('info', `✓ WebSocket Audio Levels démarré sur ${wsProtocol}://${SERVER_HOST}:${SERVER_PORT}`); // 3. Démarrer Audio Bridge Manager (Phase 2.5) log('info', ''); diff --git a/start.sh b/start.sh index 3989e1a..7f22df1 100755 --- a/start.sh +++ b/start.sh @@ -84,6 +84,11 @@ echo "" cd server +# En mode production (pas --dev), activer HTTPS +if [ "$1" != "--dev" ]; then + export ENABLE_HTTPS=true +fi + # Lancer le serveur en background silencieux npm start > ../server.log 2>&1 & SERVER_PID=$! @@ -134,12 +139,15 @@ if [ "$1" == "--dev" ]; then echo "✅ PTT Live démarré (mode dev)" echo "==================================${NC}" echo "" - echo "🌐 Accès client :" - echo " • Local : https://localhost:5173" - echo " • Réseau : https://${NETWORK_IP}:5173" + echo -e "${BLUE}🌐 ACCÈS CLIENT (HTTPS) :${NC}" + echo -e "${GREEN} 👉 Local : https://localhost:5173${NC}" + echo -e "${GREEN} 👉 Réseau : https://${NETWORK_IP}:5173${NC}" echo "" - echo "📊 API serveur : http://${NETWORK_IP}:3000 (→ redirige vers HTTPS)" - echo "🎛️ Interface admin : https://${NETWORK_IP}:5173/admin" + echo -e "${YELLOW}⚠️ Acceptez le certificat auto-signé dans votre navigateur${NC}" + echo -e "${YELLOW} (Cliquez sur 'Avancé' puis 'Continuer')${NC}" + echo "" + echo "📊 API serveur (HTTP uniquement) : http://localhost:3000" + echo "🎛️ Interface admin : https://localhost:5173/admin" echo "" echo "📝 Logs serveur : tail -f server.log" echo "" @@ -168,11 +176,14 @@ else echo "✅ PTT Live démarré (production)" echo "==================================${NC}" echo "" - echo "🌐 Accès :" - echo " • Local : http://localhost:3000" - echo " • Réseau : http://${NETWORK_IP}:3000" + echo -e "${BLUE}🌐 ACCÈS CLIENT (HTTPS) :${NC}" + echo -e "${GREEN} 👉 Local : https://localhost:3000${NC}" + echo -e "${GREEN} 👉 Réseau : https://${NETWORK_IP}:3000${NC}" echo "" - echo "🎛️ Interface admin : http://${NETWORK_IP}:3000/admin" + echo -e "${YELLOW}⚠️ Acceptez le certificat auto-signé dans votre navigateur${NC}" + echo -e "${YELLOW} (Cliquez sur 'Avancé' puis 'Continuer')${NC}" + echo "" + echo "🎛️ Interface admin : https://localhost:3000/admin" echo "" echo "📝 Logs serveur : tail -f server.log" echo ""