@push.rocks/smartacme 6.2.0 → 7.2.2
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.md +49 -82
- 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.2",
|
|
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.md
CHANGED
|
@@ -4,19 +4,26 @@ A TypeScript-based ACME client with an easy yet powerful interface for LetsEncry
|
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Using pnpm as the package manager:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
10
|
+
pnpm add @push.rocks/smartacme
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Ensure your project is set up to use TypeScript and ECMAScript Modules (ESM).
|
|
14
|
+
## Running Tests
|
|
15
|
+
|
|
16
|
+
Tests are written using `@push.rocks/tapbundle` and can be run with:
|
|
14
17
|
|
|
15
18
|
```bash
|
|
16
|
-
|
|
19
|
+
pnpm test
|
|
17
20
|
```
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
To run a specific test file:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
tsx test/<test-file>.ts
|
|
26
|
+
```
|
|
20
27
|
|
|
21
28
|
## Usage
|
|
22
29
|
|
|
@@ -42,28 +49,31 @@ Ensure your project includes the necessary TypeScript configuration and dependen
|
|
|
42
49
|
Start by importing the `SmartAcme` class and any built-in handlers you plan to use. For example, to use DNS-01 via Cloudflare:
|
|
43
50
|
|
|
44
51
|
```typescript
|
|
45
|
-
import { SmartAcme } from '@push.rocks/smartacme';
|
|
52
|
+
import { SmartAcme, MongoCertManager } from '@push.rocks/smartacme';
|
|
46
53
|
import * as cloudflare from '@apiclient.xyz/cloudflare';
|
|
47
54
|
import { Dns01Handler } from '@push.rocks/smartacme/ts/handlers/Dns01Handler.js';
|
|
48
55
|
|
|
49
56
|
// Create a Cloudflare account client with your API token
|
|
50
57
|
const cfAccount = new cloudflare.CloudflareAccount('YOUR_CF_TOKEN');
|
|
51
58
|
|
|
52
|
-
//
|
|
59
|
+
// Initialize a certificate manager (e.g., MongoDB)
|
|
60
|
+
const certManager = new MongoCertManager({
|
|
61
|
+
mongoDbUrl: 'mongodb://yourmongoURL',
|
|
62
|
+
mongoDbName: 'yourDbName',
|
|
63
|
+
mongoDbPass: 'yourDbPassword',
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Instantiate SmartAcme with the certManager and challenge handlers
|
|
53
67
|
const smartAcmeInstance = new SmartAcme({
|
|
54
68
|
accountEmail: 'youremail@example.com',
|
|
55
|
-
|
|
56
|
-
mongoDbUrl: 'mongodb://yourmongoURL',
|
|
57
|
-
mongoDbName: 'yourDbName',
|
|
58
|
-
mongoDbPass: 'yourDbPassword',
|
|
59
|
-
},
|
|
69
|
+
certManager,
|
|
60
70
|
environment: 'integration', // 'production' to request real certificates
|
|
61
|
-
retryOptions: {},
|
|
62
|
-
challengeHandlers: [
|
|
71
|
+
retryOptions: {}, // optional retry/backoff settings
|
|
72
|
+
challengeHandlers: [ // pluggable ACME challenge handlers
|
|
63
73
|
new Dns01Handler(cfAccount),
|
|
64
|
-
//
|
|
74
|
+
// add more handlers as needed (e.g., Http01Webroot, Http01MemoryHandler)
|
|
65
75
|
],
|
|
66
|
-
challengePriority: ['dns-01'], // optional
|
|
76
|
+
challengePriority: ['dns-01'], // optional challenge ordering
|
|
67
77
|
});
|
|
68
78
|
```
|
|
69
79
|
|
|
@@ -91,14 +101,16 @@ SmartAcme uses pluggable ACME challenge handlers (see built-in handlers below) t
|
|
|
91
101
|
|
|
92
102
|
### Managing Certificates
|
|
93
103
|
|
|
94
|
-
The library automatically handles fetching, renewing, and storing your certificates in a MongoDB database specified
|
|
104
|
+
The library automatically handles fetching, renewing, and storing your certificates in a MongoDB database specified via a certificate manager. Ensure your MongoDB instance is accessible and properly configured for use with SmartAcme.
|
|
95
105
|
|
|
96
106
|
```typescript
|
|
97
|
-
|
|
107
|
+
import { MongoCertManager } from '@push.rocks/smartacme';
|
|
108
|
+
|
|
109
|
+
const certManager = new MongoCertManager({
|
|
98
110
|
mongoDbUrl: 'mongodb://yourmongoURL',
|
|
99
111
|
mongoDbName: 'yourDbName',
|
|
100
112
|
mongoDbPass: 'yourDbPassword',
|
|
101
|
-
};
|
|
113
|
+
});
|
|
102
114
|
```
|
|
103
115
|
|
|
104
116
|
### Environmental Considerations
|
|
@@ -110,23 +122,27 @@ When creating an instance of `SmartAcme`, you can specify an `environment` optio
|
|
|
110
122
|
Below is a complete example demonstrating how to use `@push.rocks/smartacme` to obtain and manage an ACME certificate with Let's Encrypt using a DNS-01 handler:
|
|
111
123
|
|
|
112
124
|
```typescript
|
|
113
|
-
import { SmartAcme } from '@push.rocks/smartacme';
|
|
125
|
+
import { SmartAcme, MongoCertManager } from '@push.rocks/smartacme';
|
|
114
126
|
import * as cloudflare from '@apiclient.xyz/cloudflare';
|
|
115
127
|
import { Qenv } from '@push.rocks/qenv';
|
|
128
|
+
import { Dns01Handler } from '@push.rocks/smartacme/ts/handlers/Dns01Handler.js';
|
|
116
129
|
|
|
117
130
|
const qenv = new Qenv('./', './.nogit/');
|
|
118
131
|
const cloudflareAccount = new cloudflare.CloudflareAccount(qenv.getEnvVarOnDemand('CF_TOKEN'));
|
|
119
132
|
|
|
120
133
|
async function main() {
|
|
134
|
+
// Initialize MongoDB certificate manager
|
|
135
|
+
const certManager = new MongoCertManager({
|
|
136
|
+
mongoDbUrl: qenv.getEnvVarRequired('MONGODB_URL'),
|
|
137
|
+
mongoDbName: qenv.getEnvVarRequired('MONGODB_DATABASE'),
|
|
138
|
+
mongoDbPass: qenv.getEnvVarRequired('MONGODB_PASSWORD'),
|
|
139
|
+
});
|
|
140
|
+
|
|
121
141
|
const smartAcmeInstance = new SmartAcme({
|
|
122
142
|
accountEmail: 'youremail@example.com',
|
|
123
|
-
|
|
124
|
-
mongoDbUrl: qenv.getEnvVarRequired('MONGODB_URL'),
|
|
125
|
-
mongoDbName: qenv.getEnvVarRequired('MONGODB_DATABASE'),
|
|
126
|
-
mongoDbPass: qenv.getEnvVarRequired('MONGODB_PASSWORD'),
|
|
127
|
-
},
|
|
143
|
+
certManager,
|
|
128
144
|
environment: 'integration',
|
|
129
|
-
challengeHandlers: [
|
|
145
|
+
challengeHandlers: [new Dns01Handler(cloudflareAccount)],
|
|
130
146
|
});
|
|
131
147
|
|
|
132
148
|
await smartAcmeInstance.start();
|
|
@@ -138,8 +154,8 @@ async function main() {
|
|
|
138
154
|
await smartAcmeInstance.stop();
|
|
139
155
|
}
|
|
140
156
|
|
|
141
|
-
|
|
142
|
-
|
|
157
|
+
main().catch(console.error);
|
|
158
|
+
```
|
|
143
159
|
|
|
144
160
|
## Built-in Challenge Handlers
|
|
145
161
|
|
|
@@ -222,7 +238,7 @@ async function main() {
|
|
|
222
238
|
challengePriority: ['my-01'],
|
|
223
239
|
});
|
|
224
240
|
|
|
225
|
-
In this example, `Qenv` is used to manage environment variables, and
|
|
241
|
+
In this example, `Qenv` is used to manage environment variables, and the Cloudflare library is used to handle DNS challenges through the built-in `Dns01Handler` plugin.
|
|
226
242
|
|
|
227
243
|
## Additional Details
|
|
228
244
|
|
|
@@ -243,8 +259,6 @@ The certificate object obtained from the `getCertificateForDomain` method has th
|
|
|
243
259
|
- **start()**: Initializes the SmartAcme instance, sets up the ACME client, and registers the account with Let's Encrypt.
|
|
244
260
|
- **stop()**: Closes the MongoDB connection and performs any necessary cleanup.
|
|
245
261
|
- **getCertificateForDomain(domainArg: string)**: Retrieves or obtains a certificate for the specified domain name. If a valid certificate exists in the database, it is returned. Otherwise, a new certificate is requested and stored.
|
|
246
|
-
- **setChallenge(dnsChallenge: any)**: Automates the process of setting DNS challenge records.
|
|
247
|
-
- **removeChallenge(dnsChallenge: any)**: Automates the process of removing DNS challenge records.
|
|
248
262
|
|
|
249
263
|
### Handling Domain Matching
|
|
250
264
|
|
|
@@ -260,60 +274,13 @@ console.log('Certificate Domain Name:', certDomainName); // Output: example.com
|
|
|
260
274
|
|
|
261
275
|
### Testing
|
|
262
276
|
|
|
263
|
-
|
|
277
|
+
Sample tests are provided in the `test` directory. They demonstrate core functionality using the `MemoryCertManager` and built-in challenge handlers. To run all tests, use:
|
|
264
278
|
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
import { Qenv } from '@push.rocks/qenv';
|
|
268
|
-
import * as cloudflare from '@apiclient.xyz/cloudflare';
|
|
269
|
-
import * as smartacme from '@push.rocks/smartacme';
|
|
270
|
-
|
|
271
|
-
const testQenv = new Qenv('./', './.nogit/');
|
|
272
|
-
const testCloudflare = new cloudflare.CloudflareAccount(testQenv.getEnvVarOnDemand('CF_TOKEN'));
|
|
273
|
-
|
|
274
|
-
let smartAcmeInstance: smartacme.SmartAcme;
|
|
275
|
-
|
|
276
|
-
tap.test('should create a valid instance of SmartAcme', async () => {
|
|
277
|
-
smartAcmeInstance = new smartacme.SmartAcme({
|
|
278
|
-
accountEmail: 'domains@lossless.org',
|
|
279
|
-
accountPrivateKey: null,
|
|
280
|
-
mongoDescriptor: {
|
|
281
|
-
mongoDbName: testQenv.getEnvVarRequired('MONGODB_DATABASE'),
|
|
282
|
-
mongoDbPass: testQenv.getEnvVarRequired('MONGODB_PASSWORD'),
|
|
283
|
-
mongoDbUrl: testQenv.getEnvVarRequired('MONGODB_URL'),
|
|
284
|
-
},
|
|
285
|
-
setChallenge: async (dnsChallenge) => {
|
|
286
|
-
await testCloudflare.convenience.acmeSetDnsChallenge(dnsChallenge);
|
|
287
|
-
},
|
|
288
|
-
removeChallenge: async (dnsChallenge) => {
|
|
289
|
-
await testCloudflare.convenience.acmeRemoveDnsChallenge(dnsChallenge);
|
|
290
|
-
},
|
|
291
|
-
environment: 'integration',
|
|
292
|
-
});
|
|
293
|
-
await smartAcmeInstance.init();
|
|
294
|
-
expect(smartAcmeInstance).toBeInstanceOf(smartacme.SmartAcme);
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
tap.test('should get a domain certificate', async () => {
|
|
298
|
-
const certificate = await smartAcmeInstance.getCertificateForDomain('example.com');
|
|
299
|
-
console.log('Certificate:', certificate);
|
|
300
|
-
expect(certificate).toHaveProperty('domainName', 'example.com');
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
tap.test('certmatcher should correctly match domains', async () => {
|
|
304
|
-
const certMatcher = new smartacme.SmartacmeCertMatcher();
|
|
305
|
-
const matchedCert = certMatcher.getCertificateDomainNameByDomainName('subdomain.example.com');
|
|
306
|
-
expect(matchedCert).toBe('example.com');
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
tap.test('should stop correctly', async () => {
|
|
310
|
-
await smartAcmeInstance.stop();
|
|
311
|
-
expect(smartAcmeInstance).toHaveProperty('client', null);
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
tap.start();
|
|
279
|
+
```bash
|
|
280
|
+
pnpm test
|
|
315
281
|
```
|
|
316
282
|
|
|
283
|
+
|
|
317
284
|
This comprehensive guide ensures you can set up, manage, and test ACME certificates efficiently and effectively using `@push.rocks/smartacme`.
|
|
318
285
|
|
|
319
286
|
---
|
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
|
+
}
|