Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix loading system CAs on non-linux platforms #7515

Merged
merged 9 commits into from
Apr 5, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/

import type { DiContainerForInjection, InjectionToken } from "@ogre-tools/injectable";
import { getInjectable } from "@ogre-tools/injectable";
import platformInjectable from "../vars/platform.injectable";

export interface PlatformSpecific<T> {
instantiate: () => T;
readonly platform: NodeJS.Platform;
}

const platformSpecificVersionInjectable = getInjectable({
id: "platform-specific-version",
instantiate: (di: DiContainerForInjection) => {
const targetPlatform = di.inject(platformInjectable);

return <T>(token: InjectionToken<PlatformSpecific<T>, void>) => (
di.injectMany(token)
.find(impl => impl.platform === targetPlatform)
?.instantiate()
);
},
});

export default platformSpecificVersionInjectable;

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@
*/

import { getInjectionToken } from "@ogre-tools/injectable";
import type { PlatformSpecific } from "../../../common/utils/platform-specific-version.injectable";

export const requestSystemCAsInjectionToken = getInjectionToken<() => Promise<string[]>>({
export type RequestSystemCAs = () => Promise<string[]>;

export const platformSpecificRequestSystemCAsInjectionToken = getInjectionToken<PlatformSpecific<RequestSystemCAs>>({
id: "platform-specific-request-system-cas-token",
});

export const requestSystemCAsInjectionToken = getInjectionToken<RequestSystemCAs>({
id: "request-system-cas-token",
});
Original file line number Diff line number Diff line change
@@ -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 "@k8slens/utilities";
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[]): AsyncResult<string[]> => {
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;
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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 () => []);

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,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 platformSpecificVersionInjectable from "../../../common/utils/platform-specific-version.injectable";
import { platformSpecificRequestSystemCAsInjectionToken, requestSystemCAsInjectionToken } from "../common/request-system-cas-token";

const requestSystemCAsInjectable = getInjectable({
id: "request-system-cas",
instantiate: (di) => {
const platformSpecificVersion = di.inject(platformSpecificVersionInjectable);
const platformSpecificRequestSystemCAs = platformSpecificVersion(platformSpecificRequestSystemCAsInjectionToken);

return platformSpecificRequestSystemCAs ?? (async () => []);
},
injectionToken: requestSystemCAsInjectionToken,
});

export default requestSystemCAsInjectable;

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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;
6 changes: 3 additions & 3 deletions packages/core/src/jest.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ jest.mock("./renderer/components/tooltip/withTooltip");
jest.mock("monaco-editor");

const getInjectables = (environment: "renderer" | "main", filePathGlob: string) => [
...glob.sync(`./{common,extensions,${environment}}/**/${filePathGlob}`, {
...glob.sync(`./{common,extensions,${environment},test-env}/**/${filePathGlob}`, {
cwd: __dirname,
}),

Expand All @@ -70,10 +70,10 @@ const getInjectables = (environment: "renderer" | "main", filePathGlob: string)
global.injectablePaths = {
renderer: {
globalOverridePaths: getInjectables("renderer", "*.global-override-for-injectable.{ts,tsx}"),
paths: getInjectables("renderer", "*.{injectable,injectable.testing-env}.{ts,tsx}"),
paths: getInjectables("renderer", "*.injectable.{ts,tsx}"),
},
main: {
globalOverridePaths: getInjectables("main", "*.global-override-for-injectable.{ts,tsx}"),
paths: getInjectables("main", "*.{injectable,injectable.testing-env}.{ts,tsx}"),
paths: getInjectables("main", "*.injectable.{ts,tsx}"),
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ export const applicationInformationFakeInjectable = getInjectable({
bundledKubectlVersion: "1.23.3",
bundledHelmVersion: "3.7.2",
sentryDsn: "",
contentSecurityPolicy:
"script-src 'unsafe-eval' 'self'; frame-src http://*.localhost:*/; img-src * data:",

contentSecurityPolicy: "script-src 'unsafe-eval' 'self'; frame-src http://*.localhost:*/; img-src * data:",
welcomeRoute: "/welcome",
copyright: "some-copyright-information",
description: "some-descriptive-text",
Expand Down
Loading