diff --git a/src/main/proxy-functions/shell-api-request.ts b/src/main/proxy-functions/shell-api-request.ts index 620c1126ce..76340585e1 100644 --- a/src/main/proxy-functions/shell-api-request.ts +++ b/src/main/proxy-functions/shell-api-request.ts @@ -28,14 +28,17 @@ import URLParse from "url-parse"; import { ExtendedMap, Singleton } from "../../common/utils"; import type { ClusterId } from "../../common/cluster-types"; import { ipcMainHandle } from "../../common/ipc"; -import * as uuid from "uuid"; +import crypto from "crypto"; +import { promisify } from "util"; + +const randomBytes = promisify(crypto.randomBytes); export class ShellRequestAuthenticator extends Singleton { - private tokens = new ExtendedMap>(); + private tokens = new ExtendedMap>(); init() { - ipcMainHandle("cluster:shell-api", (event, clusterId, tabId) => { - const authToken = uuid.v4(); + ipcMainHandle("cluster:shell-api", async (event, clusterId, tabId) => { + const authToken = Uint8Array.from(await randomBytes(128)); this.tokens .getOrInsert(clusterId, () => new Map()) @@ -60,9 +63,9 @@ export class ShellRequestAuthenticator extends Singleton { } const authToken = clusterTokens.get(tabId); + const buf = Uint8Array.from(Buffer.from(token, "base64")); - // need both conditions to prevent `undefined === undefined` being true here - if (typeof authToken === "string" && authToken === token) { + if (authToken instanceof Uint8Array && authToken.length === buf.length && crypto.timingSafeEqual(authToken, buf)) { // remove the token because it is a single use token clusterTokens.delete(tabId); diff --git a/src/renderer/api/terminal-api.ts b/src/renderer/api/terminal-api.ts index 09e67d3603..779d729934 100644 --- a/src/renderer/api/terminal-api.ts +++ b/src/renderer/api/terminal-api.ts @@ -81,7 +81,12 @@ export class TerminalApi extends WebSocketApi { this.emitStatus("Connecting ..."); } - const shellToken = await ipcRenderer.invoke("cluster:shell-api", getHostedClusterId(), this.query.id); + const authTokenArray = await ipcRenderer.invoke("cluster:shell-api", getHostedClusterId(), this.query.id); + + if (!(authTokenArray instanceof Uint8Array)) { + throw new TypeError("ShellApi token is not a Uint8Array"); + } + const { hostname, protocol, port } = location; const socketUrl = url.format({ protocol: protocol.includes("https") ? "wss" : "ws", @@ -90,7 +95,7 @@ export class TerminalApi extends WebSocketApi { pathname: "/api", query: { ...this.query, - shellToken, + shellToken: Buffer.from(authTokenArray).toString("base64"), }, slashes: true, });