File size: 2,729 Bytes
42926a5 9eaf2de 940518f b0ebb84 42926a5 9eaf2de 42926a5 9fcb962 9eaf2de 9fcb962 fe865d0 42926a5 b0ebb84 9eaf2de 9fcb962 b0ebb84 42926a5 9fcb962 42926a5 9fcb962 42926a5 9fcb962 b0ebb84 9eaf2de b0ebb84 4798350 b0ebb84 4798350 b0ebb84 940518f 9fcb962 fe865d0 9fcb962 940518f 4798350 9eaf2de 42926a5 940518f 42926a5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const Convert = require('ansi-to-html');
const { exec } = require('child_process');
const path = require('path');
const app = express();
const server = http.createServer(app);
const io = new Server(server, {
cors: { origin: "*" }
});
const PORT = 7860;
// ANSI → HTML
const convert = new Convert({
fg: '#e2e8f0',
bg: '#0b1020',
newline: true,
escapeXML: true
});
// logs memory
let logs = [];
const MAX_LOGS = 10000;
function formatLog(data) {
return {
html: convert.toHtml(data.message || ''),
level: data.level || 'info',
timestamp: new Date()
};
}
function addLog(log) {
logs.push(log);
if (logs.length > MAX_LOGS) logs.shift();
}
// STATIC
app.use(express.static(path.join(__dirname, 'public')));
// ✅ PAGINATED API
app.get('/api/logs', (req, res) => {
const limit = parseInt(req.query.limit) || 50;
const offset = parseInt(req.query.offset) || 0;
const start = Math.max(logs.length - offset - limit, 0);
const end = logs.length - offset;
const slice = logs.slice(start, end);
res.json({
logs: slice,
hasMore: start > 0
});
});
// SOCKET
io.on('connection', (socket) => {
console.log('Client connected:', socket.id);
socket.on('log', (data) => {
const log = formatLog(data);
addLog(log);
io.emit('log', log);
});
socket.on('command', (data) => {
const cmd = data.command.trim();
if (!cmd) return;
if (cmd === "clear") {
logs = [];
return;
}
const blocked = ['rm', 'shutdown', 'reboot', 'mkfs'];
if (blocked.some(b => cmd.includes(b))) {
const log = formatLog({
message: "\x1b[31mBlocked command!\x1b[0m",
level: "error"
});
addLog(log);
return io.emit('log', log);
}
const cmdLog = formatLog({
message: "\x1b[32m$ " + cmd + "\x1b[0m"
});
addLog(cmdLog);
io.emit('log', cmdLog);
exec(cmd, { timeout: 20000 }, (error, stdout, stderr) => {
if (stdout) {
const outLog = formatLog({ message: stdout });
addLog(outLog);
io.emit('log', outLog);
}
if (stderr) {
const errLog = formatLog({
message: "\x1b[31m" + stderr + "\x1b[0m",
level: "error"
});
addLog(errLog);
io.emit('log', errLog);
}
if (error) {
const errLog = formatLog({
message: "\x1b[31m" + error.message + "\x1b[0m",
level: "error"
});
addLog(errLog);
io.emit('log', errLog);
}
});
});
});
server.listen(PORT, () => {
console.log('🚀 Server running on http://localhost:' + PORT);
}); |