Skip to content

Commit 50efb35

Browse files
committed
Even more ACME logging
1 parent e367131 commit 50efb35

File tree

1 file changed

+34
-20
lines changed

1 file changed

+34
-20
lines changed

src/tls-certificates/acme.ts

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import * as crypto from 'node:crypto';
22
import * as ACME from 'acme-client';
3+
import { MaybePromise } from '@httptoolkit/util';
4+
35
import { PersistentCertCache } from './cert-cache.js';
46

57
const ONE_MINUTE = 1000 * 60;
@@ -34,7 +36,7 @@ export class AcmeCA {
3436
}
3537

3638
private pendingAcmeChallenges: { [token: string]: string | undefined } = {}
37-
private pendingCertRenewals: { [domain: string]: Promise<AcmeGeneratedCertificate> | undefined } = {};
39+
private pendingCertRenewals: { [domain: string]: (Promise<AcmeGeneratedCertificate> & { id: string }) | undefined } = {};
3840

3941
private readonly acmeClient = ACME.crypto.createPrivateKey().then(
4042
(accountKey) => new ACME.Client({
@@ -73,10 +75,6 @@ export class AcmeCA {
7375
domain: string,
7476
options: { forceRegenerate?: boolean, attemptId: string }
7577
): Promise<AcmeGeneratedCertificate> {
76-
if (!options.attemptId) {
77-
options.attemptId = Math.random().toString(16).slice(2);
78-
}
79-
8078
const cachedCert = this.certCache.getCert(domain);
8179
if (cachedCert && !options.forceRegenerate) {
8280
// If we have this cert in the cache, we generally want to use that.
@@ -89,17 +87,24 @@ export class AcmeCA {
8987
}
9088

9189
if (
92-
cachedCert.expiry - Date.now() < ONE_WEEK && // Expires soon
93-
!this.pendingCertRenewals[domain] // Not already updating
90+
cachedCert.expiry - Date.now() < ONE_WEEK // Expires soon
9491
) {
95-
// Not yet expired, but expiring soon - we want to refresh this certificate, but
96-
// we're OK to do it async and keep using the current one for now.
97-
console.log(`Renewing near-expiry certificate for ${domain} (${options.attemptId})`);
98-
99-
this.pendingCertRenewals[domain] = this.getCertificate(domain, {
100-
forceRegenerate: true,
101-
attemptId: options.attemptId
102-
});
92+
if (!this.pendingCertRenewals[domain]) {
93+
// Not yet expired, but expiring soon - we want to refresh this certificate, but
94+
// we're OK to do it async and keep using the current one for now.
95+
console.log(`Renewing near-expiry certificate for ${domain} (${options.attemptId})`);
96+
97+
this.pendingCertRenewals[domain] = Object.assign(this.getCertificate(domain, {
98+
forceRegenerate: true,
99+
attemptId: options.attemptId
100+
}), { id: options.attemptId });
101+
} else {
102+
console.log(`Certificate refresh already pending for ${domain} (${options.attemptId}) from attempt ${
103+
this.pendingCertRenewals[domain]!.id
104+
}`);
105+
}
106+
} else {
107+
console.log(`Cached cert still valid for ${domain} (${options.attemptId})`);
103108
}
104109

105110
return cachedCert;
@@ -109,32 +114,41 @@ export class AcmeCA {
109114
else if (options.forceRegenerate) console.log(`Force regenerating cert for ${domain} (${options.attemptId})`);
110115

111116
if (this.pendingCertRenewals[domain] && !options.forceRegenerate) {
117+
console.log(`Certificate generation already pending for ${domain} (${options.attemptId}) from attempt ${
118+
this.pendingCertRenewals[domain]!.id
119+
}`);
120+
112121
// Coalesce updates for pending certs into one
113122
return this.pendingCertRenewals[domain]!;
114123
}
115124

116-
const refreshPromise: Promise<AcmeGeneratedCertificate> = this.requestNewCertificate(domain, {
125+
const refreshPromise = Object.assign(this.requestNewCertificate(domain, {
117126
attemptId: options.attemptId
118-
}).then((certData) => {
127+
}).then((certData): MaybePromise<AcmeGeneratedCertificate> => {
119128
if (
120129
this.pendingCertRenewals[domain] &&
121130
this.pendingCertRenewals[domain] !== refreshPromise
122131
) {
132+
console.log(`Certificate generation for ${domain} (${options.attemptId}) superseded by another attempt ${
133+
this.pendingCertRenewals[domain]!.id
134+
}`);
135+
123136
// Don't think this should happen, but if we're somehow ever not the current cert
124137
// update, delegate to the 'real' cert update instead.
125138
return this.pendingCertRenewals[domain]!;
126139
}
127140

128141
delete this.pendingCertRenewals[domain];
129142
this.certCache.cacheCert({ ...certData, domain });
130-
console.log(`Cert refresh completed for domain ${domain} (${options.attemptId}), hash:${crypto.hash('sha256', certData.cert)}`);
143+
console.log(`Cert generation completed for domain ${domain} (${options.attemptId}), hash:${crypto.hash('sha256', certData.cert)}`);
131144
return certData;
132145
}).catch((e) => {
133-
console.log(`Cert refresh failed (${options.attemptId})`, e);
146+
console.log(`Cert generation failed (${options.attemptId})`, e);
134147
return this.getCertificate(domain, { forceRegenerate: true, attemptId: options.attemptId });
135-
});
148+
}), { id: options.attemptId });
136149

137150
this.pendingCertRenewals[domain] = refreshPromise;
151+
console.log(`Started cert generation for domain ${domain} (${options.attemptId})`);
138152
return refreshPromise;
139153
}
140154

0 commit comments

Comments
 (0)