{ "permissions": { "allow": [ "Bash(ssh:*)", "Bash(scp:*)", "Bash(veth.*)", "Bash(docker.*)", "Bash(curl:*)", "Bash(findstr:*)", "Bash(cat:*)", "Bash(powershell -Command @'\n$content = @\"\"\nimport { useState, useEffect } from 'react'\nimport { useNavigate } from 'react-router-dom'\nimport { getServers } from '../api'\nimport { useUser } from '../context/UserContext'\nimport ServerCard from '../components/ServerCard'\nimport SettingsModal from '../components/SettingsModal'\nimport UserManagement from '../components/UserManagement'\n\nexport default function Dashboard\\({ onLogout }\\) {\n const navigate = useNavigate\\(\\)\n const { user, token, loading: userLoading, isSuperadmin, role } = useUser\\(\\)\n const [servers, setServers] = useState\\([]\\)\n const [loading, setLoading] = useState\\(true\\)\n const [error, setError] = useState\\(''\\)\n const [showSettings, setShowSettings] = useState\\(false\\)\n const [showUserMgmt, setShowUserMgmt] = useState\\(false\\)\n\n const fetchServers = async \\(\\) => {\n try {\n const data = await getServers\\(token\\)\n setServers\\(data\\)\n setError\\(''\\)\n } catch \\(err\\) {\n setError\\('Failed to connect to server'\\)\n if \\(err.message.includes\\('401'\\) || err.message.includes\\('403'\\)\\) {\n onLogout\\(\\)\n }\n } finally {\n setLoading\\(false\\)\n }\n }\n\n useEffect\\(\\(\\) => {\n if \\(!userLoading\\) {\n fetchServers\\(\\)\n const interval = setInterval\\(fetchServers, 10000\\)\n return \\(\\) => clearInterval\\(interval\\)\n }\n }, [token, userLoading]\\)\n\n const roleLabels = {\n user: 'Viewer',\n moderator: 'Operator',\n superadmin: 'Admin'\n }\n\n if \\(userLoading\\) {\n return \\(\n
\n
Loading...
\n
\n \\)\n }\n\n const onlineCount = servers.filter\\(s => s.running\\).length\n const totalPlayers = servers.reduce\\(\\(sum, s\\) => sum + \\(s.players?.online || 0\\), 0\\)\n\n return \\(\n
\n {/* Header */}\n
\n
\n
\n
\n

\n Gameserver Monitor\n

\n
\n \n {onlineCount}/{servers.length} online\n \n |\n \n {totalPlayers} players\n \n
\n
\n\n
\n
\n
{user?.username}
\n
{roleLabels[role]}
\n
\n\n {isSuperadmin && \\(\n setShowUserMgmt\\(true\\)}\n className=\"\"btn btn-ghost\"\"\n >\n Users\n \n \\)}\n\n setShowSettings\\(true\\)}\n className=\"\"btn btn-ghost\"\"\n >\n Settings\n \n\n \n Sign out\n \n
\n
\n
\n
\n\n {/* Main Content */}\n
\n {error && \\(\n
\n {error}\n
\n \\)}\n\n {loading ? \\(\n
\n
Loading servers...
\n
\n \\) : \\(\n
\n {servers.map\\(\\(server, index\\) => \\(\n \n navigate\\('/server/' + server.id\\)}\n />\n
\n \\)\\)}\n
\n \\)}\n \n\n {/* Modals */}\n {showSettings && \\(\n setShowSettings\\(false\\)} />\n \\)}\n\n {showUserMgmt && \\(\n setShowUserMgmt\\(false\\)} />\n \\)}\n \n \\)\n}\n\"\"@\n$content | Out-File -FilePath \"\"Dashboard.jsx\"\" -Encoding UTF8\n'@)", "Bash(git add:*)", "Bash(dir:*)", "Bash(ssh-keygen:*)", "Bash(ssh alex@192.168.2.10 \"ssh root@192.168.2.30 ''cat /etc/nginx/nginx.conf''\")", "Bash(ssh alex@192.168.2.10 \"ssh root@192.168.2.30 ''curl -s --max-time 5 http://localhost:3000/api/health''\")", "Bash(ssh alex@192.168.2.10 \"ssh root@192.168.2.30 ''sleep 3 && curl -s --max-time 10 http://localhost:3000/api/servers 2>&1''\")", "Bash(ssh alex@192.168.2.10 \"ssh root@192.168.2.30 ''cat > /opt/gameserver-monitor/backend/config.json << \"\"CONFIGEOF\"\"\n{\n \"\"servers\"\": [\n {\n \"\"id\"\": \"\"minecraft\"\",\n \"\"name\"\": \"\"All the Mods 10 | Minecraft\"\",\n \"\"host\"\": \"\"192.168.2.51\"\",\n \"\"type\"\": \"\"minecraft\"\",\n \"\"runtime\"\": \"\"screen\"\",\n \"\"rconPort\"\": 25575,\n \"\"rconPassword\"\": \"\"gsm-mc-2026\"\",\n \"\"screenName\"\": \"\"minecraft\"\",\n \"\"workDir\"\": \"\"/opt/minecraft\"\",\n \"\"startCmd\"\": \"\"./run.sh\"\"\n },\n {\n \"\"id\"\": \"\"factorio\"\",\n \"\"name\"\": \"\"Factorio\"\",\n \"\"host\"\": \"\"192.168.2.50\"\",\n \"\"type\"\": \"\"factorio\"\",\n \"\"runtime\"\": \"\"docker\"\",\n \"\"containerName\"\": \"\"factorio\"\",\n \"\"rconPort\"\": 27015,\n \"\"rconPassword\"\": \"\"jieTig6IkixaKuu\"\"\n },\n {\n \"\"id\"\": \"\"vrising\"\",\n \"\"name\"\": \"\"V Rising\"\",\n \"\"host\"\": \"\"192.168.2.52\"\",\n \"\"type\"\": \"\"vrising\"\",\n \"\"runtime\"\": \"\"systemd\"\",\n \"\"serviceName\"\": \"\"vrising\"\",\n \"\"rconPort\"\": 25575,\n \"\"rconPassword\"\": \"\"changeme\"\",\n \"\"workDir\"\": \"\"/home/steam/vrising\"\"\n },\n {\n \"\"id\"\": \"\"zomboid\"\",\n \"\"name\"\": \"\"Project Zomboid\"\",\n \"\"host\"\": \"\"10.0.30.66\"\",\n \"\"type\"\": \"\"zomboid\"\",\n \"\"runtime\"\": \"\"screen\"\",\n \"\"rconPort\"\": 27015,\n \"\"rconPassword\"\": \"\"ShkeloAufNettoParkplatzSchlagen47139\"\",\n \"\"screenName\"\": \"\"zomboid\"\",\n \"\"workDir\"\": \"\"/opt/pzserver\"\",\n \"\"startCmd\"\": \"\"./start-server.sh -servername Project\"\",\n \"\"sshUser\"\": \"\"pzuser\"\",\n \"\"logFile\"\": \"\"/home/pzuser/Zomboid/server-console.txt\"\"\n }\n ]\n}\nCONFIGEOF\npkill -f \"\"node server.js\"\" 2>/dev/null; cd /opt/gameserver-monitor/backend && node server.js >> /var/log/gsm-backend.log 2>&1 &''\")", "Bash(ssh alex@192.168.2.10 \"ssh root@192.168.2.30 ''cat /opt/gameserver-monitor/backend/config.json | head -5''\")", "Bash(ssh alex@192.168.2.10 \"ssh root@192.168.2.30 ''cat > /tmp/routefix.js << \"\"FIXEOF\"\"\nconst fs = require\\(\"\"fs\"\"\\);\nconst file = \"\"/opt/gameserver-monitor/backend/routes/servers.js\"\";\nlet content = fs.readFileSync\\(file, \"\"utf8\"\"\\);\n\n// Add import for isHostFailed\ncontent = content.replace\\(\n \"\"import { getServerStatus, startServer, stopServer, restartServer, getConsoleLog, getProcessUptime, listFactorioSaves, createFactorioWorld, deleteFactorioSave, getFactorioCurrentSave } from \\\\\"\"../services/ssh.js\\\\\"\";\"\",\n \"\"import { getServerStatus, startServer, stopServer, restartServer, getConsoleLog, getProcessUptime, listFactorioSaves, createFactorioWorld, deleteFactorioSave, getFactorioCurrentSave, isHostFailed } from \\\\\"\"../services/ssh.js\\\\\"\";\"\"\n\\);\n\n// Find and update the server list endpoint\nconst oldMapCode = \"\"const servers = await Promise.all\\(config.servers.map\\(async \\(server\\) => {\"\";\nconst newMapCode = \\\\`const servers = await Promise.all\\(config.servers.map\\(async \\(server\\) => {\n // Quick check if host is unreachable - skip expensive operations\n const hostUnreachable = isHostFailed\\(server.host, server.sshUser\\);\\\\`;\n\ncontent = content.replace\\(oldMapCode, newMapCode\\);\n\n// Update the status call to use the quick check\nconst oldStatusCall = \"\"const [status, metrics, players, playerList, processUptime] = await Promise.all\\([\"\";\nconst newStatusCall = \\\\`// If host is unreachable, return immediately with minimal data\n if \\(hostUnreachable\\) {\n const metrics = await getCurrentMetrics\\(server.id\\).catch\\(\\(\\) => \\({\n cpu: 0, cpuCores: 1, memory: 0, memoryUsed: 0, memoryTotal: 0, uptime: 0\n }\\)\\);\n const memTotal = formatBytes\\(metrics.memoryTotal\\);\n const memUsed = formatBytes\\(metrics.memoryUsed, memTotal.unit\\);\n return {\n id: server.id,\n name: server.name,\n type: server.type,\n status: \"\"unreachable\"\",\n running: false,\n metrics: {\n cpu: metrics.cpu,\n cpuCores: metrics.cpuCores,\n memory: metrics.memory,\n memoryUsed: memUsed.value,\n memoryTotal: memTotal.value,\n memoryUnit: memTotal.unit,\n uptime: 0\n },\n players: { online: 0, max: null, list: [] },\n hasRcon: !!server.rconPassword\n };\n }\n\n const [status, metrics, players, playerList, processUptime] = await Promise.all\\([\\\\`;\n\ncontent = content.replace\\(oldStatusCall, newStatusCall\\);\n\nfs.writeFileSync\\(file, content\\);\nconsole.log\\(\"\"Done\"\"\\);\nFIXEOF\nnode /tmp/routefix.js''\")", "Bash(ssh alex@192.168.2.10 \"ssh root@192.168.2.30 ''cat > /opt/gameserver-monitor/backend/config.json << \"\"CONFIGEOF\"\"\n{\n \"\"servers\"\": [\n {\n \"\"id\"\": \"\"minecraft\"\",\n \"\"name\"\": \"\"All the Mods 10 | Minecraft\"\",\n \"\"host\"\": \"\"192.168.2.51\"\",\n \"\"type\"\": \"\"minecraft\"\",\n \"\"runtime\"\": \"\"screen\"\",\n \"\"rconPort\"\": 25575,\n \"\"rconPassword\"\": \"\"gsm-mc-2026\"\",\n \"\"screenName\"\": \"\"minecraft\"\",\n \"\"workDir\"\": \"\"/opt/minecraft\"\",\n \"\"startCmd\"\": \"\"./run.sh\"\"\n },\n {\n \"\"id\"\": \"\"factorio\"\",\n \"\"name\"\": \"\"Factorio\"\",\n \"\"host\"\": \"\"192.168.2.50\"\",\n \"\"type\"\": \"\"factorio\"\",\n \"\"runtime\"\": \"\"docker\"\",\n \"\"containerName\"\": \"\"factorio\"\",\n \"\"rconPort\"\": 27015,\n \"\"rconPassword\"\": \"\"jieTig6IkixaKuu\"\"\n },\n {\n \"\"id\"\": \"\"vrising\"\",\n \"\"name\"\": \"\"V Rising\"\",\n \"\"host\"\": \"\"192.168.2.52\"\",\n \"\"type\"\": \"\"vrising\"\",\n \"\"runtime\"\": \"\"systemd\"\",\n \"\"serviceName\"\": \"\"vrising\"\",\n \"\"rconPort\"\": 25575,\n \"\"rconPassword\"\": \"\"changeme\"\",\n \"\"workDir\"\": \"\"/home/steam/vrising\"\"\n },\n {\n \"\"id\"\": \"\"zomboid\"\",\n \"\"name\"\": \"\"Project Zomboid\"\",\n \"\"host\"\": \"\"10.0.30.66\"\",\n \"\"type\"\": \"\"zomboid\"\",\n \"\"runtime\"\": \"\"screen\"\",\n \"\"rconPort\"\": 27015,\n \"\"rconPassword\"\": \"\"ShkeloAufNettoParkplatzSchlagen47139\"\",\n \"\"screenName\"\": \"\"zomboid\"\",\n \"\"workDir\"\": \"\"/opt/pzserver\"\",\n \"\"startCmd\"\": \"\"./start-server.sh -servername Project\"\",\n \"\"sshUser\"\": \"\"pzuser\"\",\n \"\"logFile\"\": \"\"/home/pzuser/Zomboid/server-console.txt\"\"\n }\n ]\n}\nCONFIGEOF''\")", "Bash(ssh alex@192.168.2.10 \"ssh root@192.168.2.30 ''wg show 2>&1 || echo \"\"WireGuard nicht installiert/aktiv\"\"''\")" ] } }