diff --git a/src/common/system-ca.test.ts b/src/common/system-ca.test.ts new file mode 100644 index 0000000000..1cc72adc7f --- /dev/null +++ b/src/common/system-ca.test.ts @@ -0,0 +1,31 @@ +import https from "https"; +import { injectMacCA } from "./system-ca"; +import { dependencies, devDependencies } from "../../package.json"; + +describe("injectMacCA()", () => { + + // for reset https.globalAgent.options.ca after testing + let _ca: string | Buffer | (string | Buffer)[]; + + beforeEach(() => { + _ca = https.globalAgent.options.ca; + }); + + afterEach(() => { + https.globalAgent.options.ca = _ca; + }); + + const deps = { ...dependencies, ...devDependencies }; + + // skip the test if mac-ca is not installed + (deps["mac-ca"] ? it: it.skip)("should inject the same ca as mac-ca", async () => { + injectMacCA(); + const injected = https.globalAgent.options.ca; + + await import("mac-ca"); + const injectedByMacCA = https.globalAgent.options.ca; + + // @ts-ignore + expect(new Set(injected)).toEqual(new Set(injectedByMacCA)); + }); +}); diff --git a/src/common/system-ca.ts b/src/common/system-ca.ts index 6119436fe6..d778f17697 100644 --- a/src/common/system-ca.ts +++ b/src/common/system-ca.ts @@ -1,16 +1,28 @@ import { isMac, isWindows } from "./vars"; import winca from "win-ca"; -import macca from "mac-ca"; -import logger from "../main/logger"; +import { spawnSync } from "child_process"; +import https from "https"; -if (isMac) { - for (const crt of macca.all()) { - const attributes = crt.issuer?.attributes?.map((a: any) => `${a.name}=${a.value}`); +const injectMacCA = () => { + // inspired mac-ca (abandoned by author) + // https://github.com/jfromaniello/mac-ca + const args = ["find-certificate", "-a", "-p"]; + const splitPattern = /(?=-----BEGIN\sCERTIFICATE-----)/g; + const systemRootCertsPath = "/System/Library/Keychains/SystemRootCertificates.keychain"; + const trusted = spawnSync("/usr/bin/security", args).stdout.toString().split(splitPattern); + const rootCerts = spawnSync("/usr/bin/security", args.concat(systemRootCertsPath)).stdout.toString().split(splitPattern); + const certs = [...new Set([...trusted, ...rootCerts])]; - logger.debug(`Using host CA: ${attributes.join(",")}`); + for (const cert of certs) { + if (Array.isArray(https.globalAgent.options.ca)) { + !https.globalAgent.options.ca.includes(cert) && https.globalAgent.options.ca.push(cert); + } else { + https.globalAgent.options.ca = [cert]; + } } -} +}; -if (isWindows) { - winca.inject("+"); // see: https://github.com/ukoloff/win-ca#caveats -} +isMac && injectMacCA(); +isWindows && winca.inject("+"); // see: https://github.com/ukoloff/win-ca#caveats + +export { injectMacCA };