// Frontend Debug-Server für MYP const express = require('express'); const path = require('path'); const http = require('http'); const si = require('systeminformation'); const os = require('os'); const osUtils = require('os-utils'); const { exec } = require('child_process'); const fetch = require('node-fetch'); const socketIo = require('socket.io'); // Konfiguration const app = express(); const server = http.createServer(app); const io = socketIo(server); const PORT = 6666; const FRONTEND_PORT = 3000; const FRONTEND_HOST = 'localhost'; const BACKEND_HOST = 'localhost'; const BACKEND_PORT = 5000; // View Engine einrichten app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, '../public/views')); app.use(express.static(path.join(__dirname, '../public'))); app.use(express.json()); // Hauptseite rendern app.get('/', async (req, res) => { const hostname = os.hostname(); const networkInterfaces = os.networkInterfaces(); const ipAddresses = {}; // IP-Adressen sammeln Object.keys(networkInterfaces).forEach(interfaceName => { const interfaceInfo = networkInterfaces[interfaceName]; const ipv4Addresses = interfaceInfo.filter(info => info.family === 'IPv4'); if (ipv4Addresses.length > 0) { ipAddresses[interfaceName] = ipv4Addresses[0].address; } }); // Rendere die Hauptseite mit Basisdaten res.render('index', { hostname: hostname, ipAddresses: ipAddresses, timestamp: new Date().toLocaleString('de-DE'), }); }); // API-Endpunkte // Systeminformationen app.get('/api/system', async (req, res) => { try { const [cpu, mem, osInfo, diskLayout, fsSize] = await Promise.all([ si.cpu(), si.mem(), si.osInfo(), si.diskLayout(), si.fsSize() ]); const data = { cpu: { manufacturer: cpu.manufacturer, brand: cpu.brand, speed: cpu.speed, cores: cpu.cores, physicalCores: cpu.physicalCores }, memory: { total: formatBytes(mem.total), free: formatBytes(mem.free), used: formatBytes(mem.used), usedPercent: Math.round(mem.used / mem.total * 100) }, os: { platform: osInfo.platform, distro: osInfo.distro, release: osInfo.release, arch: osInfo.arch, uptime: formatUptime(os.uptime()) }, filesystem: fsSize.map(fs => ({ fs: fs.fs, type: fs.type, size: formatBytes(fs.size), used: formatBytes(fs.used), available: formatBytes(fs.available), mount: fs.mount, usePercent: Math.round(fs.use) })), disks: diskLayout.map(disk => ({ device: disk.device, type: disk.type, name: disk.name, size: formatBytes(disk.size) })) }; res.json(data); } catch (error) { console.error('Fehler beim Abrufen der Systemdaten:', error); res.status(500).json({ error: 'Fehler beim Abrufen der Systemdaten' }); } }); // Netzwerkinformationen app.get('/api/network', async (req, res) => { try { const [netInterfaces, netStats] = await Promise.all([ si.networkInterfaces(), si.networkStats() ]); const dns = await getDnsServers(); const gateway = await getDefaultGateway(); const data = { interfaces: netInterfaces.map(iface => ({ iface: iface.iface, ip4: iface.ip4, ip6: iface.ip6, mac: iface.mac, internal: iface.internal, operstate: iface.operstate, type: iface.type, speed: iface.speed, dhcp: iface.dhcp })), stats: netStats.map(stat => ({ iface: stat.iface, rx_bytes: formatBytes(stat.rx_bytes), tx_bytes: formatBytes(stat.tx_bytes), rx_sec: formatBytes(stat.rx_sec), tx_sec: formatBytes(stat.tx_sec) })), dns: dns, gateway: gateway }; res.json(data); } catch (error) { console.error('Fehler beim Abrufen der Netzwerkdaten:', error); res.status(500).json({ error: 'Fehler beim Abrufen der Netzwerkdaten' }); } }); // Dienststatus app.get('/api/services', async (req, res) => { try { // Prüfen ob Frontend (Next.js) läuft const frontendStatus = await checkServiceStatus(FRONTEND_HOST, FRONTEND_PORT); // Prüfen ob Backend (Flask) läuft const backendStatus = await checkServiceStatus(BACKEND_HOST, BACKEND_PORT); // Docker-Container Status abrufen const containers = await getDockerContainers(); const data = { frontend: { name: 'Next.js Frontend', status: frontendStatus ? 'online' : 'offline', port: FRONTEND_PORT, host: FRONTEND_HOST }, backend: { name: 'Flask Backend', status: backendStatus ? 'online' : 'offline', port: BACKEND_PORT, host: BACKEND_HOST }, docker: { containers: containers } }; res.json(data); } catch (error) { console.error('Fehler beim Abrufen der Dienststatus:', error); res.status(500).json({ error: 'Fehler beim Abrufen der Dienststatus' }); } }); // Ping-Endpunkt für Netzwerkdiagnose app.get('/api/ping/:host', (req, res) => { const host = req.params.host; // Sicherheitscheck für den Hostnamen if (!isValidHostname(host)) { return res.status(400).json({ error: 'Ungültiger Hostname oder IP-Adresse' }); } // Ping-Befehl ausführen exec(`ping -n 4 ${host}`, (error, stdout, stderr) => { if (error) { return res.json({ success: false, output: stderr || stdout, error: error.message }); } res.json({ success: true, output: stdout }); }); }); // Traceroute-Endpunkt für Netzwerkdiagnose app.get('/api/traceroute/:host', (req, res) => { const host = req.params.host; // Sicherheitscheck für den Hostnamen if (!isValidHostname(host)) { return res.status(400).json({ error: 'Ungültiger Hostname oder IP-Adresse' }); } // Traceroute-Befehl ausführen (Windows: tracert, Unix: traceroute) const command = process.platform === 'win32' ? 'tracert' : 'traceroute'; exec(`${command} ${host}`, (error, stdout, stderr) => { // Traceroute kann einen Nicht-Null-Exit-Code zurückgeben, selbst wenn es teilweise erfolgreich ist res.json({ success: true, output: stdout, error: stderr }); }); }); // DNS-Lookup-Endpunkt für Netzwerkdiagnose app.get('/api/nslookup/:host', (req, res) => { const host = req.params.host; // Sicherheitscheck für den Hostnamen if (!isValidHostname(host)) { return res.status(400).json({ error: 'Ungültiger Hostname oder IP-Adresse' }); } // NSLookup-Befehl ausführen exec(`nslookup ${host}`, (error, stdout, stderr) => { if (error) { return res.json({ success: false, output: stderr || stdout, error: error.message }); } res.json({ success: true, output: stdout }); }); }); // Echtzeit-Updates über WebSockets io.on('connection', (socket) => { console.log('Neue WebSocket-Verbindung'); // CPU- und Arbeitsspeichernutzung im Intervall senden const systemMonitorInterval = setInterval(async () => { try { const [cpu, mem] = await Promise.all([ si.currentLoad(), si.mem() ]); socket.emit('system-stats', { cpu: { load: Math.round(cpu.currentLoad), cores: cpu.cpus.map(core => Math.round(core.load)) }, memory: { total: mem.total, used: mem.used, free: mem.free, usedPercent: Math.round(mem.used / mem.total * 100) } }); } catch (error) { console.error('Fehler beim Senden der Systemstatistiken:', error); } }, 2000); // Netzwerkstatistiken im Intervall senden const networkMonitorInterval = setInterval(async () => { try { const netStats = await si.networkStats(); socket.emit('network-stats', { stats: netStats.map(stat => ({ iface: stat.iface, rx_bytes: stat.rx_bytes, tx_bytes: stat.tx_bytes, rx_sec: stat.rx_sec, tx_sec: stat.tx_sec })) }); } catch (error) { console.error('Fehler beim Senden der Netzwerkstatistiken:', error); } }, 2000); // Aufräumen, wenn die Verbindung getrennt wird socket.on('disconnect', () => { console.log('WebSocket-Verbindung getrennt'); clearInterval(systemMonitorInterval); clearInterval(networkMonitorInterval); }); }); // Hilfsfunktionen // Bytes in lesbare Größen formatieren function formatBytes(bytes, decimals = 2) { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i]; } // Uptime in lesbare Zeit formatieren function formatUptime(seconds) { const days = Math.floor(seconds / 86400); const hours = Math.floor((seconds % 86400) / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = Math.floor(seconds % 60); return `${days} Tage, ${hours} Stunden, ${minutes} Minuten, ${secs} Sekunden`; } // Service-Status überprüfen async function checkServiceStatus(host, port) { return new Promise(resolve => { const socket = new (require('net').Socket)(); socket.setTimeout(1000); socket.on('connect', () => { socket.destroy(); resolve(true); }); socket.on('timeout', () => { socket.destroy(); resolve(false); }); socket.on('error', () => { socket.destroy(); resolve(false); }); socket.connect(port, host); }); } // Docker-Container abfragen async function getDockerContainers() { return new Promise((resolve) => { exec('docker ps --format "{{.ID}},{{.Image}},{{.Status}},{{.Ports}},{{.Names}}"', (error, stdout) => { if (error) { resolve([]); return; } const containers = []; const lines = stdout.trim().split('\n'); for (const line of lines) { if (line) { const [id, image, status, ports, name] = line.split(','); containers.push({ id, image, status, ports, name }); } } resolve(containers); }); }); } // DNS-Server abfragen async function getDnsServers() { return new Promise((resolve) => { if (process.platform === 'win32') { // Windows: DNS-Server über PowerShell abfragen exec('powershell.exe -Command "Get-DnsClientServerAddress -AddressFamily IPv4 | Select-Object -ExpandProperty ServerAddresses"', (error, stdout) => { if (error) { resolve(['DNS-Server konnten nicht ermittelt werden']); return; } const servers = stdout.trim().split('\r\n').filter(Boolean); resolve(servers); }); } else { // Unix: DNS-Server aus /etc/resolv.conf lesen exec('cat /etc/resolv.conf | grep nameserver | cut -d " " -f 2', (error, stdout) => { if (error) { resolve(['DNS-Server konnten nicht ermittelt werden']); return; } const servers = stdout.trim().split('\n').filter(Boolean); resolve(servers); }); } }); } // Standard-Gateway abfragen async function getDefaultGateway() { return new Promise((resolve) => { if (process.platform === 'win32') { // Windows: Gateway über PowerShell abfragen exec('powershell.exe -Command "Get-NetRoute -DestinationPrefix 0.0.0.0/0 | Select-Object -ExpandProperty NextHop"', (error, stdout) => { if (error) { resolve('Gateway konnte nicht ermittelt werden'); return; } resolve(stdout.trim()); }); } else { // Unix: Gateway aus den Routentabellen lesen exec("ip route | grep default | awk '{print $3}'", (error, stdout) => { if (error) { resolve('Gateway konnte nicht ermittelt werden'); return; } resolve(stdout.trim()); }); } }); } // Validierung des Hostnamens für Sicherheit function isValidHostname(hostname) { // Längenprüfung if (!hostname || hostname.length > 255) { return false; } // Erlaubte Hostnamen if (hostname === 'localhost' || hostname === '127.0.0.1') { return true; } // IPv4-Prüfung const ipv4Regex = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; if (ipv4Regex.test(hostname)) { return true; } // Hostname-Prüfung const hostnameRegex = /^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$/; return hostnameRegex.test(hostname); } // Server starten server.listen(PORT, () => { console.log(`MYP Frontend Debug-Server läuft auf http://localhost:${PORT}`); });