diff --git a/package.json b/package.json index ae9cba1f1c..5add3bf274 100644 --- a/package.json +++ b/package.json @@ -372,10 +372,11 @@ "@types/webpack-node-externals": "^2.5.3", "@typescript-eslint/eslint-plugin": "^5.48.1", "@typescript-eslint/parser": "^5.48.1", + "@types/ws": "^8.5.4", "adr": "^1.4.3", "ansi_up": "^5.1.0", - "chalk": "^4.1.2", "canvas": "^2.10.1", + "chalk": "^4.1.2", "chart.js": "^2.9.4", "circular-dependency-plugin": "^5.2.2", "cli-progress": "^3.11.2", diff --git a/src/main/cluster/get-cluster-for-request.injectable.ts b/src/main/cluster/get-cluster-for-request.injectable.ts deleted file mode 100644 index d2406479c0..0000000000 --- a/src/main/cluster/get-cluster-for-request.injectable.ts +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import type { IncomingMessage } from "http"; -import getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable"; -import type { Cluster } from "../../common/cluster/cluster"; -import { getClusterIdFromHost } from "../../common/utils"; -import { apiKubePrefix } from "../../common/vars"; - -export type GetClusterForRequest = (req: IncomingMessage) => Cluster | undefined; - -const getClusterForRequestInjectable = getInjectable({ - id: "get-cluster-for-request", - instantiate: (di): GetClusterForRequest => { - const getClusterById = di.inject(getClusterByIdInjectable); - - return (req) => { - if (!req.headers.host) { - return undefined; - } - - // lens-server is connecting to 127.0.0.1:/ - if (req.url && req.headers.host.startsWith("127.0.0.1")) { - const clusterId = req.url.split("/")[1]; - const cluster = getClusterById(clusterId); - - if (cluster) { - // we need to swap path prefix so that request is proxied to kube api - req.url = req.url.replace(`/${clusterId}`, apiKubePrefix); - } - - return cluster; - } - - const clusterId = getClusterIdFromHost(req.headers.host); - - if (!clusterId) { - return undefined; - } - - return getClusterById(clusterId); - }; - }, -}); - -export default getClusterForRequestInjectable; diff --git a/src/main/lens-proxy/get-cluster-for-request.injectable.ts b/src/main/lens-proxy/get-cluster-for-request.injectable.ts index 7d529540d1..d2406479c0 100644 --- a/src/main/lens-proxy/get-cluster-for-request.injectable.ts +++ b/src/main/lens-proxy/get-cluster-for-request.injectable.ts @@ -3,10 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; +import type { IncomingMessage } from "http"; import getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable"; +import type { Cluster } from "../../common/cluster/cluster"; import { getClusterIdFromHost } from "../../common/utils"; import { apiKubePrefix } from "../../common/vars"; -import type { GetClusterForRequest } from "./lens-proxy"; + +export type GetClusterForRequest = (req: IncomingMessage) => Cluster | undefined; const getClusterForRequestInjectable = getInjectable({ id: "get-cluster-for-request", diff --git a/src/main/lens-proxy/lens-proxy.ts b/src/main/lens-proxy/lens-proxy.ts index 10f0a15829..59b052f9a8 100644 --- a/src/main/lens-proxy/lens-proxy.ts +++ b/src/main/lens-proxy/lens-proxy.ts @@ -20,12 +20,12 @@ import type { SelfSignedCert } from "selfsigned"; import type { GetClusterForRequest } from "../cluster/get-cluster-for-request.injectable"; export type ServerIncomingMessage = SetRequired; -export type LensProxyApiRequest = (args: ProxyApiRequestArgs) => void | Promise; +export type ProxyRequestHandler = (args: ProxyApiRequestArgs) => void | Promise; interface Dependencies { getClusterForRequest: GetClusterForRequest; - shellApiRequest: LensProxyApiRequest; - kubeApiUpgradeRequest: LensProxyApiRequest; + shellApiRequest: ProxyRequestHandler; + kubeApiUpgradeRequest: ProxyRequestHandler; emitAppEvent: EmitAppEvent; readonly router: Router; readonly proxy: httpProxy; diff --git a/src/main/lens-proxy/proxy-functions/shell-api-request.injectable.ts b/src/main/lens-proxy/proxy-functions/shell-api-request.injectable.ts index 04b222554d..05785541df 100644 --- a/src/main/lens-proxy/proxy-functions/shell-api-request.injectable.ts +++ b/src/main/lens-proxy/proxy-functions/shell-api-request.injectable.ts @@ -7,40 +7,36 @@ import { URL } from "url"; import { WebSocketServer } from "ws"; import loggerInjectable from "../../../common/logger.injectable"; import shellApiAuthenticatorInjectable from "../../../features/terminal/main/shell-api-authenticator.injectable"; -import clusterManagerInjectable from "../../cluster/manager.injectable"; import openShellSessionInjectable from "../../shell-session/create-shell-session.injectable"; import getClusterForRequestInjectable from "../get-cluster-for-request.injectable"; -import type { ProxyApiRequestArgs } from "./types"; +import type { ProxyRequestHandler } from "../lens-proxy"; const shellApiRequestInjectable = getInjectable({ id: "shell-api-request", - instantiate: (di) => { + instantiate: (di): ProxyRequestHandler => { const openShellSession = di.inject(openShellSessionInjectable); - const clusterManager = di.inject(clusterManagerInjectable); + const getClusterForRequest = di.inject(getClusterForRequestInjectable); const logger = di.inject(loggerInjectable); const shellApiAuthenticator = di.inject(shellApiAuthenticatorInjectable); - const getClusterForRequest = di.inject(getClusterForRequestInjectable); - return ({ req, socket, head }: ProxyApiRequestArgs): void => { + return ({ req, socket, head }) => { const cluster = getClusterForRequest(req); - const { searchParams } = new URL(req.url); + const { searchParams } = new URL(req.url, `https://${req.headers.host}`); const tabId = searchParams.get("id"); const nodeName = searchParams.get("node"); const shellToken = searchParams.get("shellToken"); if (!tabId || !cluster || !shellApiAuthenticator.authenticate(cluster.id, tabId, shellToken)) { socket.write("Invalid shell request"); - - return void socket.end(); + socket.end(); + } else { + new WebSocketServer({ noServer: true }) + .handleUpgrade(req, socket, head, (websocket) => { + openShellSession({ websocket, cluster, tabId, nodeName }) + .catch(error => logger.error(`[SHELL-SESSION]: failed to open a ${nodeName ? "node" : "local"} shell`, error)); + }); } - - const ws = new WebSocketServer({ noServer: true }); - - ws.handleUpgrade(req, socket, head, (websocket) => { - openShellSession({ websocket, cluster, tabId, nodeName }) - .catch(error => logger.error(`[SHELL-SESSION]: failed to open a ${nodeName ? "node" : "local"} shell`, error)); - }); }; }, }); diff --git a/src/main/shell-session/local-shell-session/techincal.test.ts b/src/main/shell-session/local-shell-session/techincal.test.ts index 5c471d923e..7245bd7241 100644 --- a/src/main/shell-session/local-shell-session/techincal.test.ts +++ b/src/main/shell-session/local-shell-session/techincal.test.ts @@ -17,9 +17,9 @@ import { getDiForUnitTesting } from "../../getDiForUnitTesting"; import createKubectlInjectable from "../../kubectl/create-kubectl.injectable"; import type { Kubectl } from "../../kubectl/kubectl"; import buildVersionInjectable from "../../vars/build-version/build-version.injectable"; -import type { OpenShellSession } from "../create-shell-session.injectable"; import type { SpawnPty } from "../spawn-pty.injectable"; import spawnPtyInjectable from "../spawn-pty.injectable"; +import type { OpenLocalShellSession } from "./open.injectable"; import openLocalShellSessionInjectable from "./open.injectable"; describe("technical unit tests for local shell sessions", () => { @@ -42,7 +42,7 @@ describe("technical unit tests for local shell sessions", () => { }); describe("when on windows", () => { - let openLocalShellSession: OpenShellSession; + let openLocalShellSession: OpenLocalShellSession; let spawnPtyMock: jest.MockedFunction; beforeEach(() => { diff --git a/src/renderer/api/__tests__/websocket-api.test.ts b/src/renderer/api/__tests__/websocket-api.test.ts index 8b0c4e27b7..3cff13f524 100644 --- a/src/renderer/api/__tests__/websocket-api.test.ts +++ b/src/renderer/api/__tests__/websocket-api.test.ts @@ -3,6 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ +import loggerInjectable from "../../../common/logger.injectable"; import { getDiForUnitTesting } from "../../getDiForUnitTesting"; import defaultWebsocketApiParamsInjectable from "../default-websocket-api-params.injectable"; import type { WebSocketEvents } from "../websocket-api"; @@ -22,6 +23,7 @@ describe("WebsocketApi tests", () => { api = new TestWebSocketApi({ defaultParams: di.inject(defaultWebsocketApiParamsInjectable), + logger: di.inject(loggerInjectable), }, {}); }); diff --git a/src/test-utils/channel-fakes/override-requesting-from-window-to-main.ts b/src/test-utils/channel-fakes/override-requesting-from-window-to-main.ts index 02333173dd..0dd1f5509e 100644 --- a/src/test-utils/channel-fakes/override-requesting-from-window-to-main.ts +++ b/src/test-utils/channel-fakes/override-requesting-from-window-to-main.ts @@ -7,7 +7,7 @@ import { deserialize, serialize } from "v8"; import type { RequestChannel } from "../../common/utils/channel/request-channel"; import enlistRequestChannelListenerInjectableInMain from "../../main/utils/channel/channel-listeners/enlist-request-channel-listener.injectable"; import type { RequestChannelListener } from "../../main/utils/channel/channel-listeners/listener-tokens"; -import type { RequestFromChannel, RequestFromChannel } from "../../renderer/utils/channel/request-from-channel.injectable"; +import type { RequestFromChannel } from "../../renderer/utils/channel/request-from-channel.injectable"; import requestFromChannelInjectable from "../../renderer/utils/channel/request-from-channel.injectable"; export const overrideRequestingFromWindowToMain = (mainDi: DiContainer) => { diff --git a/yarn.lock b/yarn.lock index c8dbe5b4be..71a5e2692e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2773,6 +2773,13 @@ dependencies: "@types/node" "*" +"@types/ws@^8.5.4": + version "8.5.4" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.4.tgz#bb10e36116d6e570dd943735f86c933c1587b8a5" + integrity sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg== + dependencies: + "@types/node" "*" + "@types/yargs-parser@*": version "21.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b"