fix(acme): parse issued certificate expiry from X.509 metadata and update build compatibility for dependency upgrades
This commit is contained in:
45
readme.md
45
readme.md
@@ -93,7 +93,7 @@ const certWithWildcard = await smartAcme.getCertificateForDomain('example.com',
|
||||
const wildcardCert = await smartAcme.getCertificateForDomain('*.example.com');
|
||||
```
|
||||
|
||||
Certificates are automatically cached and reused when still valid. Renewal happens automatically when a certificate is within 10 days of expiration.
|
||||
Certificates are automatically cached and reused when still valid. Renewal happens automatically when a certificate is within 10 days of expiration. The actual X.509 expiry date is parsed from the issued certificate, ensuring renewal timing is precise.
|
||||
|
||||
### 📦 Certificate Object
|
||||
|
||||
@@ -372,7 +372,7 @@ await smartAcme.stop();
|
||||
server.close();
|
||||
```
|
||||
|
||||
## ACME Directory Server (Built-in CA)
|
||||
## 🏗️ ACME Directory Server (Built-in CA)
|
||||
|
||||
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.
|
||||
|
||||
@@ -414,36 +414,39 @@ interface IAcmeServerOptions {
|
||||
}
|
||||
```
|
||||
|
||||
### Using the Server with SmartAcme Client
|
||||
### Using the Server with the Low-Level ACME Client
|
||||
|
||||
Point the SmartAcme client at your own ACME server for a fully self-contained PKI:
|
||||
The `SmartAcme` class connects to Let's Encrypt by default. To use a custom ACME directory (like your own server), use the lower-level `AcmeClient` directly:
|
||||
|
||||
```typescript
|
||||
import { SmartAcme, certmanagers, handlers, server } from '@push.rocks/smartacme';
|
||||
import { server } from '@push.rocks/smartacme';
|
||||
import { AcmeCrypto, AcmeClient } from '@push.rocks/smartacme/ts/acme/index.js';
|
||||
|
||||
// 1. Start your own CA
|
||||
const acmeServer = new server.AcmeServer({
|
||||
port: 14000,
|
||||
challengeVerification: false,
|
||||
challengeVerification: false, // auto-approve for testing
|
||||
});
|
||||
await acmeServer.start();
|
||||
|
||||
// 2. Set up the client pointing at your CA
|
||||
const memHandler = new handlers.Http01MemoryHandler();
|
||||
const smartAcme = new SmartAcme({
|
||||
accountEmail: 'admin@internal.example.com',
|
||||
certManager: new certmanagers.MemoryCertManager(),
|
||||
environment: 'integration',
|
||||
challengeHandlers: [memHandler],
|
||||
directoryUrl: acmeServer.getDirectoryUrl(), // Use your own CA!
|
||||
// 2. Create an ACME client pointing at your CA
|
||||
const accountKey = AcmeCrypto.createRsaPrivateKey();
|
||||
const client = new AcmeClient({
|
||||
directoryUrl: acmeServer.getDirectoryUrl(),
|
||||
accountKeyPem: accountKey,
|
||||
});
|
||||
|
||||
await smartAcme.start();
|
||||
const cert = await smartAcme.getCertificateForDomain('myapp.internal');
|
||||
// cert.publicKey — PEM certificate chain signed by your CA
|
||||
// cert.privateKey — PEM private key
|
||||
// 3. Register an account
|
||||
await client.createAccount({ termsOfServiceAgreed: true, contact: ['mailto:admin@internal.example.com'] });
|
||||
|
||||
// 4. Create an order and issue a certificate
|
||||
const order = await client.createOrder({
|
||||
identifiers: [{ type: 'dns', value: 'myapp.internal' }],
|
||||
});
|
||||
|
||||
// ... complete challenges, finalize, and download cert
|
||||
// (challenges auto-approved since challengeVerification is false)
|
||||
|
||||
await smartAcme.stop();
|
||||
await acmeServer.stop();
|
||||
```
|
||||
|
||||
@@ -477,7 +480,7 @@ fs.writeFileSync('/usr/local/share/ca-certificates/my-ca.crt', acmeServer.getCaC
|
||||
// Then: sudo update-ca-certificates
|
||||
```
|
||||
|
||||
## Architecture
|
||||
## 🏛️ Architecture
|
||||
|
||||
Under the hood, SmartAcme uses a fully custom RFC 8555-compliant ACME protocol implementation (no external ACME libraries). Key internal modules:
|
||||
|
||||
@@ -510,7 +513,7 @@ All cryptographic operations use `node:crypto`. The only external crypto depende
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.
|
||||
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [license](./license.md) file.
|
||||
|
||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user