Skip to content

Commit 0eff973

Browse files
committed
Use certificate expiry to limit caching and regenerate appropriately
1 parent 84465f9 commit 0eff973

2 files changed

Lines changed: 28 additions & 23 deletions

File tree

src/server/http-combo-server.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,28 @@ export async function createComboServer(options: ComboServerOptions): Promise<De
200200
ALPNProtocols: serverProtocolPreferences
201201
}
202202

203-
// Cache secure contexts by domain to avoid expensive re-creation on every connection
204-
const secureContextCache = new Map<string, tls.SecureContext>();
203+
// Cache secure contexts by domain with expiry tracking, with 1h buffer
204+
const EXPIRY_BUFFER_MS = 60 * 60 * 1000;
205+
const secureContextCache = new Map<string, { context: tls.SecureContext, expiresAt: Date }>();
206+
207+
const getSecureContext = async (domain: string): Promise<tls.SecureContext> => {
208+
const cached = secureContextCache.get(domain);
209+
const now = Date.now();
210+
211+
if (cached && cached.expiresAt.getTime() - now > EXPIRY_BUFFER_MS) {
212+
return cached.context;
213+
}
214+
215+
// Generate new cert (either not cached or expiring soon)
216+
const generatedCert = await ca.generateCertificate(domain);
217+
const context = tls.createSecureContext({
218+
key: generatedCert.key,
219+
cert: generatedCert.cert,
220+
ca: generatedCert.ca
221+
});
222+
secureContextCache.set(domain, { context, expiresAt: generatedCert.expiresAt });
223+
return context;
224+
};
205225

206226
tlsServer = tls.createServer({
207227
key: defaultCert.key,
@@ -213,17 +233,7 @@ export async function createComboServer(options: ComboServerOptions): Promise<De
213233
if (options.debug) console.log(`Generating certificate for ${domain}`);
214234

215235
try {
216-
let secureContext = secureContextCache.get(domain);
217-
if (!secureContext) {
218-
const generatedCert = await ca.generateCertificate(domain);
219-
secureContext = tls.createSecureContext({
220-
key: generatedCert.key,
221-
cert: generatedCert.cert,
222-
ca: generatedCert.ca
223-
});
224-
secureContextCache.set(domain, secureContext);
225-
}
226-
cb(null, secureContext);
236+
cb(null, await getSecureContext(domain));
227237
} catch (e) {
228238
console.error('Cert generation error', e);
229239
cb(e);

src/util/certificates.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ export type PEM = string | string[] | Buffer | Buffer[];
5454
export type GeneratedCertificate = {
5555
key: string,
5656
cert: string,
57-
ca: string
57+
ca: string,
58+
expiresAt: Date
5859
};
5960

6061
const SUBJECT_NAME_MAP: { [key: string]: string } = {
@@ -311,14 +312,11 @@ export type { CA };
311312
class CA {
312313
private options: BaseCAOptions;
313314

314-
private certCache: { [domain: string]: GeneratedCertificate };
315-
316315
constructor(
317316
private caCert: x509.X509Certificate,
318317
private caKey: CryptoKey,
319318
options?: BaseCAOptions
320319
) {
321-
this.certCache = {};
322320
this.options = options ?? {};
323321

324322
const keyLength = this.options.keyLength || 2048;
@@ -337,9 +335,6 @@ class CA {
337335
}
338336

339337
async generateCertificate(domain: string): Promise<GeneratedCertificate> {
340-
// TODO: Expire domains from the cache? Based on their actual expiry?
341-
if (this.certCache[domain]) return this.certCache[domain];
342-
343338
const leafKeyPair = await KEY_PAIR!.value;
344339

345340
if (domain.includes('_')) {
@@ -427,16 +422,16 @@ class CA {
427422
extensions
428423
});
429424

430-
const generatedCertificate = {
425+
const generatedCertificate: GeneratedCertificate = {
431426
key: arrayBufferToPem(
432427
await crypto.subtle.exportKey("pkcs8", leafKeyPair.privateKey as CryptoKey),
433428
"PRIVATE KEY"
434429
),
435430
cert: certificate.toString("pem"),
436-
ca: this.caCert.toString("pem")
431+
ca: this.caCert.toString("pem"),
432+
expiresAt: notAfter
437433
};
438434

439-
this.certCache[domain] = generatedCertificate;
440435
return generatedCertificate;
441436
}
442437
}

0 commit comments

Comments
 (0)