feat: setup automatique certificats SSL au premier lancement
Nouveau : setup-helper.js - Détecte si mkcert est installé - Installe mkcert automatiquement (Homebrew macOS, curl Linux) - Installe CA locale (mkcert -install) - Génère certificats pour localhost + IP réseau - Détection automatique IP WiFi Intégration dans main.js : - Vérifie certificats au démarrage - Si absents : dialog onboarding + setup auto - Dialog progress "Configuration en cours..." - Dialog success avec IP réseau - Dialog error si échec (fallback manuel) - Ne démarre serveur que si certificats OK Expérience utilisateur : 1. Lancer l'app (première fois) 2. Dialog : "Première utilisation, configuration..." 3. Cliquer "Continuer" 4. Attendre 1-2 min (installation mkcert + CA + certificats) 5. Dialog : "Configuration terminée, IP: 192.168.x.x" 6. Serveur démarre automatiquement Prochaines fois : détection certificats OK → démarre direct L'utilisateur n'a RIEN à faire manuellement !
This commit is contained in:
+57
-1
@@ -3,10 +3,11 @@
|
|||||||
* Intègre le serveur Node.js existant dans une application Electron
|
* Intègre le serveur Node.js existant dans une application Electron
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { app, BrowserWindow, ipcMain, Menu, Tray } = require('electron');
|
const { app, BrowserWindow, ipcMain, Menu, Tray, dialog } = require('electron');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { spawn } = require('child_process');
|
const { spawn } = require('child_process');
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
|
const setupHelper = require('./setup-helper');
|
||||||
|
|
||||||
// État de l'application
|
// État de l'application
|
||||||
let mainWindow = null;
|
let mainWindow = null;
|
||||||
@@ -305,6 +306,61 @@ app.whenReady().then(async () => {
|
|||||||
createWindow();
|
createWindow();
|
||||||
createTray();
|
createTray();
|
||||||
|
|
||||||
|
// Vérifier setup automatique (certificats)
|
||||||
|
console.log('🔍 Vérification configuration...');
|
||||||
|
const projectRoot = path.join(__dirname, '..');
|
||||||
|
const certsDir = path.join(projectRoot, 'certs');
|
||||||
|
|
||||||
|
if (!setupHelper.certificatesExist(certsDir)) {
|
||||||
|
console.log('⚠️ Certificats SSL manquants, configuration automatique...\n');
|
||||||
|
|
||||||
|
// Afficher dialog d'information
|
||||||
|
const infoResult = await dialog.showMessageBox(mainWindow, {
|
||||||
|
type: 'info',
|
||||||
|
title: 'Configuration initiale',
|
||||||
|
message: 'Première utilisation de PTT Live',
|
||||||
|
detail: 'Configuration des certificats SSL en cours...\nCela peut prendre 1-2 minutes.\n\nmkcert sera installé automatiquement.',
|
||||||
|
buttons: ['Continuer', 'Annuler']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (infoResult.response === 1) {
|
||||||
|
console.log('⚠️ Configuration annulée par l\'utilisateur');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lancer setup auto
|
||||||
|
const setupResult = await setupHelper.autoSetup(projectRoot);
|
||||||
|
|
||||||
|
if (!setupResult.success) {
|
||||||
|
// Échec du setup automatique
|
||||||
|
await dialog.showMessageBox(mainWindow, {
|
||||||
|
type: 'error',
|
||||||
|
title: 'Configuration échouée',
|
||||||
|
message: 'Impossible de configurer automatiquement les certificats SSL',
|
||||||
|
detail: setupResult.manual
|
||||||
|
? 'Veuillez exécuter manuellement :\n./setup-certificates.sh\n\nOu installer mkcert : https://github.com/FiloSottile/mkcert'
|
||||||
|
: setupResult.error,
|
||||||
|
buttons: ['OK']
|
||||||
|
});
|
||||||
|
|
||||||
|
console.error('❌ Setup automatique échoué');
|
||||||
|
return; // Ne pas démarrer le serveur
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup réussi
|
||||||
|
await dialog.showMessageBox(mainWindow, {
|
||||||
|
type: 'info',
|
||||||
|
title: 'Configuration terminée',
|
||||||
|
message: 'Certificats SSL configurés avec succès !',
|
||||||
|
detail: `Votre IP réseau : ${setupResult.networkIP}\n\nLe serveur va démarrer...`,
|
||||||
|
buttons: ['OK']
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('✅ Setup automatique terminé\n');
|
||||||
|
} else {
|
||||||
|
console.log('✅ Certificats présents\n');
|
||||||
|
}
|
||||||
|
|
||||||
// Démarrer le serveur automatiquement
|
// Démarrer le serveur automatiquement
|
||||||
console.log('🔄 Démarrage automatique du serveur...');
|
console.log('🔄 Démarrage automatique du serveur...');
|
||||||
await startServer();
|
await startServer();
|
||||||
|
|||||||
@@ -0,0 +1,249 @@
|
|||||||
|
/**
|
||||||
|
* PTT Live Desktop - Setup Helper
|
||||||
|
* Automatise l'installation des dépendances et certificats
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { exec } = require('child_process');
|
||||||
|
const { promisify } = require('util');
|
||||||
|
const { existsSync } = require('fs');
|
||||||
|
const { join } = require('path');
|
||||||
|
const os = require('os');
|
||||||
|
|
||||||
|
const execPromise = promisify(exec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si mkcert est installé
|
||||||
|
*/
|
||||||
|
async function isMkcertInstalled() {
|
||||||
|
try {
|
||||||
|
await execPromise('mkcert -version');
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installe mkcert automatiquement
|
||||||
|
*/
|
||||||
|
async function installMkcert() {
|
||||||
|
const platform = os.platform();
|
||||||
|
|
||||||
|
console.log('📦 Installation de mkcert...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (platform === 'darwin') {
|
||||||
|
// macOS - via Homebrew
|
||||||
|
if (await isHomebrewInstalled()) {
|
||||||
|
await execPromise('brew install mkcert nss');
|
||||||
|
console.log('✅ mkcert installé via Homebrew');
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new Error('Homebrew requis sur macOS');
|
||||||
|
}
|
||||||
|
} else if (platform === 'linux') {
|
||||||
|
// Linux - téléchargement direct
|
||||||
|
await execPromise('curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64"');
|
||||||
|
await execPromise('chmod +x mkcert-v*-linux-amd64');
|
||||||
|
await execPromise('sudo mv mkcert-v*-linux-amd64 /usr/local/bin/mkcert');
|
||||||
|
console.log('✅ mkcert installé');
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new Error(`Plateforme non supportée: ${platform}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Erreur installation mkcert:', error.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si Homebrew est installé
|
||||||
|
*/
|
||||||
|
async function isHomebrewInstalled() {
|
||||||
|
try {
|
||||||
|
await execPromise('brew --version');
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installe la CA locale
|
||||||
|
*/
|
||||||
|
async function installCA() {
|
||||||
|
try {
|
||||||
|
console.log('🔑 Installation de la Certificate Authority locale...');
|
||||||
|
await execPromise('mkcert -install');
|
||||||
|
console.log('✅ CA locale installée');
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Erreur installation CA:', error.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Détecte l'IP réseau locale
|
||||||
|
*/
|
||||||
|
function getNetworkIP() {
|
||||||
|
const interfaces = os.networkInterfaces();
|
||||||
|
|
||||||
|
// Priorité : WiFi > Ethernet
|
||||||
|
const priority = ['en0', 'en1', 'eth0', 'wlan0'];
|
||||||
|
|
||||||
|
for (const name of priority) {
|
||||||
|
const iface = interfaces[name];
|
||||||
|
if (iface) {
|
||||||
|
for (const net of iface) {
|
||||||
|
if (net.family === 'IPv4' && !net.internal) {
|
||||||
|
return net.address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback : première IP non-interne
|
||||||
|
for (const name of Object.keys(interfaces)) {
|
||||||
|
for (const net of interfaces[name]) {
|
||||||
|
if (net.family === 'IPv4' && !net.internal) {
|
||||||
|
return net.address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '192.168.1.100'; // Fallback ultime
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Génère les certificats SSL
|
||||||
|
*/
|
||||||
|
async function generateCertificates(certsDir) {
|
||||||
|
try {
|
||||||
|
const networkIP = getNetworkIP();
|
||||||
|
const hostname = os.hostname();
|
||||||
|
|
||||||
|
console.log('📜 Génération des certificats...');
|
||||||
|
console.log(` IP réseau : ${networkIP}`);
|
||||||
|
|
||||||
|
// Créer répertoire si nécessaire
|
||||||
|
if (!existsSync(certsDir)) {
|
||||||
|
await execPromise(`mkdir -p "${certsDir}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Générer certificats
|
||||||
|
const cmd = `cd "${certsDir}" && mkcert localhost 127.0.0.1 ::1 "${networkIP}" "*.local" "${hostname}.local"`;
|
||||||
|
await execPromise(cmd);
|
||||||
|
|
||||||
|
// Renommer pour simplifier
|
||||||
|
const files = await execPromise(`ls "${certsDir}"/*.pem`);
|
||||||
|
const fileList = files.stdout.trim().split('\n');
|
||||||
|
|
||||||
|
// Trouver les fichiers générés
|
||||||
|
const certFile = fileList.find(f => !f.includes('-key.pem'));
|
||||||
|
const keyFile = fileList.find(f => f.includes('-key.pem'));
|
||||||
|
|
||||||
|
if (certFile && keyFile) {
|
||||||
|
// Copier avec noms standards
|
||||||
|
await execPromise(`cp "${certFile}" "${join(certsDir, 'localhost.pem')}"`);
|
||||||
|
await execPromise(`cp "${keyFile}" "${join(certsDir, 'localhost-key.pem')}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ Certificats générés');
|
||||||
|
return { networkIP, certPath: join(certsDir, 'localhost.pem'), keyPath: join(certsDir, 'localhost-key.pem') };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Erreur génération certificats:', error.message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si les certificats existent et sont valides
|
||||||
|
*/
|
||||||
|
function certificatesExist(certsDir) {
|
||||||
|
const certPath = join(certsDir, 'localhost.pem');
|
||||||
|
const keyPath = join(certsDir, 'localhost-key.pem');
|
||||||
|
|
||||||
|
return existsSync(certPath) && existsSync(keyPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup complet automatique
|
||||||
|
*/
|
||||||
|
async function autoSetup(projectRoot) {
|
||||||
|
const certsDir = join(projectRoot, 'certs');
|
||||||
|
|
||||||
|
console.log('🚀 Configuration automatique PTT Live...\n');
|
||||||
|
|
||||||
|
// 1. Vérifier certificats existants
|
||||||
|
if (certificatesExist(certsDir)) {
|
||||||
|
console.log('✅ Certificats déjà présents');
|
||||||
|
return { success: true, needsRestart: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('⚠️ Certificats SSL non trouvés\n');
|
||||||
|
|
||||||
|
// 2. Vérifier mkcert
|
||||||
|
const hasMkcert = await isMkcertInstalled();
|
||||||
|
|
||||||
|
if (!hasMkcert) {
|
||||||
|
console.log('📦 mkcert non installé, installation...\n');
|
||||||
|
|
||||||
|
const installed = await installMkcert();
|
||||||
|
if (!installed) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Installation mkcert échouée',
|
||||||
|
manual: true,
|
||||||
|
instructions: 'Installez mkcert manuellement : https://github.com/FiloSottile/mkcert'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('✅ mkcert déjà installé\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Installer CA locale
|
||||||
|
const caInstalled = await installCA();
|
||||||
|
if (!caInstalled) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Installation CA échouée',
|
||||||
|
manual: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
// 4. Générer certificats
|
||||||
|
const result = await generateCertificates(certsDir);
|
||||||
|
if (!result) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Génération certificats échouée',
|
||||||
|
manual: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n✅ Configuration terminée !');
|
||||||
|
console.log(` Certificats : ${certsDir}`);
|
||||||
|
console.log(` IP réseau : ${result.networkIP}\n`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
needsRestart: false,
|
||||||
|
networkIP: result.networkIP,
|
||||||
|
certPath: result.certPath,
|
||||||
|
keyPath: result.keyPath
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
isMkcertInstalled,
|
||||||
|
installMkcert,
|
||||||
|
installCA,
|
||||||
|
generateCertificates,
|
||||||
|
certificatesExist,
|
||||||
|
getNetworkIP,
|
||||||
|
autoSetup
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user