@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.
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartacme',
6
- version: '7.2.1',
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@push.rocks/smartacme",
3
- "version": "7.2.1",
3
+ "version": "7.2.3",
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",
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
- To install `@push.rocks/smartacme`, you can use npm or yarn. Run one of the following commands in your project directory:
7
+ Using pnpm as the package manager:
8
8
 
9
9
  ```bash
10
- npm install @push.rocks/smartacme --save
10
+ pnpm add @push.rocks/smartacme
11
11
  ```
12
12
 
13
- or
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
- yarn add @push.rocks/smartacme
19
+ pnpm test
17
20
  ```
18
21
 
19
- Make sure your project is set up to use TypeScript and supports ECMAScript Modules (ESM).
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
- // Instantiate SmartAcme with one or more ACME challenge handlers
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
- mongoDescriptor: {
56
- mongoDbUrl: 'mongodb://yourmongoURL',
57
- mongoDbName: 'yourDbName',
58
- mongoDbPass: 'yourDbPassword',
59
- },
69
+ certManager,
60
70
  environment: 'integration', // 'production' to request real certificates
61
- retryOptions: {}, // optional retry/backoff settings
62
- challengeHandlers: [
71
+ retryOptions: {}, // optional retry/backoff settings
72
+ challengeHandlers: [ // pluggable ACME challenge handlers
63
73
  new Dns01Handler(cfAccount),
64
- // you can add more handlers, e.g. Http01Webroot
74
+ // add more handlers as needed (e.g., Http01Webroot, Http01MemoryHandler)
65
75
  ],
66
- challengePriority: ['dns-01'], // optional ordering of challenge types
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 in your configuration. Ensure your MongoDB instance is accessible and properly configured for use with SmartAcme.
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
- const mongoDescriptor = {
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
- mongoDescriptor: {
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: [ new Dns01Handler(cloudflareAccount) ],
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
- main().catch(console.error);
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 `cloudflare` library is used to handle DNS challenges required by Let's Encrypt ACME protocol. The `setChallenge` and `removeChallenge` methods are essential for automating the DNS challenge process, which is a key part of domain validation.
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
- Automated tests can be added to ensure that the setup and functions work as expected. Using a testing framework such as `tap` and mock services for DNS providers (e.g., Cloudflare), you can simulate the process of obtaining and managing certificates without the need for actual domain ownership.
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
- ```typescript
266
- import { tap, expect } from '@push.rocks/tapbundle';
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
  ---
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartacme',
6
- version: '7.2.1',
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
  }