50 lines
1.7 KiB
JavaScript
50 lines
1.7 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* WebSocket-Proxy: Browser → Panel → Proxmox VNC
|
|
* Start: CONSOLE_PROXY_SECRET=... CONSOLE_VALIDATE_URL=https://panel/api/console/validate node scripts/console-ws-proxy.mjs
|
|
*/
|
|
import http from 'http';
|
|
import { WebSocketServer, WebSocket } from 'ws';
|
|
|
|
const PORT = parseInt(process.env.CONSOLE_PROXY_PORT || '6090', 10);
|
|
const SECRET = process.env.CONSOLE_PROXY_SECRET || '';
|
|
const VALIDATE = process.env.CONSOLE_PROXY_VALIDATE_URL || 'http://127.0.0.1:8000/api/console/validate';
|
|
|
|
const server = http.createServer();
|
|
const wss = new WebSocketServer({ server, path: '/ws/vm' });
|
|
|
|
wss.on('connection', async (clientWs, req) => {
|
|
const token = req.url?.split('/').pop()?.split('?')[0];
|
|
if (!token) {
|
|
clientWs.close(4001, 'missing token');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const res = await fetch(`${VALIDATE}/${token}`, {
|
|
headers: { 'X-Console-Proxy-Secret': SECRET },
|
|
});
|
|
if (!res.ok) {
|
|
clientWs.close(4003, 'invalid session');
|
|
return;
|
|
}
|
|
const data = await res.json();
|
|
const proxmoxWs = new WebSocket(data.proxmox_ws_url, ['binary']);
|
|
|
|
proxmoxWs.on('open', () => {
|
|
clientWs.on('message', (msg) => proxmoxWs.readyState === WebSocket.OPEN && proxmoxWs.send(msg));
|
|
proxmoxWs.on('message', (msg) => clientWs.readyState === WebSocket.OPEN && clientWs.send(msg));
|
|
});
|
|
|
|
proxmoxWs.on('error', () => clientWs.close(1011, 'upstream error'));
|
|
clientWs.on('close', () => proxmoxWs.close());
|
|
proxmoxWs.on('close', () => clientWs.close());
|
|
} catch {
|
|
clientWs.close(1011, 'proxy error');
|
|
}
|
|
});
|
|
|
|
server.listen(PORT, '127.0.0.1', () => {
|
|
console.log(`Console WS proxy on 127.0.0.1:${PORT}/ws/vm/{token}`);
|
|
});
|