fix: hijack upgrade event before WsAdapter can consume the socket

WsAdapter registered its upgrade handler first and destroyed sockets
for non-matching paths. Now we remove all existing upgrade listeners,
install ours first, and forward non-terminal/sftp upgrades to the
original WsAdapter handlers for RDP.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Vantz Stockwell 2026-03-13 23:28:54 -04:00
parent 55b944bfc5
commit 8207b78b36

View File

@ -18,7 +18,6 @@ async function bootstrap() {
await app.listen(3000); await app.listen(3000);
console.log('Wraith backend running on port 3000'); console.log('Wraith backend running on port 3000');
// Manual WebSocket handling — bypasses NestJS WsAdapter entirely
const server = app.getHttpServer(); const server = app.getHttpServer();
const terminalGateway = app.get(TerminalGateway); const terminalGateway = app.get(TerminalGateway);
const sftpGateway = app.get(SftpGateway); const sftpGateway = app.get(SftpGateway);
@ -27,30 +26,39 @@ async function bootstrap() {
const sftpWss = new WebSocketServer({ noServer: true }); const sftpWss = new WebSocketServer({ noServer: true });
terminalWss.on('connection', (ws, req) => { terminalWss.on('connection', (ws, req) => {
console.log(`[WS] Terminal connection from ${req.url}`); console.log(`[WS] Terminal connection established`);
terminalGateway.handleConnection(ws, req); terminalGateway.handleConnection(ws, req);
}); });
sftpWss.on('connection', (ws, req) => { sftpWss.on('connection', (ws, req) => {
console.log(`[WS] SFTP connection from ${req.url}`); console.log(`[WS] SFTP connection established`);
sftpGateway.handleConnection(ws, req); sftpGateway.handleConnection(ws, req);
}); });
// Remove ALL existing upgrade listeners (WsAdapter's) so we handle upgrades first
const existingListeners = server.listeners('upgrade');
server.removeAllListeners('upgrade');
// Our handler runs first — routes terminal/sftp, passes everything else to WsAdapter
server.on('upgrade', (req: any, socket: any, head: any) => { server.on('upgrade', (req: any, socket: any, head: any) => {
const pathname = req.url?.split('?')[0]; const pathname = req.url?.split('?')[0];
console.log(`[HTTP-UPGRADE] path=${pathname}`); console.log(`[HTTP-UPGRADE] path=${pathname} socket.destroyed=${socket.destroyed}`);
if (pathname === '/api/ws/terminal') { if (pathname === '/api/ws/terminal') {
terminalWss.handleUpgrade(req, socket, head, (ws) => { terminalWss.handleUpgrade(req, socket, head, (ws) => {
console.log(`[WS] Terminal upgrade complete`);
terminalWss.emit('connection', ws, req); terminalWss.emit('connection', ws, req);
}); });
} else if (pathname === '/api/ws/sftp') { } else if (pathname === '/api/ws/sftp') {
sftpWss.handleUpgrade(req, socket, head, (ws) => { sftpWss.handleUpgrade(req, socket, head, (ws) => {
console.log(`[WS] SFTP upgrade complete`);
sftpWss.emit('connection', ws, req); sftpWss.emit('connection', ws, req);
}); });
} else { } else {
console.log(`[HTTP-UPGRADE] Unknown WS path: ${pathname}, destroying socket`); // Pass to WsAdapter's original handlers (for RDP etc)
socket.destroy(); for (const listener of existingListeners) {
listener.call(server, req, socket, head);
}
} }
}); });
} }