Skip to content

Commit

Permalink
Make injecting CAs injectable, remove mac-ca as dependency
Browse files Browse the repository at this point in the history
Signed-off-by: Sebastian Malton <sebastian@malton.name>
  • Loading branch information
Nokel81 committed Aug 22, 2022
1 parent 19eb290 commit 014b2ac
Show file tree
Hide file tree
Showing 15 changed files with 249 additions and 233 deletions.
1 change: 0 additions & 1 deletion package.json
Expand Up @@ -247,7 +247,6 @@
"js-yaml": "^4.1.0",
"jsdom": "^16.7.0",
"lodash": "^4.17.15",
"mac-ca": "^1.0.6",
"marked": "^4.0.18",
"md5-file": "^5.0.0",
"mobx": "^6.6.1",
Expand Down
99 changes: 0 additions & 99 deletions src/common/__tests__/system-ca.test.ts

This file was deleted.

@@ -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 "../test-utils/get-global-override";
import injectSystemCAsOnMacOSInjectable from "./inject-system-cas-on-macos.injectable";

export default getGlobalOverride(injectSystemCAsOnMacOSInjectable, () => async () => {});
@@ -0,0 +1,62 @@
/**
* 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 { globalAgent } from "https";
import execFileInjectable from "../fs/exec-file.injectable";
import loggerInjectable from "../logger.injectable";
import { isCertActive } from "./is-cert-active";
import isMacInjectable from "../vars/is-mac.injectable";
import { systemCAsInjectorInjectionToken } from "./system-cas-injector-token";

function injectCAs(CAs: string[]) {
for (const cert of CAs) {
if (Array.isArray(globalAgent.options.ca) && !globalAgent.options.ca.includes(cert)) {
globalAgent.options.ca.push(cert);
} else {
globalAgent.options.ca = [cert];
}
}
}

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Cheatsheet#other_assertions
const certSplitPattern = /(?=-----BEGIN\sCERTIFICATE-----)/g;

const injectSystemCAsOnMacOSInjectable = getInjectable({
id: "inject-system-cas-on-macOS",
instantiate: (di) => {
const execFile = di.inject(execFileInjectable);
const logger = di.inject(loggerInjectable);
const isMac = di.inject(isMacInjectable);

const execSecurity = async (...args: string[]) => {
const output = await execFile("/usr/bin/security", args);

return output.split(certSplitPattern);
};

if (!isMac) {
return async () => {};
}

return async () => {
try {
const [trusted, rootCA] = await Promise.all([
execSecurity("find-certificate", "-a", "-p"),
execSecurity("find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain"),
]);

const certs = [...new Set([...trusted, ...rootCA])].filter(isCertActive);

injectCAs(certs);
} catch (error) {
logger.warn(`[INJECT-CAS]: Error injecting root CAs from MacOSX: ${error}`);
}
};
},
causesSideEffects: true,
injectionToken: systemCAsInjectorInjectionToken,
});

export default injectSystemCAsOnMacOSInjectable;
@@ -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 "../test-utils/get-global-override";
import injectSystemCAsOnWindowsInjectable from "./inject-system-cas-on-windows.injectable";

export default getGlobalOverride(injectSystemCAsOnWindowsInjectable, () => async () => {});
@@ -0,0 +1,53 @@
/**
* 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 wincaAPI from "win-ca/api";
import loggerInjectable from "../logger.injectable";
import { isCertActive } from "./is-cert-active";
import isWindowsInjectable from "../vars/is-windows.injectable";
import { systemCAsInjectorInjectionToken } from "./system-cas-injector-token";

function getWinRootCA(): Promise<string[]> {
return new Promise((resolve) => {
const CAs: string[] = [];

wincaAPI({
format: wincaAPI.der2.pem,
inject: false,
ondata: (ca: string) => {
CAs.push(ca);
},
onend: () => {
resolve(CAs.filter(isCertActive));
},
});
});
}

const injectSystemCAsOnWindowsInjectable = getInjectable({
id: "inject-system-cas-on-windows",
instantiate: (di) => {
const logger = di.inject(loggerInjectable);
const isWindows = di.inject(isWindowsInjectable);

if (!isWindows) {
return async () => {};
}

return async () => {
try {
const winRootCAs = await getWinRootCA();

wincaAPI.inject("+", winRootCAs);
} catch (error) {
logger.warn(`[INJECT-CAS]: Error injecting root CAs from Windows: ${error}`);
}
};
},
causesSideEffects: true,
injectionToken: systemCAsInjectorInjectionToken,
});

export default injectSystemCAsOnWindowsInjectable;
23 changes: 23 additions & 0 deletions src/common/certificate-authorities/inject-system-cas.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 { systemCAsInjectorInjectionToken } from "./system-cas-injector-token";

const injectSystemCAsInjectable = getInjectable({
id: "inject-system-cas",
instantiate: (di) => {
const systemCAsInjectors = di.injectMany(systemCAsInjectorInjectionToken);

return async () => {
for (const systemCAsInjector of systemCAsInjectors) {
await systemCAsInjector();
}
};
},
});

export default injectSystemCAsInjectable;

14 changes: 14 additions & 0 deletions src/common/certificate-authorities/is-cert-active.ts
@@ -0,0 +1,14 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/


// DST Root CA X3, which was expired on 9.30.2021
export const DSTRootCAX3 = "-----BEGIN CERTIFICATE-----\nMIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/\nMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\nDkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow\nPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD\nEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O\nrz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq\nOLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b\nxiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD\naeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\nHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG\nSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69\nikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr\nAvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz\nR8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5\nJDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo\nOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n-----END CERTIFICATE-----\n";

export function isCertActive(cert: string) {
const isExpired = typeof cert !== "string" || cert.includes(DSTRootCAX3);

return !isExpired;
}
63 changes: 63 additions & 0 deletions src/common/certificate-authorities/system-ca.test.ts
@@ -0,0 +1,63 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import https from "https";
import { DSTRootCAX3 } from "./is-cert-active";
import assert from "assert";
import { describeIf } from "../../test-utils/skippers";
import { platform } from "process";
import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
import injectSystemCAsOnMacOSInjectable from "./inject-system-cas-on-macos.injectable";
import injectSystemCAsOnWindowsInjectable from "./inject-system-cas-on-windows.injectable";

describe("CA tests", () => {
let injectSystemCAsOnMacOS: () => Promise<void>;
let injectSystemCAsOnWindows: () => Promise<void>;

beforeEach(() => {
const di = getDiForUnitTesting();

di.unoverride(injectSystemCAsOnMacOSInjectable);
di.permitSideEffects(injectSystemCAsOnMacOSInjectable);

injectSystemCAsOnMacOS = di.inject(injectSystemCAsOnMacOSInjectable);

di.unoverride(injectSystemCAsOnWindowsInjectable);
di.permitSideEffects(injectSystemCAsOnWindowsInjectable);

injectSystemCAsOnWindows = di.inject(injectSystemCAsOnWindowsInjectable);
});

// for reset https.globalAgent.options.ca after testing
let _ca: string | Buffer | (string | Buffer)[] | undefined;

beforeEach(() => {
_ca = https.globalAgent.options.ca;
});

afterEach(() => {
https.globalAgent.options.ca = _ca;
});

describeIf(platform === "darwin")("on macos", () => {
it("shouldn't included the expired DST Root CA X3 on Mac", async () => {
await injectSystemCAsOnMacOS();

const injected = https.globalAgent.options.ca;

assert(injected);
expect(injected.includes(DSTRootCAX3)).toBeFalsy();
});
});

describeIf(platform === "win32")("on windows", () => {
it("shouldn't included the expired DST Root CA X3 on Windows", async () => {
await injectSystemCAsOnWindows();

const injected = https.globalAgent.options.ca as (string | Buffer)[];

expect(injected.includes(DSTRootCAX3)).toBeFalsy();
});
});
});
10 changes: 10 additions & 0 deletions src/common/certificate-authorities/system-cas-injector-token.ts
@@ -0,0 +1,10 @@
/**
* 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";

export const systemCAsInjectorInjectionToken = getInjectionToken<() => Promise<void>>({
id: "system-cas-injector-token",
});

0 comments on commit 014b2ac

Please sign in to comment.