@cto.af/ca
Version:
Testing-only Certificate Authority (CA) for your local development environment ONLY. This is in no way suitable for production of any kind.
71 lines (70 loc) • 2.45 kB
JavaScript
import { CertificateAuthority } from './index.js';
import assert from 'node:assert';
import tls from 'node:tls';
const origCsC = tls.createSecureContext;
const EXPECTED_NAME = 'createSecureContext';
let currentSym = undefined;
/**
* Override tls.createSecureContext to trust a CA cert specified by the
* options. WARNING: Do not call this function more than once without calling
* resetCreateSecureContext.
*
* @param options CA options.
* @returns Unique symbol, to be used in resetCreateSecureContext.
* @throws On invalid state.
*/
export async function overrideCreateSecureContext(options) {
let cert = undefined;
if (typeof options === 'string') {
cert = options;
}
else {
const CA = new CertificateAuthority(options);
const { ca } = await CA.init();
assert(ca, 'Will always be filled in if no exception thrown');
({ cert } = ca);
}
assert.equal(origCsC.name, EXPECTED_NAME, 'Original createSecureContext already hooked');
if (currentSym !== undefined) {
throw new Error('Current createSecureContext already hooked');
}
// New symbol every time.
currentSym = Symbol('overrideCreateSecureContext');
tls.createSecureContext =
(opts) => {
const res = origCsC(opts);
res.context.addCACert(cert);
return res;
};
return currentSym;
}
/**
* Reset tls.createSecureContext back to its default. This must match
* a corresponding call to overrideCreateSecureContext.
*
* @param sym Unique symbol returned from overrideCreateSecureContext.
* @throws On invalid state.
*/
export function resetCreateSecureContext(sym) {
assert.equal(origCsC.name, EXPECTED_NAME, 'Original createSecureContext already hooked');
if (!sym || sym !== currentSym) {
throw new Error('Current override does not match');
}
currentSym = undefined;
tls.createSecureContext = origCsC;
}
/**
* Trust the CA cert that CertificateAuthority generates for all node.js TLS
* operations, including fetch, but only for the duration of this function
* call.
*
* @param options Certificate options.
* @param during Callback during which the cert will be valid.
* @returns The result of during.
*/
export async function whileCAtrusted(options, during) {
const sym = await overrideCreateSecureContext(options);
const val = await during();
resetCreateSecureContext(sym);
return val;
}