From 78ead4f2b93721351d72596e8c47701aff4a2572 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 3 Jun 2022 10:09:10 -0400 Subject: [PATCH] Make IPC usage injectable Signed-off-by: Sebastian Malton --- .../get-auth-token-channel.injectable.ts | 26 +++++++++++ .../get-auth-token.injectable.ts | 23 ++++++++++ src/common/utils/channel/allowed-types.ts | 12 +++++ .../utils/channel/channel-injection-token.ts | 12 ----- src/common/utils/channel/channel.test.ts | 4 +- ...equest-channel-listener-injection-token.ts | 4 +- .../listening-of-channels.injectable.ts | 4 +- .../request-channel-injection-token.ts | 14 +++--- ...equest-channel-listener-injection-token.ts | 44 +++++++++++++------ .../request-from-channel-injection-token.ts | 20 ++++----- ...ths-request-channel-listener.injectable.ts | 8 ++-- .../auth-token-channel-handler.injectable.ts | 18 ++++++++ ...itial-value-channel-listener.injectable.ts | 28 ++++-------- src/renderer/api/terminal-api.ts | 13 +++--- ...override-requesting-from-window-to-main.ts | 6 +-- 15 files changed, 156 insertions(+), 80 deletions(-) create mode 100644 src/common/shell-authentication/get-auth-token-channel.injectable.ts create mode 100644 src/common/shell-authentication/get-auth-token.injectable.ts create mode 100644 src/common/utils/channel/allowed-types.ts delete mode 100644 src/common/utils/channel/channel-injection-token.ts create mode 100644 src/main/lens-proxy/proxy-functions/shell/auth-token-channel-handler.injectable.ts diff --git a/src/common/shell-authentication/get-auth-token-channel.injectable.ts b/src/common/shell-authentication/get-auth-token-channel.injectable.ts new file mode 100644 index 0000000000..9438d50471 --- /dev/null +++ b/src/common/shell-authentication/get-auth-token-channel.injectable.ts @@ -0,0 +1,26 @@ +/** + * 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 { ClusterId } from "../cluster-types"; +import type { RequestChannel } from "../utils/channel/request-channel-injection-token"; +import { requestChannelInjectionToken } from "../utils/channel/request-channel-injection-token"; + +export type GetShellAuthTokenChannel = RequestChannel< + { + clusterId: ClusterId; + tabId: string; + }, + Uint8Array +>; + +const getShellAuthTokenChannelInjectable = getInjectable({ + id: "get-shell-auth-token-channel", + instantiate: (): GetShellAuthTokenChannel => ({ + id: "get-shell-auth-token-channel", + }), + injectionToken: requestChannelInjectionToken, +}); + +export default getShellAuthTokenChannelInjectable; diff --git a/src/common/shell-authentication/get-auth-token.injectable.ts b/src/common/shell-authentication/get-auth-token.injectable.ts new file mode 100644 index 0000000000..3407528440 --- /dev/null +++ b/src/common/shell-authentication/get-auth-token.injectable.ts @@ -0,0 +1,23 @@ +/** + * 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 { ChannelRequest } from "../utils/channel/request-channel-injection-token"; +import { requestFromChannelInjectionToken } from "../utils/channel/request-from-channel-injection-token"; +import type { GetShellAuthTokenChannel } from "./get-auth-token-channel.injectable"; +import getShellAuthTokenChannelInjectable from "./get-auth-token-channel.injectable"; + +export type GetShellAuthToken = ChannelRequest; + +const getShellAuthTokenInjectable = getInjectable({ + id: "get-shell-auth-token", + instantiate: (di): GetShellAuthToken => { + const requestFromChannel = di.inject(requestFromChannelInjectionToken); + const getShellAuthTokenChannel = di.inject(getShellAuthTokenChannelInjectable); + + return (arg) => requestFromChannel(getShellAuthTokenChannel, arg); + }, +}); + +export default getShellAuthTokenInjectable; diff --git a/src/common/utils/channel/allowed-types.ts b/src/common/utils/channel/allowed-types.ts new file mode 100644 index 0000000000..697966c6d6 --- /dev/null +++ b/src/common/utils/channel/allowed-types.ts @@ -0,0 +1,12 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import type { TypedArray } from "type-fest"; + +export type IpcPrimative = string | boolean | number | bigint | null | undefined; +export type IpcClasses = Date | RegExp | TypedArray; +export type IpcValue = IpcPrimative | IpcObject | IpcArray | IpcClasses; +export type IpcObject = { [Key in string]?: IpcValue }; +export type IpcArray = IpcValue[]; diff --git a/src/common/utils/channel/channel-injection-token.ts b/src/common/utils/channel/channel-injection-token.ts deleted file mode 100644 index 6006290f89..0000000000 --- a/src/common/utils/channel/channel-injection-token.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - - -export interface Channel { - id: string; - _messageTemplate?: MessageTemplate; - _returnTemplate?: ReturnTemplate; -} - diff --git a/src/common/utils/channel/channel.test.ts b/src/common/utils/channel/channel.test.ts index 84c1366f35..ebb05d0c0a 100644 --- a/src/common/utils/channel/channel.test.ts +++ b/src/common/utils/channel/channel.test.ts @@ -16,7 +16,7 @@ import type { MessageChannel } from "./message-channel-injection-token"; import type { RequestFromChannel } from "./request-from-channel-injection-token"; import { requestFromChannelInjectionToken } from "./request-from-channel-injection-token"; import type { RequestChannel } from "./request-channel-injection-token"; -import { requestChannelListenerInjectionToken } from "./request-channel-listener-injection-token"; +import { requestChannelHandlerInjectionToken } from "./request-channel-listener-injection-token"; import type { AsyncFnMock } from "@async-fn/jest"; import asyncFn from "@async-fn/jest"; import { getPromiseStatus } from "../../test-utils/get-promise-status"; @@ -183,7 +183,7 @@ describe("channel", () => { handler: requestListenerInMainMock, }), - injectionToken: requestChannelListenerInjectionToken, + injectionToken: requestChannelHandlerInjectionToken, }); mainDi.register(testChannelListenerInMainInjectable); diff --git a/src/common/utils/channel/enlist-request-channel-listener-injection-token.ts b/src/common/utils/channel/enlist-request-channel-listener-injection-token.ts index f87082c466..d8807ba4da 100644 --- a/src/common/utils/channel/enlist-request-channel-listener-injection-token.ts +++ b/src/common/utils/channel/enlist-request-channel-listener-injection-token.ts @@ -4,11 +4,11 @@ */ import { getInjectionToken } from "@ogre-tools/injectable"; import type { RequestChannel } from "./request-channel-injection-token"; -import type { RequestChannelListener } from "./request-channel-listener-injection-token"; +import type { RequestChannelHandlerDescriptor } from "./request-channel-listener-injection-token"; export type EnlistRequestChannelListener = < TChannel extends RequestChannel, ->(listener: RequestChannelListener) => () => void; +>(listener: RequestChannelHandlerDescriptor) => () => void; export const enlistRequestChannelListenerInjectionToken = getInjectionToken({ diff --git a/src/common/utils/channel/listening-of-channels.injectable.ts b/src/common/utils/channel/listening-of-channels.injectable.ts index 30fee42fb9..1452a4ebb2 100644 --- a/src/common/utils/channel/listening-of-channels.injectable.ts +++ b/src/common/utils/channel/listening-of-channels.injectable.ts @@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import { getStartableStoppable } from "../get-startable-stoppable"; import { disposer } from "../index"; import { messageChannelListenerInjectionToken } from "./message-channel-listener-injection-token"; -import { requestChannelListenerInjectionToken } from "./request-channel-listener-injection-token"; +import { requestChannelHandlerInjectionToken } from "./request-channel-listener-injection-token"; import { enlistMessageChannelListenerInjectionToken } from "./enlist-message-channel-listener-injection-token"; import { enlistRequestChannelListenerInjectionToken } from "./enlist-request-channel-listener-injection-token"; @@ -17,7 +17,7 @@ const listeningOfChannelsInjectable = getInjectable({ const enlistMessageChannelListener = di.inject(enlistMessageChannelListenerInjectionToken); const enlistRequestChannelListener = di.inject(enlistRequestChannelListenerInjectionToken); const messageChannelListeners = di.injectMany(messageChannelListenerInjectionToken); - const requestChannelListeners = di.injectMany(requestChannelListenerInjectionToken); + const requestChannelListeners = di.injectMany(requestChannelHandlerInjectionToken); return getStartableStoppable("listening-of-channels", () => { const messageChannelDisposers = messageChannelListeners.map(enlistMessageChannelListener); diff --git a/src/common/utils/channel/request-channel-injection-token.ts b/src/common/utils/channel/request-channel-injection-token.ts index 67044db878..b9953ea081 100644 --- a/src/common/utils/channel/request-channel-injection-token.ts +++ b/src/common/utils/channel/request-channel-injection-token.ts @@ -4,17 +4,19 @@ */ import { getInjectionToken } from "@ogre-tools/injectable"; -import type { JsonValue } from "type-fest"; +import type { IpcValue } from "./allowed-types"; export interface RequestChannel< - Request extends JsonValue | void = void, - Response extends JsonValue | void = void, + Request extends IpcValue | void = void, + Response extends IpcValue | void = void, > { - id: string; - _requestSignature?: Request; - _responseSignature?: Response; + id: Request | Response extends boolean ? string : string; } +export type ChannelRequest = Channel extends RequestChannel + ? (arg: Request) => Promise + : never; + export const requestChannelInjectionToken = getInjectionToken>({ id: "request-channel", }); diff --git a/src/common/utils/channel/request-channel-listener-injection-token.ts b/src/common/utils/channel/request-channel-listener-injection-token.ts index 690b96d9dc..88c81fe5b5 100644 --- a/src/common/utils/channel/request-channel-listener-injection-token.ts +++ b/src/common/utils/channel/request-channel-listener-injection-token.ts @@ -2,24 +2,42 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getInjectionToken } from "@ogre-tools/injectable"; -import type { SetRequired } from "type-fest"; +import type { DiContainerForInjection, Injectable } from "@ogre-tools/injectable"; +import { getInjectable, getInjectionToken } from "@ogre-tools/injectable"; import type { RequestChannel } from "./request-channel-injection-token"; -export interface RequestChannelListener> { - channel: TChannel; +export type RequestChannelHandler = Channel extends RequestChannel + ? (request: Request) => Response | Promise + : never; - handler: ( - request: SetRequired["_requestSignature"] - ) => - | SetRequired["_responseSignature"] - | Promise< - SetRequired["_responseSignature"] - >; +export interface RequestChannelHandlerDescriptor { + channel: Channel; + handler: RequestChannelHandler; } -export const requestChannelListenerInjectionToken = getInjectionToken>>( +export const requestChannelHandlerInjectionToken = getInjectionToken>>( { - id: "request-channel-listener", + id: "request-channel-handler", }, ); + +export function getRequestChannelHandlerInjectable< + ChannelInjectionToken, + Channel = ChannelInjectionToken extends Injectable, void> + ? Channel + : never, +>( + channelInjectionToken: ChannelInjectionToken, + instantiate: (di: DiContainerForInjection) => RequestChannelHandler, +) { + const token = channelInjectionToken as unknown as Injectable, RequestChannel, void>; + + return getInjectable({ + id: `${token.id}-handler`, + instantiate: (di) => ({ + channel: di.inject(token), + handler: instantiate(di), + }), + injectionToken: requestChannelHandlerInjectionToken, + }); +} diff --git a/src/common/utils/channel/request-from-channel-injection-token.ts b/src/common/utils/channel/request-from-channel-injection-token.ts index 5f4492543f..1a941e65e6 100644 --- a/src/common/utils/channel/request-from-channel-injection-token.ts +++ b/src/common/utils/channel/request-from-channel-injection-token.ts @@ -3,19 +3,19 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectionToken } from "@ogre-tools/injectable"; -import type { SetRequired } from "type-fest"; import type { RequestChannel } from "./request-channel-injection-token"; export type RequestFromChannel = < - TChannel extends RequestChannel, + Channel, + Request = Channel extends RequestChannel ? Request : never, + Response = Channel extends RequestChannel ? Response : never, >( - channel: TChannel, - ...request: TChannel["_requestSignature"] extends void + channel: Channel, + ...request: Request extends void ? [] - : [TChannel["_requestSignature"]] -) => Promise["_responseSignature"]>; + : [Request] +) => Promise; -export const requestFromChannelInjectionToken = - getInjectionToken({ - id: "request-from-request-channel", - }); +export const requestFromChannelInjectionToken = getInjectionToken({ + id: "request-from-request-channel", +}); diff --git a/src/main/app-paths/app-paths-request-channel-listener.injectable.ts b/src/main/app-paths/app-paths-request-channel-listener.injectable.ts index 3bd0c95bf7..4f44a0656d 100644 --- a/src/main/app-paths/app-paths-request-channel-listener.injectable.ts +++ b/src/main/app-paths/app-paths-request-channel-listener.injectable.ts @@ -3,8 +3,8 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import type { RequestChannelListener } from "../../common/utils/channel/request-channel-listener-injection-token"; -import { requestChannelListenerInjectionToken } from "../../common/utils/channel/request-channel-listener-injection-token"; +import type { RequestChannelHandlerDescriptor } from "../../common/utils/channel/request-channel-listener-injection-token"; +import { requestChannelHandlerInjectionToken } from "../../common/utils/channel/request-channel-listener-injection-token"; import type { AppPathsChannel } from "../../common/app-paths/app-paths-channel.injectable"; import appPathsChannelInjectable from "../../common/app-paths/app-paths-channel.injectable"; import appPathsInjectable from "../../common/app-paths/app-paths.injectable"; @@ -12,7 +12,7 @@ import appPathsInjectable from "../../common/app-paths/app-paths.injectable"; const appPathsRequestChannelListenerInjectable = getInjectable({ id: "app-paths-request-channel-listener", - instantiate: (di): RequestChannelListener => { + instantiate: (di): RequestChannelHandlerDescriptor => { const channel = di.inject(appPathsChannelInjectable); const appPaths = di.inject(appPathsInjectable); @@ -21,7 +21,7 @@ const appPathsRequestChannelListenerInjectable = getInjectable({ handler: () => appPaths, }; }, - injectionToken: requestChannelListenerInjectionToken, + injectionToken: requestChannelHandlerInjectionToken, }); export default appPathsRequestChannelListenerInjectable; diff --git a/src/main/lens-proxy/proxy-functions/shell/auth-token-channel-handler.injectable.ts b/src/main/lens-proxy/proxy-functions/shell/auth-token-channel-handler.injectable.ts new file mode 100644 index 0000000000..115f6f9fab --- /dev/null +++ b/src/main/lens-proxy/proxy-functions/shell/auth-token-channel-handler.injectable.ts @@ -0,0 +1,18 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import getShellAuthTokenChannelInjectable from "../../../../common/shell-authentication/get-auth-token-channel.injectable"; +import { getRequestChannelHandlerInjectable } from "../../../../common/utils/channel/request-channel-listener-injection-token"; +import shellRequestAuthenticatorInjectable from "./request-authenticator.injectable"; + +const getShellAuthTokenChannelHandlerInjectable = getRequestChannelHandlerInjectable( + getShellAuthTokenChannelInjectable, + (di) => { + const authenticator = di.inject(shellRequestAuthenticatorInjectable); + + return ({ clusterId, tabId }) => authenticator.getTokenFor(clusterId, tabId); + }, +); + +export default getShellAuthTokenChannelHandlerInjectable; diff --git a/src/main/utils/sync-box/sync-box-initial-value-channel-listener.injectable.ts b/src/main/utils/sync-box/sync-box-initial-value-channel-listener.injectable.ts index 5eb043291a..2a47c0343d 100644 --- a/src/main/utils/sync-box/sync-box-initial-value-channel-listener.injectable.ts +++ b/src/main/utils/sync-box/sync-box-initial-value-channel-listener.injectable.ts @@ -2,30 +2,20 @@ * 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 syncBoxInitialValueChannelInjectable from "../../../common/utils/sync-box/sync-box-initial-value-channel.injectable"; import { syncBoxInjectionToken } from "../../../common/utils/sync-box/sync-box-injection-token"; -import { requestChannelListenerInjectionToken } from "../../../common/utils/channel/request-channel-listener-injection-token"; +import { getRequestChannelHandlerInjectable } from "../../../common/utils/channel/request-channel-listener-injection-token"; -const syncBoxInitialValueChannelListenerInjectable = getInjectable({ - id: "sync-box-initial-value-channel-listener", - - instantiate: (di) => { - const channel = di.inject(syncBoxInitialValueChannelInjectable); +const syncBoxInitialValueChannelListenerInjectable = getRequestChannelHandlerInjectable( + syncBoxInitialValueChannelInjectable, + (di) => { const syncBoxes = di.injectMany(syncBoxInjectionToken); - return { - channel, - - handler: () => - syncBoxes.map((box) => ({ - id: box.id, - value: box.value.get(), - })), - }; + return () => syncBoxes.map((box) => ({ + id: box.id, + value: box.value.get(), + })); }, - - injectionToken: requestChannelListenerInjectionToken, -}); +); export default syncBoxInitialValueChannelListenerInjectable; diff --git a/src/renderer/api/terminal-api.ts b/src/renderer/api/terminal-api.ts index 75d907616c..0d68526e22 100644 --- a/src/renderer/api/terminal-api.ts +++ b/src/renderer/api/terminal-api.ts @@ -8,10 +8,10 @@ import { WebSocketApi } from "./websocket-api"; import isEqual from "lodash/isEqual"; import url from "url"; import { makeObservable, observable } from "mobx"; -import { ipcRenderer } from "electron"; import logger from "../../common/logger"; import { once } from "lodash"; import { type TerminalMessage, TerminalChannels } from "../../common/terminal/channels"; +import type { GetShellAuthToken } from "../../common/shell-authentication/get-auth-token.injectable"; enum TerminalColor { RED = "\u001b[31m", @@ -38,6 +38,7 @@ export interface TerminalEvents extends WebSocketEvents { export interface TerminalApiDependencies { readonly hostedClusterId: string; + getShellAuthToken: GetShellAuthToken; } export class TerminalApi extends WebSocketApi { @@ -66,12 +67,10 @@ export class TerminalApi extends WebSocketApi { this.emitStatus("Connecting ..."); } - const authTokenArray = await ipcRenderer.invoke("cluster:shell-api", this.dependencies.hostedClusterId, this.query.id); - - if (!(authTokenArray instanceof Uint8Array)) { - throw new TypeError("ShellApi token is not a Uint8Array"); - } - + const authTokenArray = await this.dependencies.getShellAuthToken({ + clusterId: this.dependencies.hostedClusterId, + tabId: this.query.id, + }); const { hostname, protocol, port } = location; const socketUrl = url.format({ protocol: protocol.includes("https") ? "wss" : "ws", 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 8ee4227289..d0c3183075 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 @@ -4,14 +4,14 @@ */ import type { DiContainer } from "@ogre-tools/injectable"; import type { RequestChannel } from "../../common/utils/channel/request-channel-injection-token"; -import type { RequestChannelListener } from "../../common/utils/channel/request-channel-listener-injection-token"; +import type { RequestChannelHandlerDescriptor } from "../../common/utils/channel/request-channel-listener-injection-token"; import enlistRequestChannelListenerInjectableInMain from "../../main/utils/channel/channel-listeners/enlist-request-channel-listener.injectable"; import requestFromChannelInjectable from "../../renderer/utils/channel/request-from-channel.injectable"; export const overrideRequestingFromWindowToMain = (mainDi: DiContainer) => { const requestChannelListenerFakesForMain = new Map< string, - RequestChannelListener> + RequestChannelHandlerDescriptor> >(); mainDi.override( @@ -28,7 +28,7 @@ export const overrideRequestingFromWindowToMain = (mainDi: DiContainer) => { listener.channel.id, // TODO: Figure out typing - listener as unknown as RequestChannelListener< + listener as unknown as RequestChannelHandlerDescriptor< RequestChannel >, );