mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Make ws:// authentication more timing safe (#4297)
This commit is contained in:
parent
18d695348b
commit
81b972a2d0
@ -28,14 +28,17 @@ import URLParse from "url-parse";
|
|||||||
import { ExtendedMap, Singleton } from "../../common/utils";
|
import { ExtendedMap, Singleton } from "../../common/utils";
|
||||||
import type { ClusterId } from "../../common/cluster-types";
|
import type { ClusterId } from "../../common/cluster-types";
|
||||||
import { ipcMainHandle } from "../../common/ipc";
|
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 {
|
export class ShellRequestAuthenticator extends Singleton {
|
||||||
private tokens = new ExtendedMap<ClusterId, Map<string, string>>();
|
private tokens = new ExtendedMap<ClusterId, Map<string, Uint8Array>>();
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
ipcMainHandle("cluster:shell-api", (event, clusterId, tabId) => {
|
ipcMainHandle("cluster:shell-api", async (event, clusterId, tabId) => {
|
||||||
const authToken = uuid.v4();
|
const authToken = Uint8Array.from(await randomBytes(128));
|
||||||
|
|
||||||
this.tokens
|
this.tokens
|
||||||
.getOrInsert(clusterId, () => new Map())
|
.getOrInsert(clusterId, () => new Map())
|
||||||
@ -60,9 +63,9 @@ export class ShellRequestAuthenticator extends Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const authToken = clusterTokens.get(tabId);
|
const authToken = clusterTokens.get(tabId);
|
||||||
|
const buf = Uint8Array.from(Buffer.from(token, "base64"));
|
||||||
|
|
||||||
// need both conditions to prevent `undefined === undefined` being true here
|
if (authToken instanceof Uint8Array && authToken.length === buf.length && crypto.timingSafeEqual(authToken, buf)) {
|
||||||
if (typeof authToken === "string" && authToken === token) {
|
|
||||||
// remove the token because it is a single use token
|
// remove the token because it is a single use token
|
||||||
clusterTokens.delete(tabId);
|
clusterTokens.delete(tabId);
|
||||||
|
|
||||||
|
|||||||
@ -81,7 +81,12 @@ export class TerminalApi extends WebSocketApi {
|
|||||||
this.emitStatus("Connecting ...");
|
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 { hostname, protocol, port } = location;
|
||||||
const socketUrl = url.format({
|
const socketUrl = url.format({
|
||||||
protocol: protocol.includes("https") ? "wss" : "ws",
|
protocol: protocol.includes("https") ? "wss" : "ws",
|
||||||
@ -90,7 +95,7 @@ export class TerminalApi extends WebSocketApi {
|
|||||||
pathname: "/api",
|
pathname: "/api",
|
||||||
query: {
|
query: {
|
||||||
...this.query,
|
...this.query,
|
||||||
shellToken,
|
shellToken: Buffer.from(authTokenArray).toString("base64"),
|
||||||
},
|
},
|
||||||
slashes: true,
|
slashes: true,
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user