From bc1ef8dd963111c45209929444048fc4d153b2d3 Mon Sep 17 00:00:00 2001 From: Rahul sharma Date: Wed, 17 Jun 2026 23:28:33 +0530 Subject: [PATCH] fix(ws): proxy LAN /live-ws upgrades and add unset JWT_SECRET warning (#4079) Integrated into release/v3.8.28 --- scripts/dev/standalone-server-ws.mjs | 28 ++++++++++++++++++++++++++++ src/server/ws/liveServer.ts | 8 ++++++++ 2 files changed, 36 insertions(+) diff --git a/scripts/dev/standalone-server-ws.mjs b/scripts/dev/standalone-server-ws.mjs index ceb0fde088..bb8941d56e 100644 --- a/scripts/dev/standalone-server-ws.mjs +++ b/scripts/dev/standalone-server-ws.mjs @@ -1,4 +1,5 @@ import http from "node:http"; +import net from "node:net"; import { randomUUID } from "node:crypto"; import { createResponsesWsProxy } from "./responses-ws-proxy.mjs"; import { ensurePeerStampToken, wrapRequestListenerWithPeerStamp } from "./peer-stamp.mjs"; @@ -36,9 +37,36 @@ function getProxy(server) { return proxy; } +function proxyLiveWs(req, socket, head) { + const targetPort = parseInt(process.env.LIVE_WS_PORT || "20129", 10); + const targetSocket = net.connect(targetPort, "127.0.0.1", () => { + let rawRequest = `${req.method} ${req.url} HTTP/${req.httpVersion}\r\n`; + for (const [key, val] of Object.entries(req.headers)) { + if (Array.isArray(val)) { + for (const v of val) rawRequest += `${key}: ${v}\r\n`; + } else { + rawRequest += `${key}: ${val}\r\n`; + } + } + rawRequest += "\r\n"; + targetSocket.write(rawRequest); + if (head && head.length > 0) targetSocket.write(head); + targetSocket.pipe(socket); + socket.pipe(targetSocket); + }); + + targetSocket.on("error", () => !socket.destroyed && socket.destroy()); + socket.on("error", () => !targetSocket.destroyed && targetSocket.destroy()); +} + function wrapUpgradeListener(server, listener) { return async function responsesWsAwareUpgrade(req, socket, head) { try { + const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`); + if (url.pathname === "/live-ws" || url.pathname.startsWith("/live-ws")) { + proxyLiveWs(req, socket, head); + return; + } const handled = await getProxy(server).handleUpgrade(req, socket, head); if (handled) return; return listener.call(this, req, socket, head); diff --git a/src/server/ws/liveServer.ts b/src/server/ws/liveServer.ts index 59ebb669af..9ff5ef6ba7 100644 --- a/src/server/ws/liveServer.ts +++ b/src/server/ws/liveServer.ts @@ -457,6 +457,14 @@ export async function startLiveDashboardServer( port = DEFAULT_PORT, host = DEFAULT_HOST ): Promise { + if (!process.env.JWT_SECRET) { + console.warn( + " \x1b[33m⚠ Warning: JWT_SECRET is not set in the environment.\x1b[0m\n" + + " Dashboard cookie-based WebSocket authentication will fail.\n" + + " Please ensure JWT_SECRET is configured in your .env file." + ); + } + const server = createServer((req, res) => { handleInternalEventRequest(req, res); });