@push.rocks/smartacme 7.3.4 → 9.0.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.
Files changed (50) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/acme/acme.classes.account.d.ts +20 -0
  3. package/dist_ts/acme/acme.classes.account.js +37 -0
  4. package/dist_ts/acme/acme.classes.challenge.d.ts +22 -0
  5. package/dist_ts/acme/acme.classes.challenge.js +36 -0
  6. package/dist_ts/acme/acme.classes.client.d.ts +68 -0
  7. package/dist_ts/acme/acme.classes.client.js +71 -0
  8. package/dist_ts/acme/acme.classes.crypto.d.ts +50 -0
  9. package/dist_ts/acme/acme.classes.crypto.js +180 -0
  10. package/dist_ts/acme/acme.classes.directory.d.ts +13 -0
  11. package/dist_ts/acme/acme.classes.directory.js +14 -0
  12. package/dist_ts/acme/acme.classes.error.d.ts +44 -0
  13. package/dist_ts/acme/acme.classes.error.js +41 -0
  14. package/dist_ts/acme/acme.classes.http-client.d.ts +36 -0
  15. package/dist_ts/acme/acme.classes.http-client.js +201 -0
  16. package/dist_ts/acme/acme.classes.order.d.ts +40 -0
  17. package/dist_ts/acme/acme.classes.order.js +100 -0
  18. package/dist_ts/acme/acme.interfaces.d.ts +64 -0
  19. package/dist_ts/acme/acme.interfaces.js +5 -0
  20. package/dist_ts/acme/index.d.ts +5 -0
  21. package/dist_ts/acme/index.js +5 -0
  22. package/dist_ts/certmanagers/mongo.js +1 -2
  23. package/dist_ts/plugins.d.ts +2 -7
  24. package/dist_ts/plugins.js +5 -11
  25. package/dist_ts/smartacme.classes.smartacme.d.ts +7 -2
  26. package/dist_ts/smartacme.classes.smartacme.js +80 -20
  27. package/npmextra.json +12 -6
  28. package/package.json +23 -24
  29. package/readme.hints.md +37 -2
  30. package/readme.md +201 -255
  31. package/ts/00_commitinfo_data.ts +1 -1
  32. package/ts/acme/acme.classes.account.ts +45 -0
  33. package/ts/acme/acme.classes.challenge.ts +45 -0
  34. package/ts/acme/acme.classes.client.ts +99 -0
  35. package/ts/acme/acme.classes.crypto.ts +220 -0
  36. package/ts/acme/acme.classes.directory.ts +13 -0
  37. package/ts/acme/acme.classes.error.ts +55 -0
  38. package/ts/acme/acme.classes.http-client.ts +236 -0
  39. package/ts/acme/acme.classes.order.ts +125 -0
  40. package/ts/acme/acme.interfaces.ts +74 -0
  41. package/ts/acme/index.ts +16 -0
  42. package/ts/certmanagers/mongo.ts +0 -1
  43. package/ts/plugins.ts +3 -14
  44. package/ts/smartacme.classes.smartacme.ts +88 -23
  45. package/dist_ts/certmanagers.d.ts +0 -42
  46. package/dist_ts/certmanagers.js +0 -86
  47. package/dist_ts/smartacme.classes.certmanager.d.ts +0 -43
  48. package/dist_ts/smartacme.classes.certmanager.js +0 -92
  49. package/dist_ts/smartacme.plugins.d.ts +0 -21
  50. package/dist_ts/smartacme.plugins.js +0 -28
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartacme',
6
- version: '7.3.4',
6
+ version: '9.0.0',
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=
@@ -0,0 +1,20 @@
1
+ import type { AcmeHttpClient } from './acme.classes.http-client.js';
2
+ import type { IAcmeAccount, IAcmeAccountCreateRequest } from './acme.interfaces.js';
3
+ /**
4
+ * ACME account management - registration and key management
5
+ */
6
+ export declare class AcmeAccount {
7
+ private httpClient;
8
+ private accountUrl;
9
+ constructor(httpClient: AcmeHttpClient);
10
+ /**
11
+ * Register or retrieve an ACME account.
12
+ * Uses JWK (not kid) since account URL is not yet known.
13
+ * Captures account URL from Location header for subsequent requests.
14
+ */
15
+ create(request: IAcmeAccountCreateRequest): Promise<IAcmeAccount>;
16
+ /**
17
+ * Get the account URL (kid) for use in JWS headers
18
+ */
19
+ getAccountUrl(): string;
20
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * ACME account management - registration and key management
3
+ */
4
+ export class AcmeAccount {
5
+ constructor(httpClient) {
6
+ this.accountUrl = null;
7
+ this.httpClient = httpClient;
8
+ }
9
+ /**
10
+ * Register or retrieve an ACME account.
11
+ * Uses JWK (not kid) since account URL is not yet known.
12
+ * Captures account URL from Location header for subsequent requests.
13
+ */
14
+ async create(request) {
15
+ const dir = await this.httpClient.getDirectory();
16
+ const response = await this.httpClient.signedRequest(dir.newAccount, request, {
17
+ useJwk: true,
18
+ });
19
+ // Capture account URL from Location header (used as kid for future requests)
20
+ const location = response.headers['location'];
21
+ if (location) {
22
+ this.accountUrl = location;
23
+ this.httpClient.kid = location;
24
+ }
25
+ return response.data;
26
+ }
27
+ /**
28
+ * Get the account URL (kid) for use in JWS headers
29
+ */
30
+ getAccountUrl() {
31
+ if (!this.accountUrl) {
32
+ throw new Error('Account not yet created - call create() first');
33
+ }
34
+ return this.accountUrl;
35
+ }
36
+ }
37
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNtZS5jbGFzc2VzLmFjY291bnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9hY21lL2FjbWUuY2xhc3Nlcy5hY2NvdW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFdBQVc7SUFJdEIsWUFBWSxVQUEwQjtRQUY5QixlQUFVLEdBQWtCLElBQUksQ0FBQztRQUd2QyxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztJQUMvQixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBa0M7UUFDN0MsTUFBTSxHQUFHLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ2pELE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRSxPQUFPLEVBQUU7WUFDNUUsTUFBTSxFQUFFLElBQUk7U0FDYixDQUFDLENBQUM7UUFFSCw2RUFBNkU7UUFDN0UsTUFBTSxRQUFRLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUM5QyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQ2IsSUFBSSxDQUFDLFVBQVUsR0FBRyxRQUFRLENBQUM7WUFDM0IsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLEdBQUcsUUFBUSxDQUFDO1FBQ2pDLENBQUM7UUFFRCxPQUFPLFFBQVEsQ0FBQyxJQUFvQixDQUFDO0lBQ3ZDLENBQUM7SUFFRDs7T0FFRztJQUNILGFBQWE7UUFDWCxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ3JCLE1BQU0sSUFBSSxLQUFLLENBQUMsK0NBQStDLENBQUMsQ0FBQztRQUNuRSxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ3pCLENBQUM7Q0FDRiJ9
@@ -0,0 +1,22 @@
1
+ import type { AcmeHttpClient } from './acme.classes.http-client.js';
2
+ import type { IAcmeChallenge } from './acme.interfaces.js';
3
+ /**
4
+ * ACME challenge operations - key authorization computation and challenge completion
5
+ */
6
+ export declare class AcmeChallengeManager {
7
+ private httpClient;
8
+ private accountKeyPem;
9
+ constructor(httpClient: AcmeHttpClient, accountKeyPem: string);
10
+ /**
11
+ * Compute the key authorization for a challenge.
12
+ * For http-01: returns `token.thumbprint`
13
+ * For dns-01: returns `base64url(sha256(token.thumbprint))`
14
+ *
15
+ * This is a synchronous, pure-crypto computation.
16
+ */
17
+ getKeyAuthorization(challenge: IAcmeChallenge): string;
18
+ /**
19
+ * Notify the ACME server to validate a challenge (POST {} to challenge URL)
20
+ */
21
+ complete(challenge: IAcmeChallenge): Promise<void>;
22
+ }
@@ -0,0 +1,36 @@
1
+ import * as crypto from 'node:crypto';
2
+ import { AcmeCrypto } from './acme.classes.crypto.js';
3
+ /**
4
+ * ACME challenge operations - key authorization computation and challenge completion
5
+ */
6
+ export class AcmeChallengeManager {
7
+ constructor(httpClient, accountKeyPem) {
8
+ this.httpClient = httpClient;
9
+ this.accountKeyPem = accountKeyPem;
10
+ }
11
+ /**
12
+ * Compute the key authorization for a challenge.
13
+ * For http-01: returns `token.thumbprint`
14
+ * For dns-01: returns `base64url(sha256(token.thumbprint))`
15
+ *
16
+ * This is a synchronous, pure-crypto computation.
17
+ */
18
+ getKeyAuthorization(challenge) {
19
+ const jwk = AcmeCrypto.getJwk(this.accountKeyPem);
20
+ const thumbprint = AcmeCrypto.getJwkThumbprint(jwk);
21
+ const keyAuth = `${challenge.token}.${thumbprint}`;
22
+ if (challenge.type === 'dns-01') {
23
+ // DNS-01 uses base64url(SHA-256(keyAuthorization))
24
+ return crypto.createHash('sha256').update(keyAuth).digest().toString('base64url');
25
+ }
26
+ // HTTP-01 and others use the raw key authorization
27
+ return keyAuth;
28
+ }
29
+ /**
30
+ * Notify the ACME server to validate a challenge (POST {} to challenge URL)
31
+ */
32
+ async complete(challenge) {
33
+ await this.httpClient.signedRequest(challenge.url, {});
34
+ }
35
+ }
36
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNtZS5jbGFzc2VzLmNoYWxsZW5nZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2FjbWUvYWNtZS5jbGFzc2VzLmNoYWxsZW5nZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssTUFBTSxNQUFNLGFBQWEsQ0FBQztBQUN0QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFJdEQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sb0JBQW9CO0lBSS9CLFlBQVksVUFBMEIsRUFBRSxhQUFxQjtRQUMzRCxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztRQUM3QixJQUFJLENBQUMsYUFBYSxHQUFHLGFBQWEsQ0FBQztJQUNyQyxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0gsbUJBQW1CLENBQUMsU0FBeUI7UUFDM0MsTUFBTSxHQUFHLEdBQUcsVUFBVSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDbEQsTUFBTSxVQUFVLEdBQUcsVUFBVSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3BELE1BQU0sT0FBTyxHQUFHLEdBQUcsU0FBUyxDQUFDLEtBQUssSUFBSSxVQUFVLEVBQUUsQ0FBQztRQUVuRCxJQUFJLFNBQVMsQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDaEMsbURBQW1EO1lBQ25ELE9BQU8sTUFBTSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ3BGLENBQUM7UUFFRCxtREFBbUQ7UUFDbkQsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLFFBQVEsQ0FBQyxTQUF5QjtRQUN0QyxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDekQsQ0FBQztDQUNGIn0=
@@ -0,0 +1,68 @@
1
+ import { AcmeCrypto } from './acme.classes.crypto.js';
2
+ import { type TAcmeLogger } from './acme.classes.http-client.js';
3
+ import type { IAcmeAccount, IAcmeAccountCreateRequest, IAcmeAuthorization, IAcmeChallenge, IAcmeIdentifier, IAcmeOrder } from './acme.interfaces.js';
4
+ export interface IAcmeClientOptions {
5
+ directoryUrl: string;
6
+ accountKeyPem: string;
7
+ logger?: TAcmeLogger;
8
+ }
9
+ /**
10
+ * Top-level ACME client facade.
11
+ * Composes HTTP transport, account management, order lifecycle, and challenge handling.
12
+ */
13
+ export declare class AcmeClient {
14
+ private httpClient;
15
+ private account;
16
+ private orderManager;
17
+ private challengeManager;
18
+ /** Well-known CA directory URLs */
19
+ static directory: {
20
+ readonly letsencrypt: {
21
+ readonly production: "https://acme-v02.api.letsencrypt.org/directory";
22
+ readonly staging: "https://acme-staging-v02.api.letsencrypt.org/directory";
23
+ };
24
+ readonly buypass: {
25
+ readonly production: "https://api.buypass.com/acme/directory";
26
+ readonly staging: "https://api.test4.buypass.no/acme/directory";
27
+ };
28
+ };
29
+ /** Crypto utilities */
30
+ static crypto: typeof AcmeCrypto;
31
+ constructor(options: IAcmeClientOptions);
32
+ /**
33
+ * Register or retrieve an ACME account
34
+ */
35
+ createAccount(request: IAcmeAccountCreateRequest): Promise<IAcmeAccount>;
36
+ /**
37
+ * Create a new certificate order
38
+ */
39
+ createOrder(opts: {
40
+ identifiers: IAcmeIdentifier[];
41
+ }): Promise<IAcmeOrder>;
42
+ /**
43
+ * Get all authorizations for an order
44
+ */
45
+ getAuthorizations(order: IAcmeOrder): Promise<IAcmeAuthorization[]>;
46
+ /**
47
+ * Compute the key authorization string for a challenge (sync)
48
+ */
49
+ getChallengeKeyAuthorization(challenge: IAcmeChallenge): string;
50
+ /**
51
+ * Notify the ACME server to validate a challenge
52
+ */
53
+ completeChallenge(challenge: IAcmeChallenge): Promise<void>;
54
+ /**
55
+ * Poll an ACME resource until it reaches valid/ready status
56
+ */
57
+ waitForValidStatus(item: {
58
+ url: string;
59
+ }): Promise<any>;
60
+ /**
61
+ * Finalize an order by submitting the CSR
62
+ */
63
+ finalizeOrder(order: IAcmeOrder, csrPem: string): Promise<void>;
64
+ /**
65
+ * Download the certificate chain (PEM)
66
+ */
67
+ getCertificate(order: IAcmeOrder): Promise<string>;
68
+ }
@@ -0,0 +1,71 @@
1
+ import { AcmeCrypto } from './acme.classes.crypto.js';
2
+ import { ACME_DIRECTORY_URLS } from './acme.classes.directory.js';
3
+ import { AcmeHttpClient } from './acme.classes.http-client.js';
4
+ import { AcmeAccount } from './acme.classes.account.js';
5
+ import { AcmeOrderManager } from './acme.classes.order.js';
6
+ import { AcmeChallengeManager } from './acme.classes.challenge.js';
7
+ /**
8
+ * Top-level ACME client facade.
9
+ * Composes HTTP transport, account management, order lifecycle, and challenge handling.
10
+ */
11
+ export class AcmeClient {
12
+ /** Well-known CA directory URLs */
13
+ static { this.directory = ACME_DIRECTORY_URLS; }
14
+ /** Crypto utilities */
15
+ static { this.crypto = AcmeCrypto; }
16
+ constructor(options) {
17
+ this.httpClient = new AcmeHttpClient(options.directoryUrl, options.accountKeyPem, options.logger);
18
+ this.account = new AcmeAccount(this.httpClient);
19
+ this.orderManager = new AcmeOrderManager(this.httpClient);
20
+ this.challengeManager = new AcmeChallengeManager(this.httpClient, options.accountKeyPem);
21
+ }
22
+ /**
23
+ * Register or retrieve an ACME account
24
+ */
25
+ async createAccount(request) {
26
+ return this.account.create(request);
27
+ }
28
+ /**
29
+ * Create a new certificate order
30
+ */
31
+ async createOrder(opts) {
32
+ return this.orderManager.create(opts);
33
+ }
34
+ /**
35
+ * Get all authorizations for an order
36
+ */
37
+ async getAuthorizations(order) {
38
+ return this.orderManager.getAuthorizations(order);
39
+ }
40
+ /**
41
+ * Compute the key authorization string for a challenge (sync)
42
+ */
43
+ getChallengeKeyAuthorization(challenge) {
44
+ return this.challengeManager.getKeyAuthorization(challenge);
45
+ }
46
+ /**
47
+ * Notify the ACME server to validate a challenge
48
+ */
49
+ async completeChallenge(challenge) {
50
+ return this.challengeManager.complete(challenge);
51
+ }
52
+ /**
53
+ * Poll an ACME resource until it reaches valid/ready status
54
+ */
55
+ async waitForValidStatus(item) {
56
+ return this.orderManager.waitForValidStatus(item);
57
+ }
58
+ /**
59
+ * Finalize an order by submitting the CSR
60
+ */
61
+ async finalizeOrder(order, csrPem) {
62
+ return this.orderManager.finalize(order, csrPem);
63
+ }
64
+ /**
65
+ * Download the certificate chain (PEM)
66
+ */
67
+ async getCertificate(order) {
68
+ return this.orderManager.getCertificate(order);
69
+ }
70
+ }
71
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNtZS5jbGFzc2VzLmNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2FjbWUvYWNtZS5jbGFzc2VzLmNsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDdEQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDbEUsT0FBTyxFQUFFLGNBQWMsRUFBb0IsTUFBTSwrQkFBK0IsQ0FBQztBQUNqRixPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDeEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDM0QsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFnQm5FOzs7R0FHRztBQUNILE1BQU0sT0FBTyxVQUFVO0lBTXJCLG1DQUFtQzthQUM1QixjQUFTLEdBQUcsbUJBQW1CLENBQUM7SUFDdkMsdUJBQXVCO2FBQ2hCLFdBQU0sR0FBRyxVQUFVLENBQUM7SUFFM0IsWUFBWSxPQUEyQjtRQUNyQyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksY0FBYyxDQUFDLE9BQU8sQ0FBQyxZQUFZLEVBQUUsT0FBTyxDQUFDLGFBQWEsRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDbEcsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLFdBQVcsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDaEQsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLGdCQUFnQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUMxRCxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUMzRixDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsYUFBYSxDQUFDLE9BQWtDO1FBQ3BELE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDdEMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLFdBQVcsQ0FBQyxJQUF3QztRQUN4RCxPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3hDLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxLQUFpQjtRQUN2QyxPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDcEQsQ0FBQztJQUVEOztPQUVHO0lBQ0gsNEJBQTRCLENBQUMsU0FBeUI7UUFDcEQsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsbUJBQW1CLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDOUQsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLGlCQUFpQixDQUFDLFNBQXlCO1FBQy9DLE9BQU8sSUFBSSxDQUFDLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNuRCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsa0JBQWtCLENBQUMsSUFBcUI7UUFDNUMsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3BELENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxhQUFhLENBQUMsS0FBaUIsRUFBRSxNQUFjO1FBQ25ELE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxjQUFjLENBQUMsS0FBaUI7UUFDcEMsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNqRCxDQUFDIn0=
@@ -0,0 +1,50 @@
1
+ import type { IAcmeCsrOptions } from './acme.interfaces.js';
2
+ /**
3
+ * All cryptographic operations for the ACME protocol.
4
+ * Uses node:crypto for key gen, JWK, JWS signing.
5
+ * Uses @peculiar/x509 for CSR generation (no native Node.js CSR API).
6
+ */
7
+ export declare class AcmeCrypto {
8
+ /**
9
+ * Generate an RSA private key in PEM format
10
+ */
11
+ static createRsaPrivateKey(modulusLength?: number): string;
12
+ /**
13
+ * Export public JWK from PEM private key, keys sorted alphabetically per RFC 7638
14
+ */
15
+ static getJwk(keyPem: string): Record<string, string>;
16
+ /**
17
+ * Compute JWK Thumbprint (SHA-256, base64url) per RFC 7638
18
+ */
19
+ static getJwkThumbprint(jwk: Record<string, string>): string;
20
+ /**
21
+ * Create a flattened JWS for ACME requests (RFC 7515)
22
+ * payload=null means POST-as-GET (empty string payload)
23
+ */
24
+ static createJws(keyPem: string, url: string, payload: any | null, options: {
25
+ nonce: string;
26
+ kid?: string;
27
+ jwk?: Record<string, string>;
28
+ }): {
29
+ protected: string;
30
+ payload: string;
31
+ signature: string;
32
+ };
33
+ /**
34
+ * Create a CSR (PKCS#10) via @peculiar/x509
35
+ * Returns [privateKeyPem, csrPem]
36
+ */
37
+ static createCsr(options: IAcmeCsrOptions, existingKeyPem?: string): Promise<[string, string]>;
38
+ /**
39
+ * Convert PEM to raw DER Buffer (strip headers, decode base64)
40
+ */
41
+ static pemToBuffer(pem: string): Buffer;
42
+ /**
43
+ * Determine JWS algorithm from key type
44
+ */
45
+ private static getAlg;
46
+ /**
47
+ * Import a PEM private key into WebCrypto as a CryptoKeyPair
48
+ */
49
+ private static importKeyPairToWebCrypto;
50
+ }
@@ -0,0 +1,180 @@
1
+ import * as crypto from 'node:crypto';
2
+ /**
3
+ * All cryptographic operations for the ACME protocol.
4
+ * Uses node:crypto for key gen, JWK, JWS signing.
5
+ * Uses @peculiar/x509 for CSR generation (no native Node.js CSR API).
6
+ */
7
+ export class AcmeCrypto {
8
+ /**
9
+ * Generate an RSA private key in PEM format
10
+ */
11
+ static createRsaPrivateKey(modulusLength = 2048) {
12
+ const { privateKey } = crypto.generateKeyPairSync('rsa', {
13
+ modulusLength,
14
+ publicKeyEncoding: { type: 'spki', format: 'pem' },
15
+ privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
16
+ });
17
+ return privateKey;
18
+ }
19
+ /**
20
+ * Export public JWK from PEM private key, keys sorted alphabetically per RFC 7638
21
+ */
22
+ static getJwk(keyPem) {
23
+ const keyObj = crypto.createPublicKey(keyPem);
24
+ const jwk = keyObj.export({ format: 'jwk' });
25
+ if (jwk.kty === 'RSA') {
26
+ return { e: jwk.e, kty: jwk.kty, n: jwk.n };
27
+ }
28
+ else if (jwk.kty === 'EC') {
29
+ return { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y };
30
+ }
31
+ throw new Error(`Unsupported key type: ${jwk.kty}`);
32
+ }
33
+ /**
34
+ * Compute JWK Thumbprint (SHA-256, base64url) per RFC 7638
35
+ */
36
+ static getJwkThumbprint(jwk) {
37
+ let canonical;
38
+ if (jwk.kty === 'RSA') {
39
+ canonical = JSON.stringify({ e: jwk.e, kty: jwk.kty, n: jwk.n });
40
+ }
41
+ else if (jwk.kty === 'EC') {
42
+ canonical = JSON.stringify({ crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y });
43
+ }
44
+ else {
45
+ throw new Error(`Unsupported key type: ${jwk.kty}`);
46
+ }
47
+ const hash = crypto.createHash('sha256').update(canonical).digest();
48
+ return hash.toString('base64url');
49
+ }
50
+ /**
51
+ * Create a flattened JWS for ACME requests (RFC 7515)
52
+ * payload=null means POST-as-GET (empty string payload)
53
+ */
54
+ static createJws(keyPem, url, payload, options) {
55
+ const header = {
56
+ alg: AcmeCrypto.getAlg(keyPem),
57
+ nonce: options.nonce,
58
+ url,
59
+ };
60
+ if (options.kid) {
61
+ header.kid = options.kid;
62
+ }
63
+ else if (options.jwk) {
64
+ header.jwk = options.jwk;
65
+ }
66
+ else {
67
+ header.jwk = AcmeCrypto.getJwk(keyPem);
68
+ }
69
+ const protectedB64 = Buffer.from(JSON.stringify(header)).toString('base64url');
70
+ const payloadB64 = payload !== null ? Buffer.from(JSON.stringify(payload)).toString('base64url') : '';
71
+ const signingInput = `${protectedB64}.${payloadB64}`;
72
+ const keyObj = crypto.createPrivateKey(keyPem);
73
+ const alg = AcmeCrypto.getAlg(keyPem);
74
+ let signature;
75
+ if (alg.startsWith('RS')) {
76
+ signature = crypto.sign('sha256', Buffer.from(signingInput), keyObj);
77
+ }
78
+ else if (alg.startsWith('ES')) {
79
+ signature = crypto.sign('sha256', Buffer.from(signingInput), {
80
+ key: keyObj,
81
+ dsaEncoding: 'ieee-p1363',
82
+ });
83
+ }
84
+ else {
85
+ throw new Error(`Unsupported algorithm: ${alg}`);
86
+ }
87
+ return {
88
+ protected: protectedB64,
89
+ payload: payloadB64,
90
+ signature: signature.toString('base64url'),
91
+ };
92
+ }
93
+ /**
94
+ * Create a CSR (PKCS#10) via @peculiar/x509
95
+ * Returns [privateKeyPem, csrPem]
96
+ */
97
+ static async createCsr(options, existingKeyPem) {
98
+ const x509 = await import('@peculiar/x509');
99
+ const { webcrypto } = crypto;
100
+ x509.cryptoProvider.set(webcrypto);
101
+ let keys;
102
+ let keyPem;
103
+ if (existingKeyPem) {
104
+ keys = await AcmeCrypto.importKeyPairToWebCrypto(existingKeyPem, webcrypto);
105
+ keyPem = existingKeyPem;
106
+ }
107
+ else {
108
+ keys = (await webcrypto.subtle.generateKey({
109
+ name: 'RSASSA-PKCS1-v1_5',
110
+ modulusLength: 2048,
111
+ publicExponent: new Uint8Array([1, 0, 1]),
112
+ hash: 'SHA-256',
113
+ }, true, ['sign', 'verify']));
114
+ const pkcs8 = await webcrypto.subtle.exportKey('pkcs8', keys.privateKey);
115
+ const b64 = Buffer.from(pkcs8).toString('base64');
116
+ const lines = b64.match(/.{1,64}/g);
117
+ keyPem = `-----BEGIN PRIVATE KEY-----\n${lines.join('\n')}\n-----END PRIVATE KEY-----\n`;
118
+ }
119
+ // Collect all DNS names for SAN (CN is always included)
120
+ const sanNames = [options.commonName];
121
+ if (options.altNames) {
122
+ for (const name of options.altNames) {
123
+ if (!sanNames.includes(name)) {
124
+ sanNames.push(name);
125
+ }
126
+ }
127
+ }
128
+ const csr = await x509.Pkcs10CertificateRequestGenerator.create({
129
+ name: `CN=${options.commonName}`,
130
+ keys,
131
+ signingAlgorithm: { name: 'RSASSA-PKCS1-v1_5' },
132
+ extensions: [
133
+ new x509.SubjectAlternativeNameExtension(sanNames.map((name) => ({ type: 'dns', value: name }))),
134
+ ],
135
+ });
136
+ // Convert to PEM
137
+ const csrPem = csr.toString('pem');
138
+ return [keyPem, csrPem];
139
+ }
140
+ /**
141
+ * Convert PEM to raw DER Buffer (strip headers, decode base64)
142
+ */
143
+ static pemToBuffer(pem) {
144
+ const lines = pem
145
+ .split('\n')
146
+ .filter((line) => !line.startsWith('-----') && line.trim().length > 0);
147
+ return Buffer.from(lines.join(''), 'base64');
148
+ }
149
+ /**
150
+ * Determine JWS algorithm from key type
151
+ */
152
+ static getAlg(keyPem) {
153
+ const keyObj = crypto.createPrivateKey(keyPem);
154
+ const keyType = keyObj.asymmetricKeyType;
155
+ if (keyType === 'rsa')
156
+ return 'RS256';
157
+ if (keyType === 'ec') {
158
+ const details = keyObj.asymmetricKeyDetails;
159
+ if (details?.namedCurve === 'prime256v1' || details?.namedCurve === 'P-256')
160
+ return 'ES256';
161
+ if (details?.namedCurve === 'secp384r1' || details?.namedCurve === 'P-384')
162
+ return 'ES384';
163
+ return 'ES256';
164
+ }
165
+ throw new Error(`Unsupported key type: ${keyType}`);
166
+ }
167
+ /**
168
+ * Import a PEM private key into WebCrypto as a CryptoKeyPair
169
+ */
170
+ static async importKeyPairToWebCrypto(keyPem, wc) {
171
+ const keyObj = crypto.createPrivateKey(keyPem);
172
+ const pkcs8Der = keyObj.export({ type: 'pkcs8', format: 'der' });
173
+ const privateKey = await wc.subtle.importKey('pkcs8', pkcs8Der, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' }, true, ['sign']);
174
+ const pubKeyObj = crypto.createPublicKey(keyPem);
175
+ const spkiDer = pubKeyObj.export({ type: 'spki', format: 'der' });
176
+ const publicKey = await wc.subtle.importKey('spki', spkiDer, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' }, true, ['verify']);
177
+ return { privateKey: privateKey, publicKey: publicKey };
178
+ }
179
+ }
180
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNtZS5jbGFzc2VzLmNyeXB0by5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2FjbWUvYWNtZS5jbGFzc2VzLmNyeXB0by50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssTUFBTSxNQUFNLGFBQWEsQ0FBQztBQUd0Qzs7OztHQUlHO0FBQ0gsTUFBTSxPQUFPLFVBQVU7SUFDckI7O09BRUc7SUFDSCxNQUFNLENBQUMsbUJBQW1CLENBQUMsYUFBYSxHQUFHLElBQUk7UUFDN0MsTUFBTSxFQUFFLFVBQVUsRUFBRSxHQUFHLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLEVBQUU7WUFDdkQsYUFBYTtZQUNiLGlCQUFpQixFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFO1lBQ2xELGtCQUFrQixFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFO1NBQ3JELENBQUMsQ0FBQztRQUNILE9BQU8sVUFBVSxDQUFDO0lBQ3BCLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBQyxNQUFNLENBQUMsTUFBYztRQUMxQixNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzlDLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQXdCLENBQUM7UUFDcEUsSUFBSSxHQUFHLENBQUMsR0FBRyxLQUFLLEtBQUssRUFBRSxDQUFDO1lBQ3RCLE9BQU8sRUFBRSxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQzlDLENBQUM7YUFBTSxJQUFJLEdBQUcsQ0FBQyxHQUFHLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDNUIsT0FB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
@@ -0,0 +1,13 @@
1
+ /**
2
+ * ACME directory URL constants for well-known CAs
3
+ */
4
+ export declare const ACME_DIRECTORY_URLS: {
5
+ readonly letsencrypt: {
6
+ readonly production: "https://acme-v02.api.letsencrypt.org/directory";
7
+ readonly staging: "https://acme-staging-v02.api.letsencrypt.org/directory";
8
+ };
9
+ readonly buypass: {
10
+ readonly production: "https://api.buypass.com/acme/directory";
11
+ readonly staging: "https://api.test4.buypass.no/acme/directory";
12
+ };
13
+ };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * ACME directory URL constants for well-known CAs
3
+ */
4
+ export const ACME_DIRECTORY_URLS = {
5
+ letsencrypt: {
6
+ production: 'https://acme-v02.api.letsencrypt.org/directory',
7
+ staging: 'https://acme-staging-v02.api.letsencrypt.org/directory',
8
+ },
9
+ buypass: {
10
+ production: 'https://api.buypass.com/acme/directory',
11
+ staging: 'https://api.test4.buypass.no/acme/directory',
12
+ },
13
+ };
14
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNtZS5jbGFzc2VzLmRpcmVjdG9yeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2FjbWUvYWNtZS5jbGFzc2VzLmRpcmVjdG9yeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHO0lBQ2pDLFdBQVcsRUFBRTtRQUNYLFVBQVUsRUFBRSxnREFBZ0Q7UUFDNUQsT0FBTyxFQUFFLHdEQUF3RDtLQUNsRTtJQUNELE9BQU8sRUFBRTtRQUNQLFVBQVUsRUFBRSx3Q0FBd0M7UUFDcEQsT0FBTyxFQUFFLDZDQUE2QztLQUN2RDtDQUNPLENBQUMifQ==
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Structured ACME protocol error with RFC 8555 fields.
3
+ * Provides type URN, subproblems, Retry-After, and retryability classification.
4
+ */
5
+ export declare class AcmeError extends Error {
6
+ readonly status: number;
7
+ readonly type: string;
8
+ readonly detail: string;
9
+ readonly subproblems: Array<{
10
+ type: string;
11
+ detail: string;
12
+ identifier?: {
13
+ type: string;
14
+ value: string;
15
+ };
16
+ }>;
17
+ readonly url: string;
18
+ readonly retryAfter: number;
19
+ constructor(options: {
20
+ message?: string;
21
+ status: number;
22
+ type?: string;
23
+ detail?: string;
24
+ subproblems?: Array<{
25
+ type: string;
26
+ detail: string;
27
+ identifier?: {
28
+ type: string;
29
+ value: string;
30
+ };
31
+ }>;
32
+ url?: string;
33
+ retryAfter?: number;
34
+ });
35
+ /**
36
+ * True for HTTP 429 or ACME rateLimited type URN
37
+ */
38
+ get isRateLimited(): boolean;
39
+ /**
40
+ * True for transient/retryable errors: 429, 503, 5xx, badNonce.
41
+ * False for definitive client errors: 400 (non-badNonce), 403, 404, 409.
42
+ */
43
+ get isRetryable(): boolean;
44
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Structured ACME protocol error with RFC 8555 fields.
3
+ * Provides type URN, subproblems, Retry-After, and retryability classification.
4
+ */
5
+ export class AcmeError extends Error {
6
+ constructor(options) {
7
+ const type = options.type || '';
8
+ const detail = options.detail || '';
9
+ const url = options.url || '';
10
+ const msg = options.message ||
11
+ `ACME error: ${type || 'unknown'} (HTTP ${options.status}) at ${url || 'unknown'} - ${detail || 'no detail'}`;
12
+ super(msg);
13
+ this.name = 'AcmeError';
14
+ this.status = options.status;
15
+ this.type = type;
16
+ this.detail = detail;
17
+ this.subproblems = options.subproblems || [];
18
+ this.url = url;
19
+ this.retryAfter = options.retryAfter || 0;
20
+ }
21
+ /**
22
+ * True for HTTP 429 or ACME rateLimited type URN
23
+ */
24
+ get isRateLimited() {
25
+ return this.status === 429 || this.type === 'urn:ietf:params:acme:error:rateLimited';
26
+ }
27
+ /**
28
+ * True for transient/retryable errors: 429, 503, 5xx, badNonce.
29
+ * False for definitive client errors: 400 (non-badNonce), 403, 404, 409.
30
+ */
31
+ get isRetryable() {
32
+ if (this.type === 'urn:ietf:params:acme:error:badNonce')
33
+ return true;
34
+ if (this.status === 429 || this.status === 503)
35
+ return true;
36
+ if (this.status >= 500)
37
+ return true;
38
+ return false;
39
+ }
40
+ }
41
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNtZS5jbGFzc2VzLmVycm9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvYWNtZS9hY21lLmNsYXNzZXMuZXJyb3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLFNBQVUsU0FBUSxLQUFLO0lBUWxDLFlBQVksT0FRWDtRQUNDLE1BQU0sSUFBSSxHQUFHLE9BQU8sQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDO1FBQ2hDLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxNQUFNLElBQUksRUFBRSxDQUFDO1FBQ3BDLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLElBQUksRUFBRSxDQUFDO1FBQzlCLE1BQU0sR0FBRyxHQUNQLE9BQU8sQ0FBQyxPQUFPO1lBQ2YsZUFBZSxJQUFJLElBQUksU0FBUyxVQUFVLE9BQU8sQ0FBQyxNQUFNLFFBQVEsR0FBRyxJQUFJLFNBQVMsTUFBTSxNQUFNLElBQUksV0FBVyxFQUFFLENBQUM7UUFDaEgsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ1gsSUFBSSxDQUFDLElBQUksR0FBRyxXQUFXLENBQUM7UUFDeEIsSUFBSSxDQUFDLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDO1FBQzdCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ2pCLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxXQUFXLEdBQUcsT0FBTyxDQUFDLFdBQVcsSUFBSSxFQUFFLENBQUM7UUFDN0MsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUM7UUFDZixJQUFJLENBQUMsVUFBVSxHQUFHLE9BQU8sQ0FBQyxVQUFVLElBQUksQ0FBQyxDQUFDO0lBQzVDLENBQUM7SUFFRDs7T0FFRztJQUNILElBQUksYUFBYTtRQUNmLE9BQU8sSUFBSSxDQUFDLE1BQU0sS0FBSyxHQUFHLElBQUksSUFBSSxDQUFDLElBQUksS0FBSyx3Q0FBd0MsQ0FBQztJQUN2RixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsSUFBSSxXQUFXO1FBQ2IsSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLHFDQUFxQztZQUFFLE9BQU8sSUFBSSxDQUFDO1FBQ3JFLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxHQUFHLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxHQUFHO1lBQUUsT0FBTyxJQUFJLENBQUM7UUFDNUQsSUFBSSxJQUFJLENBQUMsTUFBTSxJQUFJLEdBQUc7WUFBRSxPQUFPLElBQUksQ0FBQztRQUNwQyxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7Q0FDRiJ9