Skip to content

Commit

Permalink
Split certificates from NODE_EXTRA_CA_CERTS (#637)
Browse files Browse the repository at this point in the history
If `NODE_EXTRA_CA_CERTS` contains multiple certificates, they need to
be split before being passed to `workerd`. This change fixes that,
and adds a test for `NODE_EXTRA_CA_CERTS` handling in general.
  • Loading branch information
mrbbot committed Jul 24, 2023
1 parent b8c93f1 commit 1c25f30
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 1 deletion.
7 changes: 6 additions & 1 deletion packages/miniflare/src/plugins/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,12 @@ if (process.env.NODE_EXTRA_CA_CERTS !== undefined) {
// https://nodejs.org/api/cli.html#node_extra_ca_certsfile
try {
const extra = readFileSync(process.env.NODE_EXTRA_CA_CERTS, "utf8");
trustedCertificates.push(extra);
// Split bundle into individual certificates and add each individually:
// https://github.com/cloudflare/miniflare/pull/587/files#r1271579671
const pemBegin = "-----BEGIN";
for (const cert of extra.split(pemBegin)) {
if (cert.trim() !== "") trustedCertificates.push(pemBegin + cert);
}
} catch {}
}

Expand Down
90 changes: 90 additions & 0 deletions packages/miniflare/test/plugins/core/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import childProcess from "child_process";
import { once } from "events";
import fs from "fs/promises";
import https from "https";
import { AddressInfo } from "net";
import path from "path";
import { text } from "stream/consumers";
import tls from "tls";
import test from "ava";
import stoppable from "stoppable";
import which from "which";
import { useTmp } from "../../test-shared";

const opensslInstalled = which.sync("openssl", { nothrow: true });
const opensslTest = opensslInstalled ? test : test.skip;
opensslTest("NODE_EXTRA_CA_CERTS: loads certificates", async (t) => {
const tmp = await useTmp(t);

// Generate self-signed certificate
childProcess.execSync(
'openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 30 -out cert.pem -subj "/CN=localhost"',
{ cwd: tmp, stdio: "ignore" }
);
const keyPath = path.join(tmp, "key.pem");
const certPath = path.join(tmp, "cert.pem");
const key = await fs.readFile(keyPath);
const cert = await fs.readFile(certPath);

// Start HTTPS server with self-signed certificate
const responseBody = "secure body";
const server = https.createServer({ key, cert }, (req, res) => {
res.end(responseBody);
});
const stoppableServer = stoppable(server, /* grace */ 0);
const url = await new Promise<string>((resolve) => {
server.listen(0, () => {
t.teardown(() => {
return new Promise((resolve, reject) =>
stoppableServer.stop((err) => (err ? reject(err) : resolve()))
);
});
const port = (server.address() as AddressInfo).port;
resolve(`https://localhost:${port}`);
});
});

// Write NODE_EXTRA_CA_CERTS file, with multiple certificates
// (see https://github.com/cloudflare/miniflare/pull/587/files#r1271579671)
const caCertsPath = path.join(tmp, "bundle.pem");
const caCerts = [...tls.rootCertificates, cert];
await fs.writeFile(caCertsPath, caCerts.join("\n"));

// Start Miniflare with NODE_EXTRA_CA_CERTS environment variable
// (cannot use sync process methods here as that would block HTTPS server)
const result = childProcess.spawn(
process.execPath,
[
"-e",
`
const { Miniflare } = require("miniflare");
const mf = new Miniflare({
verbose: true,
modules: true,
script: \`export default {
fetch() {
return fetch(${JSON.stringify(url)});
}
}\`
});
(async () => {
const res = await mf.dispatchFetch("http://placeholder/");
const text = await res.text();
console.log(text);
await mf.dispose();
})();
`,
],
{
stdio: [/* in */ "ignore", /* out */ "pipe", /* error */ "inherit"],
env: { NODE_EXTRA_CA_CERTS: caCertsPath },
}
);

// Check response matches expected
const exitPromise = once(result, "exit");
const resultText = await text(result.stdout);
await exitPromise;
t.is(result.exitCode, 0);
t.is(resultText.trim(), responseBody);
});

0 comments on commit 1c25f30

Please sign in to comment.