diff --git a/packages/core/src/features/certificate-authorities/common/request-system-cas-token.ts b/packages/core/src/features/certificate-authorities/common/request-system-cas-token.ts index c69b0bd8b0..8e79d44e59 100644 --- a/packages/core/src/features/certificate-authorities/common/request-system-cas-token.ts +++ b/packages/core/src/features/certificate-authorities/common/request-system-cas-token.ts @@ -4,7 +4,10 @@ */ import { getInjectionToken } from "@ogre-tools/injectable"; +import type { PlatformSpecific } from "../../../common/utils/platform-specific-version.injectable"; -export const requestSystemCAsInjectionToken = getInjectionToken<() => Promise>({ +export type RequestSystemCAs = () => Promise; + +export const platformSpecificRequestSystemCAsInjectionToken = getInjectionToken>({ id: "request-system-cas-token", }); diff --git a/packages/core/src/features/certificate-authorities/main/darwin-request-system-cas.injectable.ts b/packages/core/src/features/certificate-authorities/main/darwin-request-system-cas.injectable.ts new file mode 100644 index 0000000000..0b50e83abc --- /dev/null +++ b/packages/core/src/features/certificate-authorities/main/darwin-request-system-cas.injectable.ts @@ -0,0 +1,60 @@ +/** + * 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 execFileInjectable from "../../../common/fs/exec-file.injectable"; +import loggerInjectable from "../../../common/logger.injectable"; +import type { AsyncResult } from "../../../common/utils/async-result"; +import { platformSpecificRequestSystemCAsInjectionToken } from "../common/request-system-cas-token"; + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Cheatsheet#other_assertions +const certSplitPattern = /(?=-----BEGIN\sCERTIFICATE-----)/g; + +const darwinRequestSystemCAsInjectable = getInjectable({ + id: "darwin-request-system-cas", + instantiate: (di) => ({ + platform: "darwin" as const, + instantiate: () => { + const execFile = di.inject(execFileInjectable); + const logger = di.inject(loggerInjectable); + + const execSecurity = async (...args: string[]): Promise> => { + const result = await execFile("/usr/bin/security", args); + + if (!result.callWasSuccessful) { + return { + callWasSuccessful: false, + error: result.error.stderr || result.error.message, + }; + } + + return { + callWasSuccessful: true, + response: result.response.split(certSplitPattern), + }; + }; + + return async () => { + const [trustedResult, rootCAResult] = await Promise.all([ + execSecurity("find-certificate", "-a", "-p"), + execSecurity("find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain"), + ]); + + if (!trustedResult.callWasSuccessful) { + logger.warn(`[INJECT-CAS]: Error retrieving trusted CAs: ${trustedResult.error}`); + } else if (!rootCAResult.callWasSuccessful) { + logger.warn(`[INJECT-CAS]: Error retrieving root CAs: ${rootCAResult.error}`); + } else { + return [...new Set([...trustedResult.response, ...rootCAResult.response])]; + } + + return []; + }; + }, + }), + causesSideEffects: true, + injectionToken: platformSpecificRequestSystemCAsInjectionToken, +}); + +export default darwinRequestSystemCAsInjectable; diff --git a/packages/core/src/features/certificate-authorities/main/linux-request-system-cas.injectable.ts b/packages/core/src/features/certificate-authorities/main/linux-request-system-cas.injectable.ts new file mode 100644 index 0000000000..520830fdf8 --- /dev/null +++ b/packages/core/src/features/certificate-authorities/main/linux-request-system-cas.injectable.ts @@ -0,0 +1,17 @@ +/** + * 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 { platformSpecificRequestSystemCAsInjectionToken } from "../common/request-system-cas-token"; + +const linuxRequestSystemCAsInjectable = getInjectable({ + id: "linux-request-system-cas", + instantiate: () => ({ + platform: "linux" as const, + instantiate: () => async () => [], + }), + injectionToken: platformSpecificRequestSystemCAsInjectionToken, +}); + +export default linuxRequestSystemCAsInjectable; diff --git a/packages/core/src/features/certificate-authorities/main/request-system-cas.global-override-for-injectable.ts b/packages/core/src/features/certificate-authorities/main/request-system-cas.global-override-for-injectable.ts new file mode 100644 index 0000000000..670f150b81 --- /dev/null +++ b/packages/core/src/features/certificate-authorities/main/request-system-cas.global-override-for-injectable.ts @@ -0,0 +1,9 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { getGlobalOverride } from "@k8slens/test-utils"; +import requestSystemCAsInjectable from "./request-system-cas.injectable"; + +export default getGlobalOverride(requestSystemCAsInjectable, () => async () => []); diff --git a/packages/core/src/features/certificate-authorities/main/request-system-cas.injectable.darwin.ts b/packages/core/src/features/certificate-authorities/main/request-system-cas.injectable.darwin.ts deleted file mode 100644 index 62cf75f6ff..0000000000 --- a/packages/core/src/features/certificate-authorities/main/request-system-cas.injectable.darwin.ts +++ /dev/null @@ -1,57 +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 execFileInjectable from "../../../common/fs/exec-file.injectable"; -import loggerInjectable from "../../../common/logger.injectable"; -import type { AsyncResult } from "../../../common/utils/async-result"; -import { requestSystemCAsInjectionToken } from "../common/request-system-cas-token"; - -// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Cheatsheet#other_assertions -const certSplitPattern = /(?=-----BEGIN\sCERTIFICATE-----)/g; - -const requestSystemCAsInjectable = getInjectable({ - id: "request-system-cas", - instantiate: (di) => { - const execFile = di.inject(execFileInjectable); - const logger = di.inject(loggerInjectable); - - const execSecurity = async (...args: string[]): Promise> => { - const result = await execFile("/usr/bin/security", args); - - if (!result.callWasSuccessful) { - return { - callWasSuccessful: false, - error: result.error.stderr || result.error.message, - }; - } - - return { - callWasSuccessful: true, - response: result.response.split(certSplitPattern), - }; - }; - - return async () => { - const [trustedResult, rootCAResult] = await Promise.all([ - execSecurity("find-certificate", "-a", "-p"), - execSecurity("find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain"), - ]); - - if (!trustedResult.callWasSuccessful) { - logger.warn(`[INJECT-CAS]: Error retreiving trusted CAs: ${trustedResult.error}`); - } else if (!rootCAResult.callWasSuccessful) { - logger.warn(`[INJECT-CAS]: Error retreiving root CAs: ${rootCAResult.error}`); - } else { - return [...new Set([...trustedResult.response, ...rootCAResult.response])]; - } - - return []; - }; - }, - causesSideEffects: true, - injectionToken: requestSystemCAsInjectionToken, -}); - -export default requestSystemCAsInjectable; diff --git a/packages/core/src/features/certificate-authorities/main/request-system-cas.injectable.testing-env.ts b/packages/core/src/features/certificate-authorities/main/request-system-cas.injectable.testing-env.ts deleted file mode 100644 index cffd0d172a..0000000000 --- a/packages/core/src/features/certificate-authorities/main/request-system-cas.injectable.testing-env.ts +++ /dev/null @@ -1,14 +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 { requestSystemCAsInjectionToken } from "../common/request-system-cas-token"; - -const requestSystemCAsInjectable = getInjectable({ - id: "request-system-cas", - instantiate: () => async () => [], - injectionToken: requestSystemCAsInjectionToken, -}); - -export default requestSystemCAsInjectable; diff --git a/packages/core/src/features/certificate-authorities/main/request-system-cas.injectable.linux.ts b/packages/core/src/features/certificate-authorities/main/request-system-cas.injectable.ts similarity index 50% rename from packages/core/src/features/certificate-authorities/main/request-system-cas.injectable.linux.ts rename to packages/core/src/features/certificate-authorities/main/request-system-cas.injectable.ts index cffd0d172a..e0c4c2fd47 100644 --- a/packages/core/src/features/certificate-authorities/main/request-system-cas.injectable.linux.ts +++ b/packages/core/src/features/certificate-authorities/main/request-system-cas.injectable.ts @@ -3,12 +3,12 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { requestSystemCAsInjectionToken } from "../common/request-system-cas-token"; +import platformSpecificVersionInjectable from "../../../common/utils/platform-specific-version.injectable"; +import { platformSpecificRequestSystemCAsInjectionToken } from "../common/request-system-cas-token"; const requestSystemCAsInjectable = getInjectable({ id: "request-system-cas", - instantiate: () => async () => [], - injectionToken: requestSystemCAsInjectionToken, + instantiate: (di) => di.inject(platformSpecificVersionInjectable)(platformSpecificRequestSystemCAsInjectionToken), }); export default requestSystemCAsInjectable; diff --git a/packages/core/src/features/certificate-authorities/main/request-system-cas.injectable.win32.ts b/packages/core/src/features/certificate-authorities/main/request-system-cas.injectable.win32.ts deleted file mode 100644 index 161b333677..0000000000 --- a/packages/core/src/features/certificate-authorities/main/request-system-cas.injectable.win32.ts +++ /dev/null @@ -1,56 +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 execFileInjectable from "../../../common/fs/exec-file.injectable"; -import loggerInjectable from "../../../common/logger.injectable"; -import { requestSystemCAsInjectionToken } from "../common/request-system-cas-token"; - -const pemEncoding = (hexEncodedCert: String) => { - const certData = Buffer.from(hexEncodedCert, "hex").toString("base64"); - const lines = ["-----BEGIN CERTIFICATE-----"]; - - for (let i = 0; i < certData.length; i += 64) { - lines.push(certData.substring(i, i + 64)); - } - - lines.push("-----END CERTIFICATE-----", ""); - - return lines.join("\r\n"); -}; - -const requestSystemCAsInjectable = getInjectable({ - id: "request-system-cas", - instantiate: (di) => { - const winCARootsExePath: string = __non_webpack_require__.resolve("win-ca/lib/roots.exe"); - const execFile = di.inject(execFileInjectable); - const logger = di.inject(loggerInjectable); - - return async () => { - /** - * This needs to be done manually because for some reason calling the api from "win-ca" - * directly fails to load "child_process" correctly on renderer - */ - const result = await execFile(winCARootsExePath, { - maxBuffer: 128 * 1024 * 1024, // 128 MiB - }); - - if (!result.callWasSuccessful) { - logger.warn(`[INJECT-CAS]: Error retrieving CAs`, result.error); - - return []; - } - - return result - .response - .split("\r\n") - .filter(Boolean) - .map(pemEncoding); - }; - }, - causesSideEffects: true, - injectionToken: requestSystemCAsInjectionToken, -}); - -export default requestSystemCAsInjectable; diff --git a/packages/core/src/features/certificate-authorities/main/win32-request-system-cas.injectable.ts b/packages/core/src/features/certificate-authorities/main/win32-request-system-cas.injectable.ts new file mode 100644 index 0000000000..2c4cc6f906 --- /dev/null +++ b/packages/core/src/features/certificate-authorities/main/win32-request-system-cas.injectable.ts @@ -0,0 +1,59 @@ +/** + * 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 execFileInjectable from "../../../common/fs/exec-file.injectable"; +import loggerInjectable from "../../../common/logger.injectable"; +import { platformSpecificRequestSystemCAsInjectionToken } from "../common/request-system-cas-token"; + +const pemEncoding = (hexEncodedCert: String) => { + const certData = Buffer.from(hexEncodedCert, "hex").toString("base64"); + const lines = ["-----BEGIN CERTIFICATE-----"]; + + for (let i = 0; i < certData.length; i += 64) { + lines.push(certData.substring(i, i + 64)); + } + + lines.push("-----END CERTIFICATE-----", ""); + + return lines.join("\r\n"); +}; + +const win32RequestSystemCAsInjectable = getInjectable({ + id: "win32-request-system-cas", + instantiate: (di) => ({ + platform: "win32" as const, + instantiate: () => { + const winCARootsExePath: string = __non_webpack_require__.resolve("win-ca/lib/roots.exe"); + const execFile = di.inject(execFileInjectable); + const logger = di.inject(loggerInjectable); + + return async () => { + /** + * This needs to be done manually because for some reason calling the api from "win-ca" + * directly fails to load "child_process" correctly on renderer + */ + const result = await execFile(winCARootsExePath, { + maxBuffer: 128 * 1024 * 1024, // 128 MiB + }); + + if (!result.callWasSuccessful) { + logger.warn(`[INJECT-CAS]: Error retrieving CAs`, result.error); + + return []; + } + + return result + .response + .split("\r\n") + .filter(Boolean) + .map(pemEncoding); + }; + }, + }), + causesSideEffects: true, + injectionToken: platformSpecificRequestSystemCAsInjectionToken, +}); + +export default win32RequestSystemCAsInjectable;