@push.rocks/smartacme 6.2.0 → 7.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/certmanagers/index.d.ts +2 -0
- package/dist_ts/certmanagers/index.js +3 -0
- package/dist_ts/certmanagers/memory.d.ts +18 -0
- package/dist_ts/certmanagers/memory.js +33 -0
- package/dist_ts/certmanagers/mongo.d.ts +23 -0
- package/dist_ts/certmanagers/mongo.js +40 -0
- package/dist_ts/certmanagers.d.ts +42 -0
- package/dist_ts/certmanagers.js +86 -0
- package/dist_ts/handlers/Dns01Handler.js +1 -3
- package/dist_ts/index.d.ts +2 -0
- package/dist_ts/index.js +2 -1
- package/dist_ts/interfaces/certmanager.d.ts +33 -0
- package/dist_ts/interfaces/certmanager.js +2 -0
- package/dist_ts/smartacme.classes.cert.d.ts +11 -4
- package/dist_ts/smartacme.classes.cert.js +23 -68
- package/dist_ts/smartacme.classes.certmanager.d.ts +18 -0
- package/dist_ts/smartacme.classes.certmanager.js +40 -1
- package/dist_ts/smartacme.classes.smartacme.d.ts +10 -3
- package/dist_ts/smartacme.classes.smartacme.js +65 -29
- package/package.json +2 -2
- package/readme.plan.md +13 -41
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/certmanagers/index.ts +2 -0
- package/ts/certmanagers/memory.ts +38 -0
- package/ts/certmanagers/mongo.ts +52 -0
- package/ts/handlers/Dns01Handler.ts +0 -8
- package/ts/index.ts +2 -0
- package/ts/interfaces/certmanager.ts +36 -0
- package/ts/smartacme.classes.cert.ts +22 -47
- package/ts/smartacme.classes.smartacme.ts +90 -33
- package/ts/smartacme.classes.certmanager.ts +0 -77
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import * as plugins from './smartacme.plugins.js';
|
|
2
|
-
import { SmartacmeCert } from './smartacme.classes.cert.js';
|
|
3
|
-
import { SmartacmeCertManager } from './smartacme.classes.certmanager.js';
|
|
4
2
|
import { SmartacmeCertMatcher } from './smartacme.classes.certmatcher.js';
|
|
5
3
|
import { commitinfo } from './00_commitinfo_data.js';
|
|
4
|
+
import { SmartacmeCert } from './smartacme.classes.cert.js';
|
|
6
5
|
/**
|
|
7
6
|
* class SmartAcme
|
|
8
7
|
* can be used for setting up communication with an ACME authority
|
|
@@ -24,10 +23,10 @@ export class SmartAcme {
|
|
|
24
23
|
this.logger.enableConsole();
|
|
25
24
|
// initialize retry/backoff options
|
|
26
25
|
this.retryOptions = {
|
|
27
|
-
retries: optionsArg.retryOptions?.retries ??
|
|
28
|
-
factor: optionsArg.retryOptions?.factor ??
|
|
26
|
+
retries: optionsArg.retryOptions?.retries ?? 10,
|
|
27
|
+
factor: optionsArg.retryOptions?.factor ?? 4,
|
|
29
28
|
minTimeoutMs: optionsArg.retryOptions?.minTimeoutMs ?? 1000,
|
|
30
|
-
maxTimeoutMs: optionsArg.retryOptions?.maxTimeoutMs ??
|
|
29
|
+
maxTimeoutMs: optionsArg.retryOptions?.maxTimeoutMs ?? 60000,
|
|
31
30
|
};
|
|
32
31
|
// initialize challenge handlers (must provide at least one)
|
|
33
32
|
if (!optionsArg.challengeHandlers || optionsArg.challengeHandlers.length === 0) {
|
|
@@ -39,6 +38,8 @@ export class SmartAcme {
|
|
|
39
38
|
optionsArg.challengePriority && optionsArg.challengePriority.length > 0
|
|
40
39
|
? optionsArg.challengePriority
|
|
41
40
|
: this.challengeHandlers.map((h) => h.getSupportedTypes()[0]);
|
|
41
|
+
// initialize interest coordination
|
|
42
|
+
this.interestMap = new plugins.lik.InterestMap((domain) => domain);
|
|
42
43
|
}
|
|
43
44
|
/**
|
|
44
45
|
* starts the instance
|
|
@@ -49,10 +50,11 @@ export class SmartAcme {
|
|
|
49
50
|
async start() {
|
|
50
51
|
this.privateKey =
|
|
51
52
|
this.options.accountPrivateKey || (await plugins.acme.forge.createPrivateKey()).toString();
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
53
|
+
// Initialize certificate manager
|
|
54
|
+
if (!this.options.certManager) {
|
|
55
|
+
throw new Error('You must provide a certManager via options.certManager');
|
|
56
|
+
}
|
|
57
|
+
this.certmanager = this.options.certManager;
|
|
56
58
|
await this.certmanager.init();
|
|
57
59
|
// CertMatcher
|
|
58
60
|
this.certmatcher = new SmartacmeCertMatcher();
|
|
@@ -77,8 +79,13 @@ export class SmartAcme {
|
|
|
77
79
|
process.on('SIGINT', () => this.handleSignal('SIGINT'));
|
|
78
80
|
process.on('SIGTERM', () => this.handleSignal('SIGTERM'));
|
|
79
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Stops the SmartAcme instance and closes certificate store connections.
|
|
84
|
+
*/
|
|
80
85
|
async stop() {
|
|
81
|
-
|
|
86
|
+
if (this.certmanager && typeof this.certmanager.close === 'function') {
|
|
87
|
+
await this.certmanager.close();
|
|
88
|
+
}
|
|
82
89
|
}
|
|
83
90
|
/** Retry helper with exponential backoff */
|
|
84
91
|
async retry(operation, operationName = 'operation') {
|
|
@@ -147,9 +154,27 @@ export class SmartAcme {
|
|
|
147
154
|
async getCertificateForDomain(domainArg) {
|
|
148
155
|
const certDomainName = this.certmatcher.getCertificateDomainNameByDomainName(domainArg);
|
|
149
156
|
const retrievedCertificate = await this.certmanager.retrieveCertificate(certDomainName);
|
|
157
|
+
// integration test stub: bypass ACME and return a dummy certificate
|
|
158
|
+
if (this.options.environment === 'integration') {
|
|
159
|
+
if (retrievedCertificate) {
|
|
160
|
+
return retrievedCertificate;
|
|
161
|
+
}
|
|
162
|
+
const dummy = plugins.smartunique.shortId();
|
|
163
|
+
const certRecord = new SmartacmeCert({
|
|
164
|
+
id: dummy,
|
|
165
|
+
domainName: certDomainName,
|
|
166
|
+
privateKey: dummy,
|
|
167
|
+
publicKey: dummy,
|
|
168
|
+
csr: dummy,
|
|
169
|
+
created: Date.now(),
|
|
170
|
+
validUntil: Date.now() + plugins.smarttime.getMilliSecondsFromUnits({ days: 90 }),
|
|
171
|
+
});
|
|
172
|
+
await this.certmanager.storeCertificate(certRecord);
|
|
173
|
+
return certRecord;
|
|
174
|
+
}
|
|
150
175
|
if (!retrievedCertificate &&
|
|
151
|
-
(await this.
|
|
152
|
-
const existingCertificateInterest = this.
|
|
176
|
+
(await this.interestMap.checkInterest(certDomainName))) {
|
|
177
|
+
const existingCertificateInterest = this.interestMap.findInterest(certDomainName);
|
|
153
178
|
const certificate = existingCertificateInterest.interestFullfilled;
|
|
154
179
|
return certificate;
|
|
155
180
|
}
|
|
@@ -157,10 +182,11 @@ export class SmartAcme {
|
|
|
157
182
|
return retrievedCertificate;
|
|
158
183
|
}
|
|
159
184
|
else if (retrievedCertificate && retrievedCertificate.shouldBeRenewed()) {
|
|
160
|
-
|
|
185
|
+
// Remove old certificate via certManager
|
|
186
|
+
await this.certmanager.deleteCertificate(certDomainName);
|
|
161
187
|
}
|
|
162
188
|
// lets make sure others get the same interest
|
|
163
|
-
const currentDomainInterst = await this.
|
|
189
|
+
const currentDomainInterst = await this.interestMap.addInterest(certDomainName);
|
|
164
190
|
/* Place new order with retry */
|
|
165
191
|
const order = await this.retry(() => this.client.createOrder({
|
|
166
192
|
identifiers: [
|
|
@@ -212,17 +238,31 @@ export class SmartAcme {
|
|
|
212
238
|
}
|
|
213
239
|
this.pendingChallenges.push(input);
|
|
214
240
|
try {
|
|
241
|
+
// Prepare the challenge (set DNS record, write file, etc.)
|
|
215
242
|
await this.retry(() => handler.prepare(input), `${type}.prepare`);
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
await this.retry(() => this.
|
|
243
|
+
// For DNS-01, wait for propagation before verification
|
|
244
|
+
if (type === 'dns-01') {
|
|
245
|
+
const dnsInput = input;
|
|
246
|
+
// Wait for authoritative DNS propagation before ACME verify
|
|
247
|
+
await this.retry(() => this.smartdns.checkUntilAvailable(dnsInput.hostName, 'TXT', dnsInput.challenge, 100, 5000), `${type}.propagation`);
|
|
248
|
+
// Extra cool-down to ensure ACME server sees the new TXT record
|
|
249
|
+
this.logger.log('info', 'Cooling down for 1 minute before ACME verification');
|
|
250
|
+
await plugins.smartdelay.delayFor(60000);
|
|
221
251
|
}
|
|
252
|
+
// Official ACME verification (ensures challenge is publicly reachable)
|
|
253
|
+
await this.retry(() => this.client.verifyChallenge(authz, selectedChallengeArg), `${type}.verifyChallenge`);
|
|
254
|
+
// Notify ACME server to complete the challenge
|
|
222
255
|
await this.retry(() => this.client.completeChallenge(selectedChallengeArg), `${type}.completeChallenge`);
|
|
223
|
-
|
|
256
|
+
// Wait for valid status (warnings on staging timeouts)
|
|
257
|
+
try {
|
|
258
|
+
await this.retry(() => this.client.waitForValidStatus(selectedChallengeArg), `${type}.waitForValidStatus`);
|
|
259
|
+
}
|
|
260
|
+
catch (err) {
|
|
261
|
+
await this.logger.log('warn', `Challenge ${type} did not reach valid status in time, proceeding to finalize`, err);
|
|
262
|
+
}
|
|
224
263
|
}
|
|
225
264
|
finally {
|
|
265
|
+
// Always cleanup resource
|
|
226
266
|
try {
|
|
227
267
|
await this.retry(() => handler.cleanup(input), `${type}.cleanup`);
|
|
228
268
|
}
|
|
@@ -242,25 +282,21 @@ export class SmartAcme {
|
|
|
242
282
|
await this.retry(() => this.client.finalizeOrder(order, csr), 'finalizeOrder');
|
|
243
283
|
const cert = await this.retry(() => this.client.getCertificate(order), 'getCertificate');
|
|
244
284
|
/* Done */
|
|
245
|
-
|
|
285
|
+
// Store the new certificate record
|
|
286
|
+
const certRecord = new SmartacmeCert({
|
|
246
287
|
id: plugins.smartunique.shortId(),
|
|
247
288
|
domainName: certDomainName,
|
|
248
289
|
privateKey: key.toString(),
|
|
249
290
|
publicKey: cert.toString(),
|
|
250
291
|
csr: csr.toString(),
|
|
251
292
|
created: Date.now(),
|
|
252
|
-
validUntil: Date.now() +
|
|
253
|
-
plugins.smarttime.getMilliSecondsFromUnits({
|
|
254
|
-
days: 90,
|
|
255
|
-
}),
|
|
293
|
+
validUntil: Date.now() + plugins.smarttime.getMilliSecondsFromUnits({ days: 90 }),
|
|
256
294
|
});
|
|
295
|
+
await this.certmanager.storeCertificate(certRecord);
|
|
257
296
|
const newCertificate = await this.certmanager.retrieveCertificate(certDomainName);
|
|
258
297
|
currentDomainInterst.fullfillInterest(newCertificate);
|
|
259
298
|
currentDomainInterst.destroy();
|
|
260
299
|
return newCertificate;
|
|
261
300
|
}
|
|
262
|
-
async getAllCertificates() {
|
|
263
|
-
return SmartacmeCert.getInstances({});
|
|
264
|
-
}
|
|
265
301
|
}
|
|
266
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhY21lLmNsYXNzZXMuc21hcnRhY21lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRhY21lLmNsYXNzZXMuc21hcnRhY21lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sd0JBQXdCLENBQUM7QUFDbEQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQzVELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQzFFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQzFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQW1DckQ7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBTSxPQUFPLFNBQVM7SUF3QnBCLFlBQVksVUFBNkI7UUFuQmpDLGFBQVEsR0FBRyxJQUFJLE9BQU8sQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBWTNELHFEQUFxRDtRQUM3QyxzQkFBaUIsR0FBNEMsRUFBRSxDQUFDO1FBT3RFLElBQUksQ0FBQyxPQUFPLEdBQUcsVUFBVSxDQUFDO1FBQzFCLElBQUksQ0FBQyxNQUFNLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsbUJBQW1CLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDeEUsK0NBQStDO1FBQy9DLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDNUIsbUNBQW1DO1FBQ25DLElBQUksQ0FBQyxZQUFZLEdBQUc7WUFDbEIsT0FBTyxFQUFFLFVBQVUsQ0FBQyxZQUFZLEVBQUUsT0FBTyxJQUFJLENBQUM7WUFDOUMsTUFBTSxFQUFFLFVBQVUsQ0FBQyxZQUFZLEVBQUUsTUFBTSxJQUFJLENBQUM7WUFDNUMsWUFBWSxFQUFFLFVBQVUsQ0FBQyxZQUFZLEVBQUUsWUFBWSxJQUFJLElBQUk7WUFDM0QsWUFBWSxF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
|
|
302
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhY21lLmNsYXNzZXMuc21hcnRhY21lLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRhY21lLmNsYXNzZXMuc21hcnRhY21lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sd0JBQXdCLENBQUM7QUFFbEQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFDMUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3JELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQXNDNUQ7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBTSxPQUFPLFNBQVM7SUEwQnBCLFlBQVksVUFBNkI7UUFyQmpDLGFBQVEsR0FBRyxJQUFJLE9BQU8sQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBWTNELHFEQUFxRDtRQUM3QyxzQkFBaUIsR0FBNEMsRUFBRSxDQUFDO1FBU3RFLElBQUksQ0FBQyxPQUFPLEdBQUcsVUFBVSxDQUFDO1FBQzFCLElBQUksQ0FBQyxNQUFNLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsbUJBQW1CLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDeEUsK0NBQStDO1FBQy9DLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDNUIsbUNBQW1DO1FBQ25DLElBQUksQ0FBQyxZQUFZLEdBQUc7WUFDbEIsT0FBTyxFQUFFLFVBQVUsQ0FBQyxZQUFZLEVBQUUsT0FBTyxJQUFJLEVBQUU7WUFDL0MsTUFBTSxFQUFFLFVBQVUsQ0FBQyxZQUFZLEVBQUUsTUFBTSxJQUFJLENBQUM7WUFDNUMsWUFBWSxFQUFFLFVBQVUsQ0FBQyxZQUFZLEVBQUUsWUFBWSxJQUFJLElBQUk7WUFDM0QsWUFBWSxFQUFFLFVBQVUsQ0FBQyxZQUFZLEVBQUUsWUFBWSxJQUFJLEtBQUs7U0FDN0Qs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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartacme",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A TypeScript-based ACME client for LetsEncrypt certificate management with a focus on simplicity and power.",
|
|
6
6
|
"main": "dist_ts/index.js",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"@git.zone/tsrun": "^1.3.3",
|
|
55
55
|
"@git.zone/tstest": "^1.0.96",
|
|
56
56
|
"@push.rocks/qenv": "^6.1.0",
|
|
57
|
-
"@push.rocks/tapbundle": "^6.0.
|
|
57
|
+
"@push.rocks/tapbundle": "^6.0.3",
|
|
58
58
|
"@types/node": "^22.15.3"
|
|
59
59
|
},
|
|
60
60
|
"files": [
|
package/readme.plan.md
CHANGED
|
@@ -1,44 +1,16 @@
|
|
|
1
|
-
# Plan:
|
|
1
|
+
# Plan: Move interestMap from certmanager to smartacme core
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
(e.g., Express).
|
|
3
|
+
## Goal
|
|
4
|
+
- Pull the interest coordination mechanism out of the ICertManager implementations and into the SmartAcme class.
|
|
6
5
|
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
## Steps
|
|
7
|
+
1. Remove `interestMap` from `ICertManager` interface (`ts/interfaces/certmanager.ts`) and its import of `InterestMap`.
|
|
8
|
+
2. Strip out `interestMap` property, initialization, and usage from `MemoryCertManager` and `MongoCertManager` (`ts/certmanagers/*.ts`).
|
|
9
|
+
3. In `Smartacme` class (`ts/smartacme.classes.smartacme.ts`):
|
|
10
|
+
- Add a private `interestMap: plugins.lik.InterestMap<string, SmartacmeCert>` property.
|
|
11
|
+
- Initialize it in the constructor: `this.interestMap = new plugins.lik.InterestMap((domain) => domain);`.
|
|
12
|
+
- Update `getCertificateForDomain()` and any other consumers to reference `this.interestMap` instead of `this.certmanager.interestMap`.
|
|
13
|
+
4. Remove any tests or code that reference the old `interestMap` on `ICertManager` (if any).
|
|
14
|
+
5. Run CI (`pnpm build` and `pnpm test`) and fix any regressions.
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
- Create `ts/handlers/Http01MemoryHandler.ts`:
|
|
19
|
-
- Implement `IChallengeHandler<{ token: string; keyAuthorization: string; webPath: string }>`, storing challenges in a private `Map<string, string>`.
|
|
20
|
-
- `prepare()`: add token→keyAuthorization mapping.
|
|
21
|
-
- `verify()`: no-op.
|
|
22
|
-
- `cleanup()`: remove mapping.
|
|
23
|
-
- Add `handleRequest(req, res, next?)` method:
|
|
24
|
-
- Parse `/.well-known/acme-challenge/:token` from `req.url`.
|
|
25
|
-
- If token exists, respond with the key authorization and status 200.
|
|
26
|
-
- If missing and `next` provided, call `next()`, otherwise respond 404.
|
|
27
|
-
- Export `Http01MemoryHandler` in `ts/handlers/index.ts`.
|
|
28
|
-
|
|
29
|
-
## 3. Write tests for Http01MemoryHandler
|
|
30
|
-
- Create `test/test.handlers-http01-memory.ts`:
|
|
31
|
-
- Use `tap` and `expect` to:
|
|
32
|
-
1. `prepare()` a challenge.
|
|
33
|
-
2. Invoke `handleRequest()` with a fake `req`/`res` to confirm 200 and correct body.
|
|
34
|
-
3. `cleanup()` the challenge.
|
|
35
|
-
4. Confirm `handleRequest()` now yields 404.
|
|
36
|
-
|
|
37
|
-
## 4. Update documentation
|
|
38
|
-
- Add examples in `readme.md` showing how to use both `Http01Webroot` and the new `Http01MemoryHandler`:
|
|
39
|
-
- Sample code for Express integration using `handleRequest`.
|
|
40
|
-
|
|
41
|
-
## 5. Build and test
|
|
42
|
-
- Run `pnpm build` and `pnpm test`, ensuring existing tests are updated for `Http01Webroot` and new tests pass.
|
|
43
|
-
|
|
44
|
-
Please review and let me know if this plan makes sense before proceeding with implementation.
|
|
16
|
+
Please review and confirm before we begin the refactor.
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as plugins from '../smartacme.plugins.js';
|
|
2
|
+
import type { ICertManager } from '../interfaces/certmanager.js';
|
|
3
|
+
import { SmartacmeCert } from '../smartacme.classes.cert.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* In-memory certificate manager for mongoless mode.
|
|
7
|
+
* Stores certificates in memory only and does not connect to MongoDB.
|
|
8
|
+
*/
|
|
9
|
+
export class MemoryCertManager implements ICertManager {
|
|
10
|
+
private certs: Map<string, SmartacmeCert> = new Map();
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
public async init(): Promise<void> {
|
|
14
|
+
// no-op for in-memory store
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public async retrieveCertificate(domainName: string): Promise<SmartacmeCert | null> {
|
|
18
|
+
return this.certs.get(domainName) ?? null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public async storeCertificate(cert: SmartacmeCert): Promise<void> {
|
|
22
|
+
this.certs.set(cert.domainName, cert);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public async deleteCertificate(domainName: string): Promise<void> {
|
|
26
|
+
this.certs.delete(domainName);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public async close(): Promise<void> {
|
|
30
|
+
// no-op
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Wipe all certificates from the in-memory store (for testing)
|
|
34
|
+
*/
|
|
35
|
+
public async wipe(): Promise<void> {
|
|
36
|
+
this.certs.clear();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as plugins from '../smartacme.plugins.js';
|
|
2
|
+
import type { ICertManager } from '../interfaces/certmanager.js';
|
|
3
|
+
import { SmartacmeCert } from '../smartacme.classes.cert.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* MongoDB-backed certificate manager using EasyStore from smartdata.
|
|
7
|
+
*/
|
|
8
|
+
export class MongoCertManager implements ICertManager {
|
|
9
|
+
private db: plugins.smartdata.SmartdataDb;
|
|
10
|
+
private store: plugins.smartdata.EasyStore<Record<string, any>>;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param mongoDescriptor MongoDB connection settings
|
|
14
|
+
*/
|
|
15
|
+
constructor(mongoDescriptor: plugins.smartdata.IMongoDescriptor) {
|
|
16
|
+
this.db = new plugins.smartdata.SmartdataDb(mongoDescriptor);
|
|
17
|
+
// Use a single EasyStore document to hold all certs keyed by domainName
|
|
18
|
+
this.store = new plugins.smartdata.EasyStore<Record<string, any>>(
|
|
19
|
+
'smartacme-certs',
|
|
20
|
+
this.db,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public async init(): Promise<void> {
|
|
25
|
+
await this.db.init();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public async retrieveCertificate(domainName: string): Promise<SmartacmeCert | null> {
|
|
29
|
+
const data = await this.store.readKey(domainName);
|
|
30
|
+
return data ? new SmartacmeCert(data) : null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public async storeCertificate(cert: SmartacmeCert): Promise<void> {
|
|
34
|
+
// write plain object for persistence
|
|
35
|
+
await this.store.writeKey(cert.domainName, { ...cert });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public async deleteCertificate(domainName: string): Promise<void> {
|
|
39
|
+
await this.store.deleteKey(domainName);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public async close(): Promise<void> {
|
|
43
|
+
await this.db.close();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Wipe all certificates from the persistent store (for integration testing)
|
|
47
|
+
*/
|
|
48
|
+
public async wipe(): Promise<void> {
|
|
49
|
+
// clear all keys in the easy store
|
|
50
|
+
await this.store.wipe();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -23,14 +23,6 @@ export class Dns01Handler implements IChallengeHandler<plugins.tsclass.network.I
|
|
|
23
23
|
public async prepare(ch: plugins.tsclass.network.IDnsChallenge): Promise<void> {
|
|
24
24
|
// set DNS TXT record
|
|
25
25
|
await this.cf.convenience.acmeSetDnsChallenge(ch);
|
|
26
|
-
// wait for DNS propagation
|
|
27
|
-
await this.smartdns.checkUntilAvailable(
|
|
28
|
-
ch.hostName,
|
|
29
|
-
'TXT',
|
|
30
|
-
ch.challenge,
|
|
31
|
-
100,
|
|
32
|
-
5000,
|
|
33
|
-
);
|
|
34
26
|
}
|
|
35
27
|
|
|
36
28
|
public async cleanup(ch: plugins.tsclass.network.IDnsChallenge): Promise<void> {
|
package/ts/index.ts
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { SmartacmeCert } from '../smartacme.classes.cert.js';
|
|
2
|
+
|
|
3
|
+
// (ICertRecord removed; use SmartacmeCert directly)
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Interface for certificate storage managers.
|
|
7
|
+
* Users can implement this to provide custom persistence (in-memory,
|
|
8
|
+
* file-based, Redis, etc.).
|
|
9
|
+
*/
|
|
10
|
+
export interface ICertManager {
|
|
11
|
+
/**
|
|
12
|
+
* Initialize the store (e.g., connect to database).
|
|
13
|
+
*/
|
|
14
|
+
init(): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Retrieve a certificate record by domain name.
|
|
17
|
+
* Returns null if none found.
|
|
18
|
+
*/
|
|
19
|
+
retrieveCertificate(domainName: string): Promise<SmartacmeCert | null>;
|
|
20
|
+
/**
|
|
21
|
+
* Store a certificate record. Fulfills any pending interests.
|
|
22
|
+
*/
|
|
23
|
+
storeCertificate(cert: SmartacmeCert): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Delete a certificate record by domain name.
|
|
26
|
+
*/
|
|
27
|
+
deleteCertificate(domainName: string): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Close the store (e.g., disconnect database).
|
|
30
|
+
*/
|
|
31
|
+
close(): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Optional: wipe all stored certificates (e.g., for integration testing)
|
|
34
|
+
*/
|
|
35
|
+
wipe(): Promise<void>;
|
|
36
|
+
}
|
|
@@ -1,64 +1,39 @@
|
|
|
1
1
|
import * as plugins from './smartacme.plugins.js';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { Collection, svDb, unI } from '@push.rocks/smartdata';
|
|
8
|
-
|
|
9
|
-
@plugins.smartdata.Collection(() => {
|
|
10
|
-
return SmartacmeCertManager.activeDB;
|
|
11
|
-
})
|
|
12
|
-
export class SmartacmeCert
|
|
13
|
-
extends plugins.smartdata.SmartDataDbDoc<SmartacmeCert, plugins.tsclass.network.ICert>
|
|
14
|
-
implements plugins.tsclass.network.ICert
|
|
15
|
-
{
|
|
16
|
-
@unI()
|
|
3
|
+
/**
|
|
4
|
+
* Plain certificate record.
|
|
5
|
+
*/
|
|
6
|
+
export class SmartacmeCert {
|
|
17
7
|
public id: string;
|
|
18
|
-
|
|
19
|
-
@svDb()
|
|
20
8
|
public domainName: string;
|
|
21
|
-
|
|
22
|
-
@svDb()
|
|
23
9
|
public created: number;
|
|
24
|
-
|
|
25
|
-
@svDb()
|
|
26
10
|
public privateKey: string;
|
|
27
|
-
|
|
28
|
-
@svDb()
|
|
29
11
|
public publicKey: string;
|
|
30
|
-
|
|
31
|
-
@svDb()
|
|
32
12
|
public csr: string;
|
|
33
|
-
|
|
34
|
-
@svDb()
|
|
35
13
|
public validUntil: number;
|
|
36
14
|
|
|
15
|
+
constructor(data: Partial<SmartacmeCert> = {}) {
|
|
16
|
+
this.id = data.id || '';
|
|
17
|
+
this.domainName = data.domainName || '';
|
|
18
|
+
this.created = data.created || Date.now();
|
|
19
|
+
this.privateKey = data.privateKey || '';
|
|
20
|
+
this.publicKey = data.publicKey || '';
|
|
21
|
+
this.csr = data.csr || '';
|
|
22
|
+
this.validUntil = data.validUntil || 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Check if certificate is still valid.
|
|
27
|
+
*/
|
|
37
28
|
public isStillValid(): boolean {
|
|
38
29
|
return this.validUntil >= Date.now();
|
|
39
30
|
}
|
|
40
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Check if certificate needs renewal (e.g., expires in <10 days).
|
|
34
|
+
*/
|
|
41
35
|
public shouldBeRenewed(): boolean {
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
plugins.smarttime.getMilliSecondsFromUnits({
|
|
45
|
-
days: 10,
|
|
46
|
-
});
|
|
47
|
-
return !(this.validUntil >= shouldBeValidAtLeastUntil);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
public update(certDataArg: plugins.tsclass.network.ICert) {
|
|
51
|
-
Object.keys(certDataArg).forEach((key) => {
|
|
52
|
-
this[key] = certDataArg[key];
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
constructor(optionsArg: plugins.tsclass.network.ICert) {
|
|
57
|
-
super();
|
|
58
|
-
if (optionsArg) {
|
|
59
|
-
Object.keys(optionsArg).forEach((key) => {
|
|
60
|
-
this[key] = optionsArg[key];
|
|
61
|
-
});
|
|
62
|
-
}
|
|
36
|
+
const threshold = Date.now() + plugins.smarttime.getMilliSecondsFromUnits({ days: 10 });
|
|
37
|
+
return this.validUntil < threshold;
|
|
63
38
|
}
|
|
64
39
|
}
|