@push.rocks/smartacme 7.2.1 → 7.2.3
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/package.json +1 -1
- package/readme.md +97 -82
- package/ts/00_commitinfo_data.ts +1 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartacme',
|
|
6
|
-
version: '7.2.
|
|
6
|
+
version: '7.2.3',
|
|
7
7
|
description: 'A TypeScript-based ACME client for LetsEncrypt certificate management with a focus on simplicity and power.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx1QkFBdUI7SUFDN0IsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDZHQUE2RztDQUMzSCxDQUFBIn0=
|
package/package.json
CHANGED
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,64 @@ 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
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
SmartAcme uses the `ICertManager` interface for certificate storage. Two built-in implementations are available:
|
|
117
|
+
|
|
118
|
+
- **MemoryCertManager**
|
|
119
|
+
- In-memory storage, suitable for testing or ephemeral use.
|
|
120
|
+
- Import example:
|
|
121
|
+
```typescript
|
|
122
|
+
import { MemoryCertManager } from '@push.rocks/smartacme';
|
|
123
|
+
const certManager = new MemoryCertManager();
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- **MongoCertManager**
|
|
127
|
+
- Persistent storage in MongoDB (collection: `SmartacmeCert`).
|
|
128
|
+
- Import example:
|
|
129
|
+
```typescript
|
|
130
|
+
import { MongoCertManager } from '@push.rocks/smartacme';
|
|
131
|
+
const certManager = new MongoCertManager({
|
|
132
|
+
mongoDbUrl: 'mongodb://yourmongoURL',
|
|
133
|
+
mongoDbName: 'yourDbName',
|
|
134
|
+
mongoDbPass: 'yourDbPassword',
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### Custom Certificate Managers
|
|
139
|
+
|
|
140
|
+
To implement a custom certificate manager, implement the `ICertManager` interface and pass it to `SmartAcme`:
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
import type { ICertManager, Cert as SmartacmeCert } from '@push.rocks/smartacme';
|
|
144
|
+
import { SmartAcme } from '@push.rocks/smartacme';
|
|
145
|
+
|
|
146
|
+
class MyCustomCertManager implements ICertManager {
|
|
147
|
+
async init(): Promise<void> { /* setup storage */ }
|
|
148
|
+
async get(domainName: string): Promise<SmartacmeCert | null> { /* lookup cert */ }
|
|
149
|
+
async put(cert: SmartacmeCert): Promise<SmartacmeCert> { /* store cert */ }
|
|
150
|
+
async delete(domainName: string): Promise<void> { /* remove cert */ }
|
|
151
|
+
async close?(): Promise<void> { /* optional cleanup */ }
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Use your custom manager:
|
|
155
|
+
const customManager = new MyCustomCertManager();
|
|
156
|
+
const smartAcme = new SmartAcme({
|
|
157
|
+
accountEmail: 'youremail@example.com',
|
|
158
|
+
certManager: customManager,
|
|
159
|
+
environment: 'integration',
|
|
160
|
+
challengeHandlers: [], // add your handlers
|
|
161
|
+
});
|
|
102
162
|
```
|
|
103
163
|
|
|
104
164
|
### Environmental Considerations
|
|
@@ -110,23 +170,27 @@ When creating an instance of `SmartAcme`, you can specify an `environment` optio
|
|
|
110
170
|
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
171
|
|
|
112
172
|
```typescript
|
|
113
|
-
import { SmartAcme } from '@push.rocks/smartacme';
|
|
173
|
+
import { SmartAcme, MongoCertManager } from '@push.rocks/smartacme';
|
|
114
174
|
import * as cloudflare from '@apiclient.xyz/cloudflare';
|
|
115
175
|
import { Qenv } from '@push.rocks/qenv';
|
|
176
|
+
import { Dns01Handler } from '@push.rocks/smartacme/ts/handlers/Dns01Handler.js';
|
|
116
177
|
|
|
117
178
|
const qenv = new Qenv('./', './.nogit/');
|
|
118
179
|
const cloudflareAccount = new cloudflare.CloudflareAccount(qenv.getEnvVarOnDemand('CF_TOKEN'));
|
|
119
180
|
|
|
120
181
|
async function main() {
|
|
182
|
+
// Initialize MongoDB certificate manager
|
|
183
|
+
const certManager = new MongoCertManager({
|
|
184
|
+
mongoDbUrl: qenv.getEnvVarRequired('MONGODB_URL'),
|
|
185
|
+
mongoDbName: qenv.getEnvVarRequired('MONGODB_DATABASE'),
|
|
186
|
+
mongoDbPass: qenv.getEnvVarRequired('MONGODB_PASSWORD'),
|
|
187
|
+
});
|
|
188
|
+
|
|
121
189
|
const smartAcmeInstance = new SmartAcme({
|
|
122
190
|
accountEmail: 'youremail@example.com',
|
|
123
|
-
|
|
124
|
-
mongoDbUrl: qenv.getEnvVarRequired('MONGODB_URL'),
|
|
125
|
-
mongoDbName: qenv.getEnvVarRequired('MONGODB_DATABASE'),
|
|
126
|
-
mongoDbPass: qenv.getEnvVarRequired('MONGODB_PASSWORD'),
|
|
127
|
-
},
|
|
191
|
+
certManager,
|
|
128
192
|
environment: 'integration',
|
|
129
|
-
challengeHandlers: [
|
|
193
|
+
challengeHandlers: [new Dns01Handler(cloudflareAccount)],
|
|
130
194
|
});
|
|
131
195
|
|
|
132
196
|
await smartAcmeInstance.start();
|
|
@@ -138,8 +202,8 @@ async function main() {
|
|
|
138
202
|
await smartAcmeInstance.stop();
|
|
139
203
|
}
|
|
140
204
|
|
|
141
|
-
|
|
142
|
-
|
|
205
|
+
main().catch(console.error);
|
|
206
|
+
```
|
|
143
207
|
|
|
144
208
|
## Built-in Challenge Handlers
|
|
145
209
|
|
|
@@ -222,7 +286,7 @@ async function main() {
|
|
|
222
286
|
challengePriority: ['my-01'],
|
|
223
287
|
});
|
|
224
288
|
|
|
225
|
-
In this example, `Qenv` is used to manage environment variables, and
|
|
289
|
+
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
290
|
|
|
227
291
|
## Additional Details
|
|
228
292
|
|
|
@@ -243,8 +307,6 @@ The certificate object obtained from the `getCertificateForDomain` method has th
|
|
|
243
307
|
- **start()**: Initializes the SmartAcme instance, sets up the ACME client, and registers the account with Let's Encrypt.
|
|
244
308
|
- **stop()**: Closes the MongoDB connection and performs any necessary cleanup.
|
|
245
309
|
- **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
310
|
|
|
249
311
|
### Handling Domain Matching
|
|
250
312
|
|
|
@@ -260,60 +322,13 @@ console.log('Certificate Domain Name:', certDomainName); // Output: example.com
|
|
|
260
322
|
|
|
261
323
|
### Testing
|
|
262
324
|
|
|
263
|
-
|
|
325
|
+
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
326
|
|
|
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();
|
|
327
|
+
```bash
|
|
328
|
+
pnpm test
|
|
315
329
|
```
|
|
316
330
|
|
|
331
|
+
|
|
317
332
|
This comprehensive guide ensures you can set up, manage, and test ACME certificates efficiently and effectively using `@push.rocks/smartacme`.
|
|
318
333
|
|
|
319
334
|
---
|
package/ts/00_commitinfo_data.ts
CHANGED