@push.rocks/smartacme 9.2.0 → 9.3.0
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 +3 -3
- package/package.json +8 -3
- package/readme.hints.md +25 -1
- package/readme.md +122 -2
- package/ts/00_commitinfo_data.ts +2 -2
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartacme',
|
|
6
|
-
version: '9.
|
|
7
|
-
description: 'A TypeScript-based ACME client for
|
|
6
|
+
version: '9.3.0',
|
|
7
|
+
description: 'A TypeScript-based ACME client and server for certificate management with built-in CA, supporting LetsEncrypt and custom ACME authorities.'
|
|
8
8
|
};
|
|
9
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
9
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx1QkFBdUI7SUFDN0IsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDRJQUE0STtDQUMxSixDQUFBIn0=
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartacme",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.3.0",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "A TypeScript-based ACME client for
|
|
5
|
+
"description": "A TypeScript-based ACME client and server for certificate management with built-in CA, supporting LetsEncrypt and custom ACME authorities.",
|
|
6
6
|
"main": "dist_ts/index.js",
|
|
7
7
|
"typings": "dist_ts/index.d.ts",
|
|
8
8
|
"type": "module",
|
|
@@ -20,6 +20,9 @@
|
|
|
20
20
|
"LetsEncrypt",
|
|
21
21
|
"TypeScript",
|
|
22
22
|
"certificate management",
|
|
23
|
+
"certificate authority",
|
|
24
|
+
"ACME server",
|
|
25
|
+
"PKI",
|
|
23
26
|
"DNS challenges",
|
|
24
27
|
"SSL/TLS",
|
|
25
28
|
"secure communication",
|
|
@@ -28,9 +31,11 @@
|
|
|
28
31
|
"crypto",
|
|
29
32
|
"MongoDB",
|
|
30
33
|
"dns-01 challenge",
|
|
34
|
+
"http-01 challenge",
|
|
31
35
|
"token-based challenges",
|
|
32
36
|
"certificate renewal",
|
|
33
|
-
"wildcard certificates"
|
|
37
|
+
"wildcard certificates",
|
|
38
|
+
"RFC 8555"
|
|
34
39
|
],
|
|
35
40
|
"author": "Task Venture Capital GmbH",
|
|
36
41
|
"license": "MIT",
|
package/readme.hints.md
CHANGED
|
@@ -43,10 +43,34 @@ Key implementation details:
|
|
|
43
43
|
- `TaskManager.start()` is called in `SmartAcme.start()` and `TaskManager.stop()` in `SmartAcme.stop()`.
|
|
44
44
|
- The "no cronjobs specified" log messages during tests come from taskbuffer's internal CronManager polling — harmless noise when no cron tasks are scheduled.
|
|
45
45
|
|
|
46
|
+
## ACME Directory Server (ts_server/)
|
|
47
|
+
|
|
48
|
+
As of v9.2.0, a built-in ACME Directory Server lives under `ts_server/`. This is a full RFC 8555-compliant CA server that allows running your own Certificate Authority.
|
|
49
|
+
|
|
50
|
+
Key files:
|
|
51
|
+
- `ts_server/server.classes.acmeserver.ts` — Top-level `AcmeServer` facade (start/stop/config)
|
|
52
|
+
- `ts_server/server.classes.ca.ts` — Self-signed root CA generation + certificate signing via `@peculiar/x509`
|
|
53
|
+
- `ts_server/server.classes.jws.verifier.ts` — JWS signature verification (inverse of `AcmeCrypto.createJws`)
|
|
54
|
+
- `ts_server/server.classes.router.ts` — Minimal HTTP router with `:param` support using raw `node:http`
|
|
55
|
+
- `ts_server/server.classes.nonce.ts` — Single-use replay nonce management
|
|
56
|
+
- `ts_server/server.classes.challenge.verifier.ts` — HTTP-01/DNS-01 verification (with bypass mode)
|
|
57
|
+
- `ts_server/server.classes.account.store.ts` — In-memory account storage
|
|
58
|
+
- `ts_server/server.classes.order.store.ts` — In-memory order/authz/challenge/cert storage
|
|
59
|
+
- `ts_server/server.handlers.*.ts` — Route handlers for each ACME endpoint
|
|
60
|
+
|
|
61
|
+
Design decisions:
|
|
62
|
+
- Uses raw `node:http` (no framework dependency — `@api.global/typedserver` was explicitly removed in v8.1.0)
|
|
63
|
+
- Zero new dependencies: uses `node:crypto`, `@peculiar/x509`, and existing project deps
|
|
64
|
+
- Reuses `AcmeCrypto` for JWK thumbprint/base64url, ACME interfaces for response types, `AcmeError` patterns
|
|
65
|
+
- `AcmeCrypto.getAlg()` was made public (was private) for use by the JWS verifier
|
|
66
|
+
- Storage interfaces (`IServerAccountStore`, `IServerOrderStore`) are pluggable, with in-memory defaults
|
|
67
|
+
- `challengeVerification: false` option auto-approves challenges for testing
|
|
68
|
+
- `tsbuild tsfolders` automatically compiles `ts_server/` to `dist_ts_server/`
|
|
69
|
+
|
|
46
70
|
## Dependency Notes
|
|
47
71
|
|
|
48
72
|
- `acme-client` was replaced with custom implementation in `ts/acme/` + `@peculiar/x509` for CSR generation
|
|
49
73
|
- `@push.rocks/smartfile`, `@api.global/typedserver`, `@push.rocks/smartrequest`, `@push.rocks/smartpromise` were removed as unused dependencies in v8.1.0
|
|
50
74
|
- The `@apiclient.xyz/cloudflare` `convenience` namespace is deprecated but still functional. The `Dns01Handler` accepts an `IConvenientDnsProvider` interface which remains stable.
|
|
51
75
|
- Test imports use `@git.zone/tstest/tapbundle` (not `@push.rocks/tapbundle`)
|
|
52
|
-
- Build uses `tsbuild` (
|
|
76
|
+
- Build uses `tsbuild tsfolders` (v4.3.0+) — auto-discovers and compiles `ts/` and `ts_server/` directories
|
package/readme.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @push.rocks/smartacme
|
|
2
2
|
|
|
3
|
-
A TypeScript-based ACME client
|
|
3
|
+
A TypeScript-based ACME client and server for certificate management with a focus on simplicity and power. Includes a full RFC 8555-compliant ACME client for Let's Encrypt and a built-in ACME Directory Server for running your own Certificate Authority.
|
|
4
4
|
|
|
5
5
|
## Issue Reporting and Security
|
|
6
6
|
|
|
@@ -372,10 +372,117 @@ await smartAcme.stop();
|
|
|
372
372
|
server.close();
|
|
373
373
|
```
|
|
374
374
|
|
|
375
|
+
## ACME Directory Server (Built-in CA)
|
|
376
|
+
|
|
377
|
+
SmartAcme includes a full RFC 8555-compliant ACME Directory Server, allowing you to run your own Certificate Authority. This is useful for internal PKI, development/testing environments, and air-gapped networks.
|
|
378
|
+
|
|
379
|
+
### Quick Start — ACME Server
|
|
380
|
+
|
|
381
|
+
```typescript
|
|
382
|
+
import { server } from '@push.rocks/smartacme';
|
|
383
|
+
|
|
384
|
+
const acmeServer = new server.AcmeServer({
|
|
385
|
+
port: 14000,
|
|
386
|
+
challengeVerification: false, // Auto-approve challenges (for testing)
|
|
387
|
+
caOptions: {
|
|
388
|
+
commonName: 'My Internal CA',
|
|
389
|
+
certValidityDays: 365,
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
await acmeServer.start();
|
|
394
|
+
console.log(acmeServer.getDirectoryUrl()); // http://localhost:14000/directory
|
|
395
|
+
console.log(acmeServer.getCaCertPem()); // Root CA certificate in PEM format
|
|
396
|
+
|
|
397
|
+
// ... use it, then shut down
|
|
398
|
+
await acmeServer.stop();
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Server Options
|
|
402
|
+
|
|
403
|
+
```typescript
|
|
404
|
+
interface IAcmeServerOptions {
|
|
405
|
+
port?: number; // Default: 14000
|
|
406
|
+
hostname?: string; // Default: '0.0.0.0'
|
|
407
|
+
baseUrl?: string; // Auto-built from hostname:port if not provided
|
|
408
|
+
challengeVerification?: boolean; // Default: true. Set false to auto-approve challenges
|
|
409
|
+
caOptions?: {
|
|
410
|
+
commonName?: string; // CA subject CN (default: 'SmartACME Test CA')
|
|
411
|
+
validityDays?: number; // Root cert validity in days (default: 3650)
|
|
412
|
+
certValidityDays?: number; // Issued cert validity in days (default: 90)
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Using the Server with SmartAcme Client
|
|
418
|
+
|
|
419
|
+
Point the SmartAcme client at your own ACME server for a fully self-contained PKI:
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
import { SmartAcme, certmanagers, handlers, server } from '@push.rocks/smartacme';
|
|
423
|
+
|
|
424
|
+
// 1. Start your own CA
|
|
425
|
+
const acmeServer = new server.AcmeServer({
|
|
426
|
+
port: 14000,
|
|
427
|
+
challengeVerification: false,
|
|
428
|
+
});
|
|
429
|
+
await acmeServer.start();
|
|
430
|
+
|
|
431
|
+
// 2. Set up the client pointing at your CA
|
|
432
|
+
const memHandler = new handlers.Http01MemoryHandler();
|
|
433
|
+
const smartAcme = new SmartAcme({
|
|
434
|
+
accountEmail: 'admin@internal.example.com',
|
|
435
|
+
certManager: new certmanagers.MemoryCertManager(),
|
|
436
|
+
environment: 'integration',
|
|
437
|
+
challengeHandlers: [memHandler],
|
|
438
|
+
directoryUrl: acmeServer.getDirectoryUrl(), // Use your own CA!
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
await smartAcme.start();
|
|
442
|
+
const cert = await smartAcme.getCertificateForDomain('myapp.internal');
|
|
443
|
+
// cert.publicKey — PEM certificate chain signed by your CA
|
|
444
|
+
// cert.privateKey — PEM private key
|
|
445
|
+
|
|
446
|
+
await smartAcme.stop();
|
|
447
|
+
await acmeServer.stop();
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### Server Endpoints
|
|
451
|
+
|
|
452
|
+
The ACME server implements all RFC 8555 endpoints:
|
|
453
|
+
|
|
454
|
+
| Endpoint | Method | Description |
|
|
455
|
+
|----------|--------|-------------|
|
|
456
|
+
| `/directory` | GET | ACME directory with all endpoint URLs |
|
|
457
|
+
| `/new-nonce` | HEAD/GET | Fresh replay nonce |
|
|
458
|
+
| `/new-account` | POST | Account registration/lookup |
|
|
459
|
+
| `/new-order` | POST | Create certificate order |
|
|
460
|
+
| `/order/:id` | POST | Poll order status |
|
|
461
|
+
| `/authz/:id` | POST | Get authorization with challenges |
|
|
462
|
+
| `/challenge/:id` | POST | Trigger or poll challenge validation |
|
|
463
|
+
| `/finalize/:id` | POST | Submit CSR and issue certificate |
|
|
464
|
+
| `/cert/:id` | POST | Download PEM certificate chain |
|
|
465
|
+
|
|
466
|
+
### Challenge Verification
|
|
467
|
+
|
|
468
|
+
By default, the server performs real challenge verification (HTTP-01 fetches the token, DNS-01 queries TXT records). Set `challengeVerification: false` to auto-approve all challenges — useful for testing or internal environments where domain validation isn't needed.
|
|
469
|
+
|
|
470
|
+
### Root CA Certificate
|
|
471
|
+
|
|
472
|
+
Use `getCaCertPem()` to retrieve the root CA certificate for trust configuration:
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
import * as fs from 'fs';
|
|
476
|
+
fs.writeFileSync('/usr/local/share/ca-certificates/my-ca.crt', acmeServer.getCaCertPem());
|
|
477
|
+
// Then: sudo update-ca-certificates
|
|
478
|
+
```
|
|
479
|
+
|
|
375
480
|
## Architecture
|
|
376
481
|
|
|
377
482
|
Under the hood, SmartAcme uses a fully custom RFC 8555-compliant ACME protocol implementation (no external ACME libraries). Key internal modules:
|
|
378
483
|
|
|
484
|
+
### Client Modules (`ts/acme/`)
|
|
485
|
+
|
|
379
486
|
| Module | Purpose |
|
|
380
487
|
|--------|---------|
|
|
381
488
|
| `AcmeClient` | Top-level ACME facade — orders, authorizations, finalization |
|
|
@@ -386,7 +493,20 @@ Under the hood, SmartAcme uses a fully custom RFC 8555-compliant ACME protocol i
|
|
|
386
493
|
| `AcmeChallengeManager` | Key authorization computation and challenge completion |
|
|
387
494
|
| `TaskManager` | Constraint-based concurrency control, rate limiting, and request deduplication via `@push.rocks/taskbuffer` |
|
|
388
495
|
|
|
389
|
-
|
|
496
|
+
### Server Modules (`ts_server/`)
|
|
497
|
+
|
|
498
|
+
| Module | Purpose |
|
|
499
|
+
|--------|---------|
|
|
500
|
+
| `AcmeServer` | Top-level server facade — start, stop, configuration |
|
|
501
|
+
| `AcmeServerCA` | Self-signed root CA generation and certificate signing via `@peculiar/x509` |
|
|
502
|
+
| `JwsVerifier` | JWS signature verification (inverse of `AcmeCrypto.createJws`) |
|
|
503
|
+
| `NonceManager` | Single-use replay nonce generation and validation |
|
|
504
|
+
| `ChallengeVerifier` | HTTP-01 and DNS-01 challenge verification (with bypass mode) |
|
|
505
|
+
| `AcmeRouter` | Minimal HTTP router with parameterized path support |
|
|
506
|
+
| `MemoryAccountStore` | In-memory ACME account storage |
|
|
507
|
+
| `MemoryOrderStore` | In-memory order, authorization, challenge, and certificate storage |
|
|
508
|
+
|
|
509
|
+
All cryptographic operations use `node:crypto`. The only external crypto dependency is `@peculiar/x509` for CSR generation and certificate signing.
|
|
390
510
|
|
|
391
511
|
## License and Legal Information
|
|
392
512
|
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartacme',
|
|
6
|
-
version: '9.
|
|
7
|
-
description: 'A TypeScript-based ACME client for
|
|
6
|
+
version: '9.3.0',
|
|
7
|
+
description: 'A TypeScript-based ACME client and server for certificate management with built-in CA, supporting LetsEncrypt and custom ACME authorities.'
|
|
8
8
|
}
|