156 lines
4.3 KiB
JavaScript
156 lines
4.3 KiB
JavaScript
// WebSocket Server for Terminal
|
|
// This runs as a separate process managed by PM2
|
|
import { createServer } from 'http';
|
|
import { Server } from 'socket.io';
|
|
import { Client } from 'ssh2';
|
|
import jwt from 'jsonwebtoken';
|
|
|
|
const JWT_SECRET = process.env.JWT_SECRET || '4916c430ed2682c2f023762e47531d95c6e51c4c5ab4ca8af79f6f010e203cf9';
|
|
const VM100_SSH_HOST = process.env.VM100_SSH_HOST || '192.168.178.129';
|
|
const VM100_SSH_USER = process.env.VM100_SSH_USER || 'root';
|
|
const VM100_SSH_PASSWORD = process.env.VM100_SSH_PASSWORD || 'Ba12sti34+';
|
|
|
|
const httpServer = createServer();
|
|
const io = new Server(httpServer, {
|
|
cors: {
|
|
origin: '*',
|
|
credentials: true
|
|
},
|
|
path: '/socket.io/',
|
|
transports: ['websocket', 'polling']
|
|
});
|
|
|
|
// Authentication Middleware
|
|
io.use((socket, next) => {
|
|
const token = socket.handshake.auth.token;
|
|
|
|
if (!token) {
|
|
return next(new Error('Authentication error: No token provided'));
|
|
}
|
|
|
|
try {
|
|
const payload = jwt.verify(token, JWT_SECRET);
|
|
socket.data.user = payload.username;
|
|
next();
|
|
} catch (err) {
|
|
next(new Error('Authentication error: Invalid token'));
|
|
}
|
|
});
|
|
|
|
io.on('connection', (socket) => {
|
|
console.log(`[Terminal] User ${socket.data.user} connected (${socket.id})`);
|
|
|
|
const vmid = socket.handshake.query.vmid;
|
|
const initialCols = parseInt(socket.handshake.query.cols) || 80;
|
|
const initialRows = parseInt(socket.handshake.query.rows) || 24;
|
|
|
|
console.log(`[Terminal] Initial terminal size: ${initialCols}x${initialRows}`);
|
|
|
|
// Only allow VM 100
|
|
if (vmid !== '100') {
|
|
socket.emit('error', 'Access denied: Only VM 100 console is available');
|
|
socket.disconnect();
|
|
return;
|
|
}
|
|
|
|
let sshClient = null;
|
|
let sshStream = null;
|
|
|
|
// SSH Connection
|
|
const connectSSH = () => {
|
|
sshClient = new Client();
|
|
|
|
sshClient.on('ready', () => {
|
|
console.log(`[Terminal] SSH connected to VM ${vmid}`);
|
|
socket.emit('status', 'connected');
|
|
|
|
// Create shell with correct initial size
|
|
sshClient.shell({
|
|
term: 'xterm-256color',
|
|
cols: initialCols,
|
|
rows: initialRows
|
|
}, (err, stream) => {
|
|
if (err) {
|
|
socket.emit('error', `Shell error: ${err.message}`);
|
|
return;
|
|
}
|
|
|
|
sshStream = stream;
|
|
|
|
// SSH → Browser
|
|
stream.on('data', (data) => {
|
|
socket.emit('data', data.toString('utf-8'));
|
|
});
|
|
|
|
stream.on('close', () => {
|
|
console.log(`[Terminal] SSH stream closed for ${socket.id}`);
|
|
socket.emit('status', 'disconnected');
|
|
});
|
|
|
|
stream.stderr.on('data', (data) => {
|
|
socket.emit('data', data.toString('utf-8'));
|
|
});
|
|
|
|
// Browser → SSH
|
|
socket.on('data', (data) => {
|
|
if (sshStream && !sshStream.destroyed) {
|
|
stream.write(data);
|
|
}
|
|
});
|
|
|
|
// Terminal Resize
|
|
socket.on('resize', ({ rows, cols }) => {
|
|
console.log(`[Terminal] Resize request: ${cols}x${rows}`);
|
|
if (sshStream && !sshStream.destroyed) {
|
|
try {
|
|
stream.setWindow(rows, cols);
|
|
console.log(`[Terminal] Resized to: ${cols}x${rows}`);
|
|
} catch (err) {
|
|
console.error(`[Terminal] Resize failed: ${err.message}`);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
sshClient.on('error', (err) => {
|
|
console.error(`[Terminal] SSH error: ${err.message}`);
|
|
socket.emit('error', `SSH connection failed: ${err.message}`);
|
|
});
|
|
|
|
sshClient.on('close', () => {
|
|
console.log(`[Terminal] SSH connection closed for ${socket.id}`);
|
|
});
|
|
|
|
// Connect to VM 100
|
|
sshClient.connect({
|
|
host: VM100_SSH_HOST,
|
|
port: 22,
|
|
username: VM100_SSH_USER,
|
|
password: VM100_SSH_PASSWORD,
|
|
readyTimeout: 10000,
|
|
});
|
|
};
|
|
|
|
// Start SSH connection
|
|
connectSSH();
|
|
|
|
// Handle disconnect
|
|
socket.on('disconnect', () => {
|
|
console.log(`[Terminal] User ${socket.data.user} disconnected (${socket.id})`);
|
|
|
|
if (sshStream) {
|
|
sshStream.end();
|
|
}
|
|
if (sshClient) {
|
|
sshClient.end();
|
|
}
|
|
});
|
|
});
|
|
|
|
const PORT = process.env.TERMINAL_PORT || 3001;
|
|
|
|
httpServer.listen(PORT, () => {
|
|
console.log(`[Terminal] WebSocket server running on port ${PORT}`);
|
|
});
|