// Audio Context for Sound Effects let audioCtx = null; let soundEnabled = false; let ws = null; // WebSocket connection // Authentication State let currentUser = null; let sessionId = null; let accessLevel = null; const ACTIVE_SESSIONS = new Map(); // API Configuration const API_BASE = 'http://localhost:3000/api'; document.addEventListener('DOMContentLoaded', () => { // Initialize Audio on first interaction (browser policy) document.body.addEventListener('click', initAudio, { once: true }); document.getElementById('btn-sound').addEventListener('click', toggleSound); // Setup Login Form setupAuthentication(); // Terminal Setup setupTerminal(); setupAIChat(); // Feather Icons re-render if (typeof feather !== 'undefined') { feather.replace(); } }); // Authentication System function setupAuthentication() { const loginForm = document.getElementById('login-form'); if (loginForm) { loginForm.addEventListener('submit', async (e) => { e.preventDefault(); const user = document.getElementById('login-user').value; const pass = document.getElementById('login-pass').value; await authenticateUser(user, pass); }); } } function checkAuthentication() { const session = localStorage.getItem('cybershield_session'); if (session) { const sessionData = JSON.parse(session); if (sessionData.expiry > Date.now()) { restoreSession(sessionData); } else { localStorage.removeItem('cybershield_session'); showLoginModal(); } } else { showLoginModal(); } } function showLoginModal() { document.getElementById('login-modal').classList.remove('hidden'); document.getElementById('main-container').classList.add('blur-sm'); } function hideLoginModal() { document.getElementById('login-modal').classList.add('hidden'); document.getElementById('main-container').classList.remove('blur-sm'); document.getElementById('main-container').classList.add('pt-8'); } async function authenticateUser(username, password) { // Simulation d'authentification (en production: appel API sécurisé) if (username.startsWith('ADMIN_') && password.length >= 8) { currentUser = username; sessionId = 'AUTH-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9); accessLevel = 'ADMIN_T3'; // Store session const sessionData = { user: currentUser, sessionId: sessionId, level: accessLevel, expiry: Date.now() + (8 * 60 * 60 * 1000) // 8 heures }; localStorage.setItem('cybershield_session', JSON.stringify(sessionData)); // Update UI document.getElementById('current-user').textContent = currentUser; document.getElementById('session-id').textContent = sessionId; document.getElementById('session-bar').classList.remove('hidden'); hideLoginModal(); // Log access addLogEntry(`Authentification réussie: ${username} (Niveau ${accessLevel})`, 'success', 'AUTH'); // Initialize Systems after auth initializeSystems(); // Start access monitoring startAccessMonitoring(); startEgressMonitoring(); startIngressMonitoring(); playBeep(800, 'sine', 0.2); return true; } else { addLogEntry(`Tentative d'authentification échouée: ${username}`, 'error', 'AUTH'); alert('Identifiants invalides. Format requis: ADMIN_xxxx'); return false; } } function restoreSession(sessionData) { currentUser = sessionData.user; sessionId = sessionData.sessionId; accessLevel = sessionData.level; document.getElementById('current-user').textContent = currentUser; document.getElementById('session-id').textContent = sessionId; document.getElementById('session-bar').classList.remove('hidden'); document.getElementById('main-container').classList.add('pt-8'); initializeSystems(); startAccessMonitoring(); startEgressMonitoring(); startIngressMonitoring(); } function logout() { if (confirm('Confirmer la déconnexion ?')) { localStorage.removeItem('cybershield_session'); addLogEntry(`Déconnexion: ${currentUser}`, 'info', 'AUTH'); location.reload(); } } function forceLogoutAll() { if (confirm('ÊTES-VOUS SÛR ? Cette action déconnectera tous les utilisateurs actifs.')) { broadcastAlertToServer({ type: 'FORCE_LOGOUT_ALL', severity: 'CRITICAL', description: 'Déconnexion forcée de toutes les sessions par administrateur', timestamp: new Date().toISOString() }); addLogEntry('Déconnexion forcée de toutes les sessions', 'error', 'AUTH'); } } function initializeSystems() { // Initialize UI initLiveChart(); initMap(); // Connect WebSocket for real-time alerts connectWebSocket(); // Start Real-time Data Fetching from Backend fetchStats(); setInterval(fetchStats, 1000); startVulnStream(); startInfraStream(); startMapStream(); initCognitiveEngine(); startCognitiveStream(); startLogStream(); // Initialize USB monitoring simulation simulateUSBMonitoring(); } // Access Control Monitoring function startAccessMonitoring() { // Simulate active sessions monitoring updateSessionsTable(); setInterval(updateSessionsTable, 5000); // Simulate file access monitoring simulateFileAccessMonitoring(); } function updateSessionsTable() { const tbody = document.getElementById('sessions-table'); if (!tbody) return; const sessions = [ { user: currentUser, ip: '192.168.1.100', time: new Date().toLocaleTimeString(), level: 'ADMIN_T3', status: 'Active' }, { user: 'AGENT_4521', ip: '192.168.1.45', time: '09:15:32', level: 'OPERATOR', status: 'Active' }, { user: 'TECH_8842', ip: '10.0.0.15', time: '08:30:12', level: 'TECHNICIAN', status: 'Idle' } ]; tbody.innerHTML = sessions.map(s => ` ${s.user} ${s.ip} ${s.time} ${s.level} ${s.status} ${s.user !== currentUser ? `` : 'Current'} `).join(''); document.getElementById('active-sessions').textContent = sessions.length; document.getElementById('admin-sessions').textContent = sessions.filter(s => s.level === 'ADMIN_T3').length; } function terminateSession(username) { addLogEntry(`Session terminée: ${username}`, 'warning', 'AUTH'); updateSessionsTable(); } // USB Device Monitoring function simulateUSBMonitoring() { const usbDevices = [ { name: 'SanDisk Cruzer 32GB', vid: '0781', pid: '5567', status: 'blocked', type: 'storage' }, { name: 'Logitech Mouse', vid: '046d', pid: 'c52b', status: 'allowed', type: 'hid' }, { name: 'Unknown Device', vid: '1234', pid: '5678', status: 'pending', type: 'unknown' } ]; const container = document.getElementById('usb-monitor'); if (!container) return; container.innerHTML = usbDevices.map(dev => `
${dev.name}
VID:${dev.vid} PID:${dev.pid} | ${dev.type}
${dev.status} ${dev.status === 'pending' ? ` ` : ''}
`).join(''); if (typeof feather !== 'undefined') feather.replace(); } function authorizeUSB(vid, pid) { addLogEntry(`USB Autorisé: VID:${vid} PID:${pid}`, 'success', 'USB'); simulateUSBMonitoring(); } function blockUSB(vid, pid) { addLogEntry(`USB Bloqué: VID:${vid} PID:${pid}`, 'error', 'USB'); simulateUSBMonitoring(); } function authorizeAllUSB() { addLogEntry('Tous les périphériques USB autorisés', 'warning', 'USB'); simulateUSBMonitoring(); } function blockAllUSB() { addLogEntry('Tous les périphériques USB bloqués', 'error', 'USB'); simulateUSBMonitoring(); } // File Access Monitoring function simulateFileAccessMonitoring() { const sensitiveFiles = [ { file: '/secure/taj/TAJ_2024.db', user: 'AGENT_4521', action: 'READ', time: new Date().toLocaleTimeString() }, { file: '/secure/dgfip/FICoba_National.db', user: 'ADMIN_SYS', action: 'READ', time: new Date().toLocaleTimeString() }, { file: '/secure/fpr/FPR_Access.log', user: 'SYSTEM', action: 'WRITE', time: new Date().toLocaleTimeString() } ]; const container = document.getElementById('file-access-log'); if (!container) return; container.innerHTML = sensitiveFiles.map(f => `
${f.file.split('/').pop()} ${f.user}
${f.action}
`).join(''); } // Ingress Monitoring (what enters) function startIngressMonitoring() { const container = document.getElementById('ingress-logs'); if (!container) return; const ingressEvents = [ { type: 'CONNECTION', src: '185.220.101.42:4444', dst: '192.168.1.100:443', status: 'BLOCKED', proto: 'TCP' }, { type: 'DOWNLOAD', file: 'update.exe', size: '2.4MB', status: 'SCANNING', user: 'AGENT_4521' }, { type: 'EMAIL', from: 'suspect@phishing.ru', to: 'admin@interieur.fr', status: 'QUARANTINED', subject: 'Urgent: Mise à jour' }, { type: 'AUTH', user: 'TECH_8842', src: '10.0.0.15', status: 'SUCCESS', method: 'RSA-Key' } ]; setInterval(() => { const evt = ingressEvents[Math.floor(Math.random() * ingressEvents.length)]; const time = new Date().toLocaleTimeString(); let colorClass = 'text-gray-400'; let statusColor = 'text-gray-500'; if (evt.status === 'BLOCKED' || evt.status === 'QUARANTINED') { colorClass = 'text-red-400'; statusColor = 'text-red-400'; } else if (evt.status === 'SUCCESS') { colorClass = 'text-green-400'; statusColor = 'text-green-400'; } else if (evt.status === 'SCANNING') { colorClass = 'text-yellow-400'; statusColor = 'text-yellow-400'; } const line = document.createElement('div'); line.className = `font-mono text-xs ${colorClass} border-l-2 ${evt.status === 'BLOCKED' ? 'border-red-500 bg-red-900/10' : 'border-gray-700'} pl-2 py-1`; line.innerHTML = ` [${time}] ${evt.type} ${evt.src || evt.file || evt.from} → ${evt.dst || evt.user || evt.to} ${evt.status} `; container.prepend(line); if (container.children.length > 50) container.lastChild.remove(); if (evt.status === 'BLOCKED' || evt.status === 'QUARANTINED') { addLogEntry(`Ingress bloqué: ${evt.type} depuis ${evt.src || evt.from}`, 'error', 'INGRESS'); } }, 3000); } // Egress Monitoring (what exits - Data Exfiltration Prevention) function startEgressMonitoring() { let totalVolume = 0; setInterval(() => { // Simulate egress traffic const volume = Math.random() * 50; // MB totalVolume += volume; const isBlocked = Math.random() > 0.8; const isSuspicious = Math.random() > 0.7; const blockedEl = document.getElementById('blocked-files'); const suspectEl = document.getElementById('suspect-conn'); const volumeEl = document.getElementById('egress-volume'); const rateEl = document.getElementById('egress-rate'); if (blockedEl && isBlocked) { blockedEl.textContent = parseInt(blockedEl.textContent || 0) + 1; addEgressAlert('Tentative d\'exfiltration bloquée', 'Fichier TAJ détecté dans flux sortant', 'CRITICAL'); } if (suspectEl && isSuspicious) { suspectEl.textContent = parseInt(suspectEl.textContent || 0) + 1; addEgressAlert('Connexion sortante suspecte', 'DNS tunneling détecté vers 185.220.101.42', 'HIGH'); } // Update stats if (volumeEl) volumeEl.textContent = totalVolume.toFixed(1) + ' MB'; if (rateEl) rateEl.textContent = '+' + volume.toFixed(1) + ' MB/s'; // Update analysis updateEgressAnalysis(); }, 2000); } function addEgressAlert(title, detail, severity) { const container = document.getElementById('egress-alerts-log'); const alertsEl = document.getElementById('egress-alerts'); if (!container || !alertsEl) return; const alerts = parseInt(alertsEl.textContent || 0); alertsEl.textContent = alerts + 1; const line = document.createElement('div'); line.className = `p-2 rounded border-l-2 ${severity === 'CRITICAL' ? 'border-red-500 bg-red-900/20' : 'border-yellow-500 bg-yellow-900/10'} animate-fade-in`; line.innerHTML = `
${title}
${detail}
${new Date().toLocaleTimeString()}
`; container.prepend(line); if (container.children.length > 20) container.lastChild.remove(); // Global alert if (severity === 'CRITICAL') { addLogEntry(`EGRESS ALERT: ${title} - ${detail}`, 'error', 'DLP'); playAlertSound(); } } function updateEgressAnalysis() { const container = document.getElementById('egress-analysis'); if (!container) return; const processes = [ { name: 'chrome.exe', status: 'Autorisé', width: 15, color: 'bg-green-500', dest: 'google.com', size: '1.2 MB' }, { name: 'outlook.exe', status: 'Limité', width: 45, color: 'bg-yellow-500', dest: 'smtp.office365.com', size: '8.4 MB' }, { name: 'svchost.exe', status: 'Surveillance', width: 30, color: 'bg-orange-500', dest: 'windowsupdate.com', size: '2.1 MB' }, { name: 'unknown_process', status: 'Bloqué', width: 0, color: 'bg-red-500', dest: 'BLOCKED', size: '0 MB' } ]; container.innerHTML = processes.map(p => `
${p.name} ${p.status}
${p.dest} ${p.size}
`).join(''); } function enableStrictMode() { if (confirm('Activer le mode STRICT ? Tous les flux sortants non essentiels seront bloqués.')) { addLogEntry('MODE STRICT activé - Egress filtering renforcé', 'error', 'DLP'); addEgressAlert('Mode Strict Activé', 'Tous les transferts > 1Mo nécessitent autorisation', 'INFO'); } } function clearEgressAlerts() { const alertsEl = document.getElementById('egress-alerts'); if (alertsEl) alertsEl.textContent = '0'; const container = document.getElementById('egress-alerts-log'); if (container) container.innerHTML = ''; } function refreshAccessLogs() { addLogEntry('Rafraîchissement des logs d\'accès...', 'info', 'AUTH'); updateSessionsTable(); simulateFileAccessMonitoring(); simulateUSBMonitoring(); } // WebSocket Connection for Critical Alerts function connectWebSocket() { const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const wsUrl = `${protocol}//${window.location.hostname}:3000`; console.log('🔌 Connexion WebSocket:', wsUrl); ws = new WebSocket(wsUrl); ws.onopen = () => { console.log('🔌 Connecté au SOC temps réel'); updateSystemStatus('online'); }; ws.onmessage = (event) => { const data = JSON.parse(event.data); handleRealtimeAlert(data); }; ws.onerror = (error) => { console.error('WebSocket erreur:', error); updateSystemStatus('error'); }; ws.onclose = () => { console.log('Déconnecté - Reconnexion dans 5s...'); updateSystemStatus('offline'); setTimeout(connectWebSocket, 5000); }; } function handleRealtimeAlert(data) { // Vérifier que data existe if (!data) return; // Jouer son d'alerte si critique if (data.severity === 'CRITICAL' || data.severity === 'HIGH') { playAlertSound(); showToastAlert(data); // Notification urgente pour administration if (data.type && (data.type.includes('EXFILTRATION') || data.type.includes('EMAIL') || data.type.includes('SENSITIVE'))) { showEmergencyAlert(data); } } // Mettre à jour l'interface selon le type avec vérifications null switch(data.type) { case 'SUSPICIOUS_CONNECTION': if (data.data && data.data.peer) { addLogEntry(`Connexion suspecte: ${data.data.peer}:${data.data.peerPort || 'N/A'}`, 'error', data.data.peer); } break; case 'BRUTE_FORCE_DETECTED': const count = data.count || 0; const ip = (data.ips && data.ips.length > 0) ? data.ips[0] : 'UNKNOWN'; addLogEntry(`Brute Force (${count} tentatives)`, 'error', ip); incrementThreatCounter(count); break; case 'IP_BLOCKED': addLogEntry(`IP bloquée: ${data.ip || 'UNKNOWN'}`, 'success', 'SYSTEM'); break; case 'PROCESS_ALERT': if (data.data && data.data.length > 0 && data.data[0].name) { addLogEntry(`Processus suspect: ${data.data[0].name}`, 'warning', 'LOCAL'); } break; // NOUVEAUX: Alertes spécifiques administration française case 'DATA_EXFILTRATION_DETECTED': addLogEntry(`🚨 EXFILTRATION: ${data.description || 'Données sensibles'}`, 'error', 'TAJ/FPR'); incrementThreatCounter(10); break; case 'EMAIL_COMPROMISE': if (data.data) { const user = data.data.user || 'UNKNOWN'; const country = data.data.country || 'UNKNOWN'; const ip = data.data.ip || 'UNKNOWN'; addLogEntry(`📧 MESSAGERIE COMPROMISE: ${user} depuis ${country}`, 'error', ip); } break; case 'SENSITIVE_FILE_ACCESS': if (data.data) { const isBanking = data.data.type === 'FINANCES'; const prefix = isBanking ? '🏦 FICoba/DGFiP:' : '🔒'; const file = data.data.file || 'UNKNOWN'; const volume = data.data.volume || 'N/A'; addLogEntry(`${prefix} ACCÈS ${file} (${volume})`, 'error', data.data.type || 'SYSTEM'); if (isBanking) { const records = data.data.records || 'N/A'; showEmergencyAlert({ type: 'FICOBa_BREACH_ATTEMPT', severity: 'CRITICAL', description: `Tentative d'accès au fichier des comptes bancaires: ${file}. ${records} comptes potentiellement concernés.`, timestamp: data.timestamp || new Date().toISOString() }); } } break; case 'CREDENTIAL_STOLEN': if (data.data) { const user = data.data.user || 'UNKNOWN'; const source = data.data.source || 'UNKNOWN'; addLogEntry(`🔑 CODE ACCÈS VOLÉ: ${user} via ${source}`, 'warning', 'AUTH'); } break; case 'USB_DETECTED': if (data.device) { addLogEntry(`USB Détecté: ${data.device.model || 'Unknown'}`, 'info', 'USB'); } break; case 'USB_BLOCKED': if (data.device) { addLogEntry(`USB Bloqué: ${data.device.model || 'Unknown'}`, 'error', 'USB'); } break; case 'FILE_ACCESS': case 'FILE_MODIFIED': case 'SENSITIVE_FILE_CREATED': if (data.file) { addLogEntry(`Fichier: ${data.type} - ${data.file}`, data.severity === 'CRITICAL' ? 'error' : 'warning', 'FS'); } break; } } // NOUVEAU: Alerte d'urgence en plein écran pour incidents critiques function showEmergencyAlert(data) { if (!data) return; const existing = document.getElementById('emergency-alert'); if (existing) existing.remove(); const alertType = data.type || 'UNKNOWN_ALERT'; const description = data.description || 'Menace détectée sur infrastructure sensible'; const alert = document.createElement('div'); alert.id = 'emergency-alert'; alert.className = 'fixed inset-0 bg-red-900/90 z-[100] flex items-center justify-center backdrop-blur-sm animate-fade-in'; alert.innerHTML = `

Alerte Critique Administration

${new Date().toLocaleTimeString('fr-FR')}

${alertType.replace(/_/g, ' ')}

${description}

`; document.body.appendChild(alert); if (typeof feather !== 'undefined') feather.replace(); } // NOUVEAU: Fonctions de réponse aux incidents async function blockIP(ip) { try { const response = await fetch('http://localhost:3000/api/block-ip', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ip: ip, reason: 'Attaque administration française' }) }); const data = await response.json(); addLogEntry(`IP ${ip} bloquée définitivement`, 'success', 'FIREWALL'); } catch (e) { addLogEntry(`Échec blocage IP ${ip}`, 'error', 'SYSTEM'); } } function isolateSystem() { addLogEntry('🔒 ISOLEMENT DU SYSTÈME ENGAGÉ', 'error', 'ADMIN'); showToastAlert({ type: 'SYSTEM_ISOLATION', severity: 'CRITICAL', description: 'Réseau segmenté, accès externes coupés', timestamp: new Date().toISOString() }); } function revokeCredentials() { addLogEntry('🔑 RÉVOCATION MASSIVE DES ACCÈS', 'warning', 'ADMIN'); alert('Tous les tokens de session ont été révoqués. Reconnexion requise pour tous les agents.'); } function exportReport() { const report = { date: new Date().toISOString(), administration: 'Ministère de l\'Intérieur (Simulation)', incidents: [], // Récupérer depuis les logs visibles si besoin status: 'Rapport généré par CyberShield SOC' }; console.log('Rapport exporté:', report); addLogEntry('📄 Rapport d\'incident exporté', 'info', 'REPORT'); alert('Rapport d\'incident exporté vers le SI-Central'); } function showToastAlert(data) { if (!data) return; // Créer une notification toast pour alertes critiques const toast = document.createElement('div'); toast.className = 'fixed top-4 right-4 bg-red-600 text-white px-6 py-4 rounded-lg shadow-2xl z-50 animate-slide-in border-l-4 border-red-300 flex items-center'; toast.style.animation = 'slideInRight 0.3s ease-out'; toast.innerHTML = `
${data.type || 'ALERTE'}
${data.timestamp ? new Date(data.timestamp).toLocaleTimeString('fr-FR') : new Date().toLocaleTimeString('fr-FR')}
`; document.body.appendChild(toast); if (typeof feather !== 'undefined') feather.replace(); setTimeout(() => { toast.remove(); }, 5000); } function updateSystemStatus(status) { const statusEl = document.getElementById('status-text'); if (!statusEl) return; const indicator = statusEl.parentElement.nextElementSibling; if (status === 'online') { statusEl.innerText = 'Connecté - Temps Réel (PROD)'; statusEl.className = 'text-green-400 font-mono font-bold'; if (indicator) indicator.className = 'w-2 h-2 bg-green-400 rounded-full animate-pulse'; } else if (status === 'error') { statusEl.innerText = 'Erreur Connexion'; statusEl.className = 'text-red-400 font-mono'; if (indicator) indicator.className = 'w-2 h-2 bg-red-500 rounded-full'; } else { statusEl.innerText = 'Hors ligne'; statusEl.className = 'text-gray-400 font-mono'; if (indicator) indicator.className = 'w-2 h-2 bg-gray-500 rounded-full'; } } function incrementThreatCounter(count = 1) { // Trouve le compteur spécifique des menaces (premier counter) const counter = document.querySelector('.counter[data-target]') || document.querySelector('.counter'); if (counter) { let current = parseInt(counter.innerText.replace(/,/g, '')) || 0; current += count; counter.innerText = current.toLocaleString(); } } // --- Sound Manager --- function initAudio() { if (!audioCtx) { audioCtx = new (window.AudioContext || window.webkitAudioContext)(); } } function toggleSound() { soundEnabled = !soundEnabled; const btn = document.getElementById('btn-sound'); const icon = btn.querySelector('i'); if (soundEnabled) { icon.setAttribute('data-feather', 'volume-2'); icon.classList.replace('text-gray-400', 'text-cyber-primary'); playBeep(600, 'sine', 0.1); // Confirmation beep } else { icon.setAttribute('data-feather', 'volume-x'); icon.classList.replace('text-cyber-primary', 'text-gray-400'); } feather.replace(); } function playAlertSound() { if (!soundEnabled || !audioCtx) return; const osc = audioCtx.createOscillator(); const gain = audioCtx.createGain(); osc.type = 'sawtooth'; osc.frequency.setValueAtTime(440, audioCtx.currentTime); osc.frequency.exponentialRampToValueAtTime(880, audioCtx.currentTime + 0.1); gain.gain.setValueAtTime(0.1, audioCtx.currentTime); gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.3); osc.connect(gain); gain.connect(audioCtx.destination); osc.start(); osc.stop(audioCtx.currentTime + 0.3); } // 0. Navigation Logic (SPA) function navigateTo(viewId) { // Hide all views document.querySelectorAll('[id^="view-"]').forEach(el => el.classList.add('hidden')); // Show selected document.getElementById(`view-${viewId}`).classList.remove('hidden'); // Reset Nav Styles document.querySelectorAll('.nav-link').forEach(el => { el.classList.remove('active', 'bg-gray-800/50', 'text-cyber-primary', 'border-gray-700'); el.classList.add('text-gray-400'); }); // Set Active Nav const activeNav = document.getElementById(`nav-${viewId}`); if(activeNav) { activeNav.classList.add('active', 'bg-gray-800/50', 'text-cyber-primary', 'border-gray-700'); activeNav.classList.remove('text-gray-400'); } // Re-init icons feather.replace(); } // 1. Real-time Chart Initialization avec données réseau réelles let trafficHistory = []; function initLiveChart() { const chartContainer = document.getElementById('liveChart'); const barCount = 50; // Create initial bars for(let i = 0; i < barCount; i++) { const bar = document.createElement('div'); bar.className = 'bg-cyber-primary w-1.5 rounded-t-sm opacity-60 transition-all duration-300 ease-in-out hover:opacity-100 hover:bg-white'; bar.style.height = '10%'; chartContainer.appendChild(bar); trafficHistory.push(10); } } function updateTrafficChart(currentTraffic) { const chartContainer = document.getElementById('liveChart'); if (!chartContainer || chartContainer.children.length === 0) return; // Décaler l'historique trafficHistory.shift(); trafficHistory.push(currentTraffic); // Mettre à jour les barres visuellement const bars = chartContainer.children; const maxTraffic = Math.max(...trafficHistory, 100); // Échelle dynamique for (let i = 0; i < bars.length; i++) { const percentage = (trafficHistory[i] / maxTraffic) * 100; bars[i].style.height = `${Math.max(percentage, 5)}%`; // Coloration selon l'intensité if (percentage > 80) { bars[i].className = 'bg-red-500 w-1.5 rounded-t-sm shadow-[0_0_10px_rgba(239,68,68,0.8)] transition-all duration-300'; } else if (percentage > 50) { bars[i].className = 'bg-yellow-400 w-1.5 rounded-t-sm transition-all duration-300'; } else { bars[i].className = 'bg-cyber-primary w-1.5 rounded-t-sm opacity-60 transition-all duration-300 ease-in-out hover:opacity-100 hover:bg-white'; } } } // 2. Fetch Statistics from Backend API avec données réelles let previousAlertCount = 0; async function fetchStats() { try { const response = await fetch('http://localhost:3000/api/stats'); if (!response.ok) throw new Error('Network response was not ok'); const data = await response.json(); // Vérifier nouvelles alertes critiques if (data.criticalAlerts > previousAlertCount) { playAlertSound(); // Notification visuelle urgente document.querySelectorAll('.counter')[3].parentElement.parentElement.classList.add('pulse-alert'); setTimeout(() => { document.querySelectorAll('.counter')[3].parentElement.parentElement.classList.remove('pulse-alert'); }, 2000); } previousAlertCount = data.criticalAlerts; // Update Dashboard Data avec animation updateCounterAnimated(document.querySelector('.counter'), data.threatsBlocked); // Santé serveur avec couleur dynamique const healthEl = document.querySelectorAll('.counter')[1].nextElementSibling; healthEl.innerText = data.serverHealth + "%"; if (data.serverHealth < 50) healthEl.className = 'text-3xl font-bold text-red-500 mt-2'; else if (data.serverHealth < 80) healthEl.className = 'text-3xl font-bold text-yellow-400 mt-2'; else healthEl.className = 'text-3xl font-bold text-cyber-secondary mt-2'; // Trafic réseau document.querySelectorAll('.counter')[2].previousElementSibling.lastElementChild.innerText = data.networkTraffic + " MB/s"; updateTrafficChart(data.networkTraffic); // Alertes avec formatage const alertEl = document.querySelectorAll('.counter')[3]; alertEl.innerText = data.criticalAlerts.toString().padStart(2, '0'); if (data.criticalAlerts > 0) { alertEl.classList.add('text-red-500'); } } catch (error) { console.error('Erreur fetch stats:', error); updateSystemStatus('error'); } } function updateCounterAnimated(element, targetValue) { if (!element) return; const current = parseInt(element.innerText.replace(/,/g, '')) || 0; if (current !== targetValue) { element.innerText = targetValue.toLocaleString(); // Effet visuel de mise à jour element.style.transform = 'scale(1.1)'; setTimeout(() => element.style.transform = 'scale(1)', 200); } } // 3. Gestion des logs temps réel function addLogEntry(message, type, ip) { const container = document.getElementById('logContainer'); if (!container) return; const logLine = document.createElement('div'); logLine.className = 'log-entry flex justify-between border-b border-gray-900 pb-1 mb-1 animate-fade-in'; let colorClass = 'text-gray-400'; if(type === 'error') colorClass = 'text-red-400'; if(type === 'success') colorClass = 'text-green-400'; if(type === 'warning') colorClass = 'text-yellow-400'; const time = new Date().toLocaleTimeString('fr-FR', { hour12: false }); logLine.innerHTML = ` [${time}] ${message} (${ip || 'SYSTEM'}) ${type.toUpperCase()} `; container.prepend(logLine); // Garder seulement les 50 dernières entrées while(container.children.length > 50) { container.lastElementChild.remove(); } } async function startLogStream() { // Récupération initiale puis via WebSocket principalement try { const response = await fetch('http://localhost:3000/api/log'); const data = await response.json(); addLogEntry(data.msg, data.type, data.ip); } catch (e) { addLogEntry('Initialisation du système de logs...', 'info', 'LOCAL'); } } // Fallback to simulate data if user doesn't run the server function simulateFallbackData() { // Just ensures the chart keeps moving if no server is present const chartContainer = document.getElementById('liveChart'); if(!chartContainer.children.length) initLiveChart(); const bars = chartContainer.children; for(let i = 0; i < bars.length - 1; i++) { bars[i].style.height = bars[i+1].style.height; } const lastBar = bars[bars.length - 1]; const newHeight = Math.floor(Math.random() * 90) + 10; lastBar.style.height = `${newHeight}%`; if(newHeight > 80) { lastBar.className = 'bg-red-500 w-2 rounded-t-sm shadow-[0_0_10px_rgba(239,68,68,0.8)] transition-all duration-300'; } else if (newHeight > 50) { lastBar.className = 'bg-yellow-400 w-2 rounded-t-sm transition-all duration-300'; } else { lastBar.className = 'bg-cyber-primary w-2 rounded-t-sm opacity-50 transition-all duration-300'; } } // --- NEW FEATURES: MAP, VULNS, INFRA --- // 4. Threat Map Logic function initMap() { // Clear existing svg lines if any const svg = document.getElementById('map-svg-layer'); while (svg.lastChild) { svg.removeChild(svg.lastChild); } } async function startMapStream() { const container = document.getElementById('geo-log-container'); const mapArea = document.getElementById('attack-map-container'); if (!container || !mapArea) return; if (!document.getElementById('map-svg-layer')) { const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.id = "map-svg-layer"; svg.style.position = "absolute"; svg.style.top = "0"; svg.style.left = "0"; svg.style.width = "100%"; svg.style.height = "100%"; svg.style.pointerEvents = "none"; svg.style.zIndex = "5"; mapArea.appendChild(svg); } const svg = document.getElementById('map-svg-layer'); const fetchMapData = async () => { try { const response = await fetch('http://localhost:3000/api/geo'); const data = await response.json(); // Add Log avec badge pays const logLine = document.createElement('div'); logLine.className = 'border-b border-gray-900 pb-1 text-xs font-mono animate-fade-in flex justify-between items-center'; logLine.innerHTML = `
${data.country} ${data.type} from ${data.ip}
${new Date(data.timestamp).toLocaleTimeString('fr-FR')} `; container.prepend(logLine); if(container.children.length > 20) container.lastChild.remove(); // Animation sur la carte const node = document.createElement('div'); node.className = 'geo-node'; const top = Math.random() * 80 + 10; const left = Math.random() * 80 + 10; node.style.top = `${top}%`; node.style.left = `${left}%`; mapArea.appendChild(node); const line = document.createElementNS("http://www.w3.org/2000/svg", "line"); line.setAttribute("x1", `${left}%`); line.setAttribute("y1", `${top}%`); line.setAttribute("x2", "50%"); line.setAttribute("y2", "50%"); line.setAttribute("stroke", data.real ? "#ff0000" : "#00f0ff"); line.setAttribute("stroke-width", "2"); line.setAttribute("stroke-opacity", "0.8"); line.setAttribute("stroke-dasharray", "5,5"); const animate = document.createElementNS("http://www.w3.org/2000/svg", "animate"); animate.setAttribute("attributeName", "stroke-dashoffset"); animate.setAttribute("from", "100"); animate.setAttribute("to", "0"); animate.setAttribute("dur", "0.5s"); animate.setAttribute("repeatCount", "1"); line.appendChild(animate); svg.appendChild(line); // Impact visuel au centre (cible) const target = document.createElement('div'); target.className = 'absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-4 h-4 bg-red-500 rounded-full animate-ping'; mapArea.appendChild(target); setTimeout(() => { node.remove(); line.remove(); target.remove(); }, 2000); } catch(e) { console.error('Erreur carte:', e); } }; // Plus fréquent si données réelles disponibles setInterval(fetchMapData, 2000); } // --- 7. Terminal Logic --- function toggleAIChat() { const modal = document.getElementById('ai-chat-modal'); if (modal.classList.contains('hidden')) { // Opening modal.classList.remove('hidden'); // Small delay to allow CSS display property to apply before removing transform/opacity setTimeout(() => { modal.classList.remove('translate-y-4', 'opacity-0'); }, 10); document.getElementById('ai-input').focus(); } else { // Closing modal.classList.add('translate-y-4', 'opacity-0'); // Wait for transition to finish before setting display: none setTimeout(() => { modal.classList.add('hidden'); }, 300); } } function setupAIChat() { const input = document.getElementById('ai-input'); input.addEventListener('keypress', function (e) { if (e.key === 'Enter') sendAIMessage(); }); } function sendAIMessage() { const input = document.getElementById('ai-input'); const text = input.value.trim(); if(!text) return; const history = document.getElementById('chat-history'); // User Message const userMsg = `
${text}
`; history.innerHTML += userMsg; input.value = ''; history.scrollTop = history.scrollHeight; // AI Simulation Response setTimeout(() => { let response = "Analyse en cours..."; const lowerText = text.toLowerCase(); if(lowerText.includes("menace") || lowerText.includes("threat")) { response = "J'ai analysé les 30 dernières minutes. Une tentative d'intrusion de type 'Brute Force' a été détectée sur le port 22. Elle a été bloquée automatiquement."; } else if (lowerText.includes("serveur") || lowerText.includes("server")) { response = "Les serveurs、主 인프라 sont sains. L'utilisation du CPU est stable à 24%. Aucun goulot d'étranglement détecté."; } else if (lowerText.includes("optimiser") || lowerText.includes("optimize")) { response = "Recommandation: Activer le protocole de mise en cache avancées sur le noeud DB-01 pour réduire la latence de 15%."; } else { response = "Données non traitées. Voulez-vous que je lance une analyse approfondie du pare-feu ?"; } const aiMsg = `
${response}
`; history.innerHTML += aiMsg; history.scrollTop = history.scrollHeight; feather.replace(); }, 800); } function toggleTerminal() { const modal = document.getElementById('terminal-modal'); const input = document.getElementById('terminal-input'); if (modal.classList.contains('hidden')) { modal.classList.remove('hidden'); input.focus(); } else { modal.classList.add('hidden'); } } function setupTerminal() { const input = document.getElementById('terminal-input'); const output = document.getElementById('terminal-output'); input.addEventListener('keypress', function (e) { if (e.key === 'Enter') { const command = input.value.trim(); if (command) { printToTerminal(`root@sys:~$ ${command}`); executeCommand(command); } input.value = ''; } }); } function printToTerminal(text, color = 'text-green-400') { const output = document.getElementById('terminal-output'); const p = document.createElement('p'); p.className = color + " font-mono"; p.innerText = text; output.appendChild(p); output.scrollTop = output.scrollHeight; } async function executeCommand(cmd) { const output = document.getElementById('terminal-output'); const args = cmd.split(' '); const command = args[0].toLowerCase(); // Realistic SOC terminal commands switch(command) { case 'help': case '?': printToTerminal("CYBERSHIELD SOC v3.0 - Commandes disponibles:", "text-cyber-primary"); printToTerminal(" netstat - Affiche les connexions actives"); printToTerminal(" ps - Liste des processus suspects"); printToTerminal(" kill [PID] - Termine un processus"); printToTerminal(" block [IP] - Bloque une adresse IP au firewall"); printToTerminal(" isolate - Mode confinement d'urgence"); printToTerminal(" scan [target] - Scan de vulnérabilités rapide"); printToTerminal(" clear - Nettoie le terminal"); printToTerminal(" status - État des systèmes"); break; case 'netstat': printToTerminal("Connexions réseau actives:", "text-yellow-400"); setTimeout(() => { printToTerminal("tcp ESTABLISHED 192.168.1.100:443 -> 185.220.101.42:4444 [SUSPECT]", "text-red-400"); printToTerminal("tcp ESTABLISHED 192.168.1.5:22 -> 10.0.0.15:22 [SSH]", "text-green-400"); printToTerminal("udp OPEN 0.0.0.0:53 -> 8.8.8.8:53 [DNS]", "text-gray-400"); printToTerminal("tcp LISTEN 0.0.0.0:8080 -> 0.0.0.0:0 [HTTP]", "text-gray-400"); }, 300); break; case 'ps': printToTerminal("Processus en cours:", "text-yellow-400"); setTimeout(() => { printToTerminal("PID USER CPU MEM COMMAND", "text-gray-500"); printToTerminal("1 root 0.1 0.2 /sbin/init", "text-gray-400"); printToTerminal("1842 www-data 45.2 12.5 /usr/bin/python3 -m http.server [SUSPECT]", "text-red-400"); printToTerminal("2156 mysql 2.1 8.4 mysqld --daemonize", "text-gray-400"); printToTerminal("3421 root 0.0 0.1 /bin/bash /tmp/.hidden/script.sh [MALICIOUS]", "text-red-400 font-bold"); }, 300); break; case 'kill': if (args[1]) { printToTerminal(`Envoi du signal SIGTERM au processus ${args[1]}...`, "text-yellow-400"); setTimeout(() => { printToTerminal(`Processus ${args[1]} terminé.`, "text-green-400"); addLogEntry(`Processus ${args[1]} terminé manuellement via terminal`, 'warning', 'ADMIN'); }, 500); } else { printToTerminal("Usage: kill [PID]", "text-red-400"); } break; case 'block': if (args[1]) { const ip = args[1]; if (/^(\d{1,3}\.){3}\d{1,3}$/.test(ip)) { printToTerminal(`Blocage de l'IP ${ip}...`, "text-yellow-400"); setTimeout(() => { printToTerminal(`iptables -A INPUT -s ${ip} -j DROP`, "text-gray-500"); printToTerminal(`IP ${ip} bloquée avec succès.`, "text-green-400"); blockIP(ip); }, 600); } else { printToTerminal("IP invalide.", "text-red-400"); } } else { printToTerminal("Usage: block [IP]", "text-red-400"); } break; case 'isolate': printToTerminal("INITIATION DU CONFINEMENT D'URGENCE...", "text-red-400 font-bold"); setTimeout(() => { printToTerminal("[-] Coupure des interfaces réseau externes...", "text-yellow-400"); printToTerminal("[-] Isolation du VLAN sensibles...", "text-yellow-400"); printToTerminal("[-] Preservation des logs forensiques...", "text-yellow-400"); printToTerminal("[✓] SYSTÈME ISOLÉ - Mode quarantaine actif", "text-green-400 font-bold"); isolateSystem(); }, 1000); break; case 'scan': const target = args[1] || 'localhost'; printToTerminal(`Lancement du scan de vulnérabilités sur ${target}...`, "text-yellow-400"); setTimeout(() => { printToTerminal("[*] Scan des ports ouverts...", "text-gray-500"); printToTerminal("[!] Port 22/tcp open SSH - Version outdated", "text-orange-400"); printToTerminal("[!] Port 3389/tcp open RDP - Vulnérable à BlueKeep", "text-red-400"); printToTerminal("[*] Scan terminé. 2 vulnérabilités trouvées.", "text-green-400"); }, 2000); break; case 'clear': output.innerHTML = ''; break; case 'uptime': const days = Math.floor(Math.random() * 100); const hours = Math.floor(Math.random() * 24); printToTerminal(`System uptime: ${days} days, ${hours} hours`, "text-gray-400"); break; case 'status': printToTerminal("Checking systems...", "text-yellow-400"); setTimeout(() => { printToTerminal("[✓] Firewall: ACTIVE", "text-green-400"); printToTerminal("[✓] IDS/IPS: ONLINE", "text-green-400"); printToTerminal("[✓] SIEM: CONNECTED", "text-green-400"); printToTerminal("[✓] Threat Intel: FEED ACTIVE", "text-green-400"); printToTerminal("[!] Backup: SYNCING...", "text-orange-400"); }, 800); break; default: printToTerminal(`Command not found: ${cmd}. Type 'help' for available commands.`, "text-red-400"); } } // Dark Web Monitor Functions function investigateLeak(leakType) { if (!leakType) return; addLogEntry(`Investigation lancée: ${leakType.toUpperCase()}`, 'info', 'DARKWEB'); showToastAlert({ type: 'DARKWEB_INVESTIGATION', severity: 'HIGH', description: `Analyse forensique de la fuite ${leakType} en cours...`, timestamp: new Date().toISOString() }); } // Packet Capture Simulation let packetCaptureActive = false; function startPacketCapture() { const container = document.getElementById('packet-analyzer'); packetCaptureActive = !packetCaptureActive; if (packetCaptureActive) { addLogEntry('Capture de paquets démarrée sur interface eth0', 'info', 'NETWORK'); container.innerHTML = '
Capture active...
'; const protocols = ['TCP', 'UDP', 'ICMP', 'DNS']; const flags = ['SYN', 'ACK', 'PSH', 'FIN', 'RST']; const interval = setInterval(() => { if (!packetCaptureActive) { clearInterval(interval); return; } const proto = protocols[Math.floor(Math.random() * protocols.length)]; const src = `192.168.1.${Math.floor(Math.random() * 255)}`; const dst = Math.random() > 0.8 ? `185.220.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}` : `10.0.0.${Math.floor(Math.random() * 50)}`; const port = [4444, 5555, 80, 443, 22, 3389][Math.floor(Math.random() * 6)]; const flag = flags[Math.floor(Math.random() * flags.length)]; const isSuspicious = dst.startsWith('185.220') || port === 4444; const colorClass = isSuspicious ? 'text-red-400' : 'text-gray-400'; const alert = isSuspicious ? ' [!SUSPICIOUS]' : ''; const line = document.createElement('div'); line.className = `font-mono text-xs ${colorClass} border-l-2 ${isSuspicious ? 'border-red-500 bg-red-900/10' : 'border-gray-700'} pl-2 mb-1`; line.innerHTML = `[${new Date().toLocaleTimeString()}] ${proto} ${src} -> ${dst}:${port} [${flag}]${alert}`; container.prepend(line); if (container.children.length > 50) container.lastChild.remove(); }, 200); } else { addLogEntry('Capture de paquets arrêtée', 'info', 'NETWORK'); container.innerHTML = '
Capture arrêtée. En attente...
'; } } // Emergency Lockdown function emergencyLockdown() { if (!confirm('ÊTES-VOUS SÛR ? Cette action coupera TOUTES les connexions réseau et isolera le système.')) return; addLogEntry('🔒 CONFINEMENT D\'URGENCE ACTIVÉ PAR ADMINISTRATEUR', 'error', 'EMERGENCY'); // Update all network status to offline document.getElementById('status-eth').innerText = 'COUPÉ'; document.getElementById('status-eth').className = 'text-red-500 font-mono animate-pulse'; document.getElementById('icon-eth').classList.add('text-red-500'); document.getElementById('status-wifi').innerText = 'COUPÉ'; document.getElementById('status-wifi').className = 'text-red-500 font-mono animate-pulse'; document.getElementById('icon-wifi').classList.add('text-red-500'); // Show emergency modal const modal = document.createElement('div'); modal.className = 'fixed inset-0 bg-red-900/95 z-[200] flex items-center justify-center'; modal.innerHTML = `

SYSTÈME EN CONFINEMENT

Toutes les interfaces réseau ont été désactivées.

`; document.body.appendChild(modal); feather.replace(); playAlertSound(); } // Memory Analysis Simulation function startMemoryAnalysis() { addLogEntry('Analyse mémoire RAM démarrée...', 'info', 'FORENSICS'); showToastAlert({ type: 'FORENSICS_MEMORY', severity: 'INFO', description: 'Dump mémoire en cours - Recherche d\'artefacts malveillants', timestamp: new Date().toISOString() }); setTimeout(() => { addLogEntry('Artefact détecté: Processus injecté dans lsass.exe', 'error', 'FORENSICS'); }, 3000); } // Export Forensic Report function exportForensicReport() { const report = { case_id: 'FR-2025-0129-FICOBa', date: new Date().toISOString(), type: 'Breach Investigation', iocs: ['185.220.101.42', 'ms-office-update.org', 'd41d8cd98f00b204e9800998ecf8427e'], timeline: '28-29 Jan 2025', analyst: 'CyberShield SOC' }; const blob = new Blob([JSON.stringify(report, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `forensic_report_${report.case_id}.json`; a.click(); addLogEntry(`Rapport forensique exporté: ${report.case_id}`, 'success', 'FORENSICS'); } // Add to Blocklist function addToBlocklist() { const iocs = ['185.220.101.42', 'ms-office-update.org']; iocs.forEach(ioc => { if (ioc.includes('.')) { addLogEntry(`IoC ajouté aux listes de blocage: ${ioc}`, 'success', 'THREAT_INTEL'); } }); showToastAlert({ type: 'IOC_BLOCKLIST', severity: 'SUCCESS', description: '3 indicateurs ajoutés aux listes de blocage', timestamp: new Date().toISOString() }); } // Data Exfiltration Visualization function initExfilChart() { const canvas = document.getElementById('dataFlowCanvas'); if (!canvas) return; const ctx = canvas.getContext('2d'); if (!ctx) return; // S'assurer que le canvas a une taille valide canvas.width = canvas.offsetWidth || 400; canvas.height = canvas.offsetHeight || 200; let dataPoints = []; const maxPoints = 50; const normalEl = document.getElementById('normal-traffic'); const suspiciousEl = document.getElementById('suspicious-outbound'); const encryptedEl = document.getElementById('encrypted-ratio'); setInterval(() => { // Simulate data flow const normal = Math.random() * 2 + 1; // 1-3 MB/s normal const suspicious = Math.random() > 0.7 ? Math.random() * 20 + 10 : 0; // Spikes if (normalEl) normalEl.innerText = normal.toFixed(1) + ' MB/s'; if (suspiciousEl) suspiciousEl.innerText = suspicious > 0 ? suspicious.toFixed(1) + ' MB/s' : '0 MB/s'; if (encryptedEl) encryptedEl.innerText = Math.floor(Math.random() * 15 + 80) + '%'; dataPoints.push({ normal, suspicious }); if (dataPoints.length > maxPoints) dataPoints.shift(); // Clear canvas ctx.fillStyle = '#0a0a12'; ctx.fillRect(0, 0, canvas.width, canvas.height); if (dataPoints.length < 2) return; const step = canvas.width / maxPoints; // Draw normal traffic ctx.beginPath(); ctx.strokeStyle = '#00ff9d'; ctx.lineWidth = 2; dataPoints.forEach((p, i) => { const y = canvas.height - (p.normal / 25 * canvas.height); if (i === 0) ctx.moveTo(0, y); else ctx.lineTo(i * step, y); }); ctx.stroke(); // Draw suspicious spikes ctx.beginPath(); ctx.strokeStyle = '#ef4444'; ctx.lineWidth = 2; dataPoints.forEach((p, i) => { if (p.suspicious > 0) { const y = canvas.height - (p.suspicious / 25 * canvas.height); ctx.moveTo(i * step, canvas.height); ctx.lineTo(i * step, y); } }); ctx.stroke(); }, 1000); } // Initialize exfil chart when view loads document.addEventListener('DOMContentLoaded', () => { setTimeout(initExfilChart, 1000); }); // 5. Vulnerabilities Logic avec actions réelles async function startVulnStream() { const tableBody = document.getElementById('vuln-table-body'); const fetchVulns = async () => { try { const response = await fetch('http://localhost:3000/api/vulns'); if (!response.ok) throw new Error('Server unavailable'); const data = await response.json(); // Update Counts avec animation couleur const critEl = document.getElementById('vuln-critical-count'); critEl.innerText = data.stats.critical; if (data.stats.critical > 0) critEl.classList.add('text-red-500', 'animate-pulse'); document.getElementById('vuln-high-count').innerText = data.stats.high; document.getElementById('vuln-med-count').innerText = data.stats.medium; // Render List tableBody.innerHTML = ''; data.list.forEach(vuln => { let color = 'text-blue-400'; let badgeClass = 'bg-blue-500/20 text-blue-400 border-blue-500/30'; if(vuln.score >= 9) { color = 'text-red-400 font-bold'; badgeClass = 'bg-red-500/20 text-red-400 border-red-500/30 animate-pulse'; } else if(vuln.score >= 7) { color = 'text-orange-400'; badgeClass = 'bg-orange-500/20 text-orange-400 border-orange-500/30'; } const row = document.createElement('tr'); row.className = 'hover:bg-gray-800/30 transition border-b border-gray-800/50'; row.innerHTML = ` ${vuln.id} ${vuln.component} ${vuln.score} ${vuln.status} `; tableBody.appendChild(row); }); feather.replace(); } catch(e) { console.error('Erreur vulnérabilités:', e); } }; fetchVulns(); setInterval(fetchVulns, 10000); // Toutes les 10s } // Fonction pour simuler/appliquer un patch async function applyPatch(cveId) { if (!confirm(`Confirmer l'application du patch pour ${cveId} ?`)) return; addLogEntry(`Application du patch ${cveId} en cours...`, 'info', 'ADMIN'); try { // Ici: appel API réel pour déclencher patch management const response = await fetch('http://localhost:3000/api/patch', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ cve: cveId }) }); if (response.ok) { addLogEntry(`Patch ${cveId} appliqué avec succès`, 'success', 'SYSTEM'); playBeep(800, 'sine', 0.2); // Son de succès } } catch (e) { addLogEntry(`Échec application patch ${cveId}`, 'error', 'SYSTEM'); } } // --- COGNITIVE ENGINE LOGIC --- function initCognitiveEngine() { const chartContainer = document.getElementById('predictionChart'); const barCount = 30; for(let i = 0; i < barCount; i++) { const bar = document.createElement('div'); bar.className = 'bg-purple-500/40 w-2 rounded-t-sm transition-all duration-500'; // Simulate a prediction curve let h = 20 + (i * 2) + (Math.random() * 10 - 5); if (h > 90) h = 90; bar.style.height = `${h}%`; // Random anomaly if (Math.random() > 0.95) { bar.classList.add('bg-red-500', 'shadow-[0_0_10px_rgba(239,68,68,0.8)]'); } chartContainer.appendChild(bar); } } function startCognitiveStream() { const container = document.getElementById('cognitive-log'); const insights = [ { type: 'WARNING', text: 'Anomalie de trafic détectée: Protocol SSH handshake failed.', score: '92%' }, { type: 'INFO', text: 'Mise à jour des signatures de pare-feu terminée.', score: '100%' }, { type: 'ANALYSIS', text: 'Pattern reconnu: Attaque DDoS de faible niveau (Type UDP Flood).', score: '88%' }, { type: 'OPTIMIZATION', text: 'Optimisation dynamique: Cache Redis activé sur Cluster A.', score: 'N/A' }, { type: 'DETECTION', text: 'Compte utilisateur "admin" connecté depuis une localisation inhabituelle.', score: '45%' } ]; setInterval(() => { // Randomly pick an insight const item = insights[Math.floor(Math.random() * insights.length)]; const div = document.createElement('div'); div.className = "border-b border-gray-800 pb-2 animate-fade-in"; let color = "text-gray-400"; if(item.type === 'WARNING') color = "text-red-400"; if(item.type === 'OPTIMIZATION') color = "text-green-400"; div.innerHTML = `
[${item.type}] ${item.score}

${item.text}

`; container.prepend(div); if(container.children.length > 10) container.lastChild.remove(); }, 5000); } function generateCognitiveInsight() { const container = document.getElementById('cognitive-log'); const div = document.createElement('div'); div.className = "border-l-2 border-purple-500 pl-3 py-1 bg-purple-900/10 animate-pulse"; div.innerHTML = ` Re-Analyse Terminée

Aucun risque critique identifié. Efficacité du système: 99.8%

`; container.prepend(div); } // 6. Infrastructure Logic avec données réelles système async function startInfraStream() { const container = document.getElementById('server-rack-container'); const fetchInfra = async () => { try { const response = await fetch('http://localhost:3000/api/infra'); if (!response.ok) throw new Error('Network response was not ok'); const data = await response.json(); if(container.children.length === 0) { data.servers.forEach(srv => { const card = document.createElement('div'); card.className = 'server-card p-4 rounded-xl shadow-lg relative'; card.id = `srv-${srv.id}`; container.appendChild(card); }); } data.servers.forEach(srv => { const card = document.getElementById(`srv-${srv.id}`); if(card) { const loadColor = srv.load > 80 ? 'bg-red-500 shadow-[0_0_10px_rgba(239,68,68,0.5)]' : (srv.load > 50 ? 'bg-yellow-400' : 'bg-cyber-secondary'); const tempColor = srv.temp > 70 ? 'text-red-400 animate-pulse' : (srv.temp > 60 ? 'text-yellow-400' : 'text-white'); // Badge de statut dynamique const statusBadge = srv.status === 'Online' ? 'Online' : 'Warning'; card.innerHTML = `

${srv.name}

${statusBadge}
CPU Load ${srv.load}%

RAM

${srv.ram} GB

Temp

${srv.temp}°C

Proc

${srv.processes}

${srv.load > 80 ? '
SURCHARGE CPU DETECTÉE
' : ''}
`; } }); feather.replace(); } catch(e) { console.error('Erreur infrastructure:', e); } }; fetchInfra(); setInterval(fetchInfra, 3000); // Rafraîchissement toutes les 3s }