@certd/acme-client 1.39.12 → 1.39.13

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.
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Defaults
3
+ */
4
+ declare const instance: import("axios").AxiosInstance;
5
+ /**
6
+ * Export instance
7
+ */
8
+ export default instance;
@@ -1,26 +1,23 @@
1
+ // @ts-nocheck
1
2
  /**
2
3
  * Axios instance
3
4
  */
4
5
  import axios from 'axios';
5
6
  import { parseRetryAfterHeader } from './util.js';
6
7
  const { AxiosError } = axios;
7
- import {getGlobalAgents, HttpError} from '@certd/basic'
8
+ import { getGlobalAgents, HttpError } from '@certd/basic';
8
9
  import { log } from './logger.js';
9
10
  /**
10
11
  * Defaults
11
12
  */
12
-
13
13
  const instance = axios.create();
14
-
15
14
  /* Default User-Agent */
16
15
  instance.defaults.headers.common['User-Agent'] = `@certd/acme-client`;
17
-
18
16
  /* Default ACME settings */
19
17
  instance.defaults.acmeSettings = {
20
18
  httpChallengePort: 80,
21
19
  httpsChallengePort: 443,
22
20
  tlsAlpnChallengePort: 443,
23
-
24
21
  retryMaxAttempts: 3,
25
22
  retryDefaultDelay: 3,
26
23
  };
@@ -34,15 +31,12 @@ instance.defaults.acmeSettings = {
34
31
  * https://github.com/axios/axios/issues/1180
35
32
  * https://stackoverflow.com/questions/42677387
36
33
  */
37
-
38
34
  instance.defaults.adapter = 'http';
39
-
40
35
  /**
41
36
  * Retry requests on server errors or when rate limited
42
37
  *
43
38
  * https://datatracker.ietf.org/doc/html/rfc8555#section-6.6
44
39
  */
45
-
46
40
  function isRetryableError(error) {
47
41
  return (error.code !== 'ECONNABORTED')
48
42
  && (error.code !== 'ERR_NOCK_NO_MATCH')
@@ -50,7 +44,6 @@ function isRetryableError(error) {
50
44
  || (error.response.status === 429)
51
45
  || ((error.response.status >= 500) && (error.response.status <= 599)));
52
46
  }
53
-
54
47
  /* https://github.com/axios/axios/blob/main/lib/core/settle.js */
55
48
  function validateStatus(response) {
56
49
  if (!response) {
@@ -63,25 +56,15 @@ function validateStatus(response) {
63
56
  if (!response.status || !validator || validator(response.status)) {
64
57
  return response;
65
58
  }
66
-
67
- const err = new AxiosError(
68
- `Request failed with status code ${response.status}`,
69
- (Math.floor(response.status / 100) === 4) ? AxiosError.ERR_BAD_REQUEST : AxiosError.ERR_BAD_RESPONSE,
70
- response.config,
71
- response.request,
72
- response,
73
- );
74
-
59
+ const err = new AxiosError(`Request failed with status code ${response.status}`, (Math.floor(response.status / 100) === 4) ? AxiosError.ERR_BAD_REQUEST : AxiosError.ERR_BAD_RESPONSE, response.config, response.request, response);
75
60
  throw new HttpError(err);
76
61
  }
77
-
78
62
  /* Pass all responses through the error interceptor */
79
63
  instance.interceptors.request.use((config) => {
80
64
  if (!('retryValidateStatus' in config)) {
81
65
  config.retryValidateStatus = config.validateStatus;
82
66
  }
83
67
  config.validateStatus = () => false;
84
-
85
68
  const agents = getGlobalAgents();
86
69
  // if (config.skipSslVerify) {
87
70
  // logger.info('跳过SSL验证');
@@ -93,53 +76,42 @@ instance.interceptors.request.use((config) => {
93
76
  config.proxy = false; // 必须 否则还会走一层代理,
94
77
  return config;
95
78
  });
96
-
97
79
  /* Handle request retries if applicable */
98
80
  instance.interceptors.response.use(null, async (error) => {
99
81
  const { config, response } = error;
100
-
101
82
  if (!config) {
102
83
  return Promise.reject(new HttpError(error));
103
84
  }
104
-
105
85
  /* Pick up errors we want to retry */
106
86
  if (isRetryableError(error)) {
107
87
  const { retryMaxAttempts, retryDefaultDelay } = instance.defaults.acmeSettings;
108
88
  config.retryAttempt = ('retryAttempt' in config) ? (config.retryAttempt + 1) : 1;
109
-
110
89
  if (config.retryAttempt <= retryMaxAttempts) {
111
90
  const code = response ? `HTTP ${response.status}` : error.code;
112
91
  log(`Caught ${code}, retry attempt ${config.retryAttempt}/${retryMaxAttempts} to URL ${config.url}`);
113
-
114
92
  const retryAfter = (retryDefaultDelay * config.retryAttempt);
115
93
  /* Attempt to parse Retry-After header, fallback to default delay */
116
94
  const headerRetryAfter = response ? parseRetryAfterHeader(response.headers['retry-after']) : 0;
117
-
118
95
  if (headerRetryAfter > 0) {
119
96
  const waitMinutes = (headerRetryAfter / 60).toFixed(1);
120
97
  log(`Found retry-after response header with value: ${response.headers['retry-after']}, waiting ${waitMinutes} minutes`);
121
98
  log(JSON.stringify(response.data));
122
99
  return Promise.reject(new HttpError(error));
123
100
  }
124
-
125
101
  log(`waiting ${retryAfter} seconds`);
126
-
127
102
  /* Wait and retry the request */
128
103
  await new Promise((resolve) => { setTimeout(resolve, (retryAfter * 1000)); });
129
104
  log(`Retrying request to URL ${config.url}`);
130
105
  return instance(config);
131
106
  }
132
107
  }
133
-
134
108
  if (!response) {
135
109
  return Promise.reject(new HttpError(error));
136
110
  }
137
111
  /* Validate and return response */
138
112
  return validateStatus(response);
139
113
  });
140
-
141
114
  /**
142
115
  * Export instance
143
116
  */
144
-
145
117
  export default instance;
@@ -0,0 +1,396 @@
1
+ /**
2
+ * AcmeClient
3
+ *
4
+ * @class
5
+ * @param {object} opts
6
+ * @param {string} opts.directoryUrl ACME directory URL
7
+ * @param {buffer|string} opts.accountKey PEM encoded account private key
8
+ * @param {string} [opts.accountUrl] Account URL, default: `null`
9
+ * @param {object} [opts.externalAccountBinding]
10
+ * @param {string} [opts.externalAccountBinding.kid] External account binding KID
11
+ * @param {string} [opts.externalAccountBinding.hmacKey] External account binding HMAC key
12
+ * @param {number} [opts.backoffAttempts] Maximum number of backoff attempts, default: `10`
13
+ * @param {number} [opts.backoffMin] Minimum backoff attempt delay in milliseconds, default: `5000`
14
+ * @param {number} [opts.backoffMax] Maximum backoff attempt delay in milliseconds, default: `30000`
15
+ *
16
+ * @example Create ACME client instance
17
+ * ```js
18
+ * const client = new acme.Client({
19
+ * directoryUrl: acme.directory.letsencrypt.staging,
20
+ * accountKey: 'Private key goes here',
21
+ * });
22
+ * ```
23
+ *
24
+ * @example Create ACME client instance
25
+ * ```js
26
+ * const client = new acme.Client({
27
+ * directoryUrl: acme.directory.letsencrypt.staging,
28
+ * accountKey: 'Private key goes here',
29
+ * accountUrl: 'Optional account URL goes here',
30
+ * backoffAttempts: 10,
31
+ * backoffMin: 5000,
32
+ * backoffMax: 30000,
33
+ * });
34
+ * ```
35
+ *
36
+ * @example Create ACME client with external account binding
37
+ * ```js
38
+ * const client = new acme.Client({
39
+ * directoryUrl: 'https://acme-provider.example.com/directory-url',
40
+ * accountKey: 'Private key goes here',
41
+ * externalAccountBinding: {
42
+ * kid: 'YOUR-EAB-KID',
43
+ * hmacKey: 'YOUR-EAB-HMAC-KEY',
44
+ * },
45
+ * });
46
+ * ```
47
+ */
48
+ declare class AcmeClient {
49
+ sslProvider: any;
50
+ constructor(opts: any);
51
+ log(...args: any[]): void;
52
+ /**
53
+ * Get Terms of Service URL if available
54
+ *
55
+ * @returns {Promise<string|null>} ToS URL
56
+ *
57
+ * @example Get Terms of Service URL
58
+ * ```js
59
+ * const termsOfService = client.getTermsOfServiceUrl();
60
+ *
61
+ * if (!termsOfService) {
62
+ * // CA did not provide Terms of Service
63
+ * }
64
+ * ```
65
+ */
66
+ getTermsOfServiceUrl(): any;
67
+ /**
68
+ * Get current account URL
69
+ *
70
+ * @returns {string} Account URL
71
+ * @throws {Error} No account URL found
72
+ *
73
+ * @example Get current account URL
74
+ * ```js
75
+ * try {
76
+ * const accountUrl = client.getAccountUrl();
77
+ * }
78
+ * catch (e) {
79
+ * // No account URL exists, need to create account first
80
+ * }
81
+ * ```
82
+ */
83
+ getAccountUrl(): any;
84
+ /**
85
+ * Create a new account
86
+ *
87
+ * https://datatracker.ietf.org/doc/html/rfc8555#section-7.3
88
+ *
89
+ * @param {object} [data] Request data
90
+ * @returns {Promise<object>} Account
91
+ *
92
+ * @example Create a new account
93
+ * ```js
94
+ * const account = await client.createAccount({
95
+ * termsOfServiceAgreed: true,
96
+ * });
97
+ * ```
98
+ *
99
+ * @example Create a new account with contact info
100
+ * ```js
101
+ * const account = await client.createAccount({
102
+ * termsOfServiceAgreed: true,
103
+ * contact: ['mailto:test@example.com'],
104
+ * });
105
+ * ```
106
+ */
107
+ createAccount(data?: {}): any;
108
+ /**
109
+ * Update existing account
110
+ *
111
+ * https://datatracker.ietf.org/doc/html/rfc8555#section-7.3.2
112
+ *
113
+ * @param {object} [data] Request data
114
+ * @returns {Promise<object>} Account
115
+ *
116
+ * @example Update existing account
117
+ * ```js
118
+ * const account = await client.updateAccount({
119
+ * contact: ['mailto:foo@example.com'],
120
+ * });
121
+ * ```
122
+ */
123
+ updateAccount(data?: {}): any;
124
+ /**
125
+ * Update account private key
126
+ *
127
+ * https://datatracker.ietf.org/doc/html/rfc8555#section-7.3.5
128
+ *
129
+ * @param {buffer|string} newAccountKey New PEM encoded private key
130
+ * @param {object} [data] Additional request data
131
+ * @returns {Promise<object>} Account
132
+ *
133
+ * @example Update account private key
134
+ * ```js
135
+ * const newAccountKey = 'New private key goes here';
136
+ * const result = await client.updateAccountKey(newAccountKey);
137
+ * ```
138
+ */
139
+ updateAccountKey(newAccountKey: any, data?: {}): Promise<any>;
140
+ /**
141
+ * Create a new order
142
+ *
143
+ * https://datatracker.ietf.org/doc/html/rfc8555#section-7.4
144
+ *
145
+ * @param {object} data Request data
146
+ * @returns {Promise<object>} Order
147
+ *
148
+ * @example Create a new order
149
+ * ```js
150
+ * const order = await client.createOrder({
151
+ * identifiers: [
152
+ * { type: 'dns', value: 'example.com' },
153
+ * { type: 'dns', value: 'test.example.com' },
154
+ * ],
155
+ * });
156
+ * ```
157
+ */
158
+ createOrder(data: any): Promise<any>;
159
+ /**
160
+ * Refresh order object from CA
161
+ *
162
+ * https://datatracker.ietf.org/doc/html/rfc8555#section-7.4
163
+ *
164
+ * @param {object} order Order object
165
+ * @returns {Promise<object>} Order
166
+ *
167
+ * @example
168
+ * ```js
169
+ * const order = { ... }; // Previously created order object
170
+ * const result = await client.getOrder(order);
171
+ * ```
172
+ */
173
+ getOrder(order: any): Promise<any>;
174
+ /**
175
+ * Finalize order
176
+ *
177
+ * https://datatracker.ietf.org/doc/html/rfc8555#section-7.4
178
+ *
179
+ * @param {object} order Order object
180
+ * @param {buffer|string} csr PEM encoded Certificate Signing Request
181
+ * @returns {Promise<object>} Order
182
+ *
183
+ * @example Finalize order
184
+ * ```js
185
+ * const order = { ... }; // Previously created order object
186
+ * const csr = { ... }; // Previously created Certificate Signing Request
187
+ * const result = await client.finalizeOrder(order, csr);
188
+ * ```
189
+ */
190
+ finalizeOrder(order: any, csr: any): Promise<any>;
191
+ /**
192
+ * Get identifier authorizations from order
193
+ *
194
+ * https://datatracker.ietf.org/doc/html/rfc8555#section-7.5
195
+ *
196
+ * @param {object} order Order
197
+ * @returns {Promise<object[]>} Authorizations
198
+ *
199
+ * @example Get identifier authorizations
200
+ * ```js
201
+ * const order = { ... }; // Previously created order object
202
+ * const authorizations = await client.getAuthorizations(order);
203
+ *
204
+ * authorizations.forEach((authz) => {
205
+ * const { challenges } = authz;
206
+ * });
207
+ * ```
208
+ */
209
+ getAuthorizations(order: any): Promise<any[]>;
210
+ /**
211
+ * Deactivate identifier authorization
212
+ *
213
+ * https://datatracker.ietf.org/doc/html/rfc8555#section-7.5.2
214
+ *
215
+ * @param {object} authz Identifier authorization
216
+ * @returns {Promise<object>} Authorization
217
+ *
218
+ * @example Deactivate identifier authorization
219
+ * ```js
220
+ * const authz = { ... }; // Identifier authorization resolved from previously created order
221
+ * const result = await client.deactivateAuthorization(authz);
222
+ * ```
223
+ */
224
+ deactivateAuthorization(authz: any): Promise<any>;
225
+ /**
226
+ * Get key authorization for ACME challenge
227
+ *
228
+ * https://datatracker.ietf.org/doc/html/rfc8555#section-8.1
229
+ *
230
+ * @param {object} challenge Challenge object returned by API
231
+ * @returns {Promise<string>} Key authorization
232
+ *
233
+ * @example Get challenge key authorization
234
+ * ```js
235
+ * const challenge = { ... }; // Challenge from previously resolved identifier authorization
236
+ * const key = await client.getChallengeKeyAuthorization(challenge);
237
+ *
238
+ * // Write key somewhere to satisfy challenge
239
+ * ```
240
+ */
241
+ getChallengeKeyAuthorization(challenge: any): Promise<string>;
242
+ /**
243
+ * Verify that ACME challenge is satisfied
244
+ *
245
+ * @param {object} authz Identifier authorization
246
+ * @param {object} challenge Authorization challenge
247
+ * @returns {Promise}
248
+ *
249
+ * @example Verify satisfied ACME challenge
250
+ * ```js
251
+ * const authz = { ... }; // Identifier authorization
252
+ * const challenge = { ... }; // Satisfied challenge
253
+ * await client.verifyChallenge(authz, challenge);
254
+ * ```
255
+ */
256
+ verifyChallenge(authz: any, challenge: any): Promise<any>;
257
+ /**
258
+ * Notify CA that challenge has been completed
259
+ *
260
+ * https://datatracker.ietf.org/doc/html/rfc8555#section-7.5.1
261
+ *
262
+ * @param {object} challenge Challenge object returned by API
263
+ * @returns {Promise<object>} Challenge
264
+ *
265
+ * @example Notify CA that challenge has been completed
266
+ * ```js
267
+ * const challenge = { ... }; // Satisfied challenge
268
+ * const result = await client.completeChallenge(challenge);
269
+ * ```
270
+ */
271
+ completeChallenge(challenge: any): Promise<any>;
272
+ /**
273
+ * Wait for ACME provider to verify status on a order, authorization or challenge
274
+ *
275
+ * https://datatracker.ietf.org/doc/html/rfc8555#section-7.5.1
276
+ *
277
+ * @param {object} item An order, authorization or challenge object
278
+ * @returns {Promise<object>} Valid order, authorization or challenge
279
+ *
280
+ * @example Wait for valid challenge status
281
+ * ```js
282
+ * const challenge = { ... };
283
+ * await client.waitForValidStatus(challenge);
284
+ * ```
285
+ *
286
+ * @example Wait for valid authorization status
287
+ * ```js
288
+ * const authz = { ... };
289
+ * await client.waitForValidStatus(authz);
290
+ * ```
291
+ *
292
+ * @example Wait for valid order status
293
+ * ```js
294
+ * const order = { ... };
295
+ * await client.waitForValidStatus(order);
296
+ * ```
297
+ */
298
+ waitForValidStatus(item: any, d?: any): Promise<any>;
299
+ /**
300
+ * Get certificate from ACME order
301
+ *
302
+ * https://datatracker.ietf.org/doc/html/rfc8555#section-7.4.2
303
+ *
304
+ * @param {object} order Order object
305
+ * @param {string} [preferredChain] Indicate which certificate chain is preferred if a CA offers multiple, by exact issuer common name, default: `null`
306
+ * @returns {Promise<string>} Certificate
307
+ *
308
+ * @example Get certificate
309
+ * ```js
310
+ * const order = { ... }; // Previously created order
311
+ * const certificate = await client.getCertificate(order);
312
+ * ```
313
+ *
314
+ * @example Get certificate with preferred chain
315
+ * ```js
316
+ * const order = { ... }; // Previously created order
317
+ * const certificate = await client.getCertificate(order, 'DST Root CA X3');
318
+ * ```
319
+ */
320
+ getCertificate(order: any, preferredChain?: any): Promise<any>;
321
+ /**
322
+ * Revoke certificate
323
+ *
324
+ * https://datatracker.ietf.org/doc/html/rfc8555#section-7.6
325
+ *
326
+ * @param {buffer|string} cert PEM encoded certificate
327
+ * @param {object} [data] Additional request data
328
+ * @returns {Promise}
329
+ *
330
+ * @example Revoke certificate
331
+ * ```js
332
+ * const certificate = { ... }; // Previously created certificate
333
+ * const result = await client.revokeCertificate(certificate);
334
+ * ```
335
+ *
336
+ * @example Revoke certificate with reason
337
+ * ```js
338
+ * const certificate = { ... }; // Previously created certificate
339
+ * const result = await client.revokeCertificate(certificate, {
340
+ * reason: 4,
341
+ * });
342
+ * ```
343
+ */
344
+ revokeCertificate(cert: any, data?: {}): Promise<any>;
345
+ /**
346
+ * Auto mode
347
+ *
348
+ * @param {object} opts
349
+ * @param {buffer|string} opts.csr Certificate Signing Request
350
+ * @param {function} opts.challengeCreateFn Function returning Promise triggered before completing ACME challenge
351
+ * @param {function} opts.challengeRemoveFn Function returning Promise triggered after completing ACME challenge
352
+ * @param {string} [opts.email] Account email address
353
+ * @param {boolean} [opts.termsOfServiceAgreed] Agree to Terms of Service, default: `false`
354
+ * @param {boolean} [opts.skipChallengeVerification] Skip internal challenge verification before notifying ACME provider, default: `false`
355
+ * @param {string[]} [opts.challengePriority] Array defining challenge type priority, default: `['http-01', 'dns-01']`
356
+ * @param {string} [opts.preferredChain] Indicate which certificate chain is preferred if a CA offers multiple, by exact issuer common name, default: `null`
357
+ * @returns {Promise<string>} Certificate
358
+ *
359
+ * @example Order a certificate using auto mode
360
+ * ```js
361
+ * const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
362
+ * altNames: ['test.example.com'],
363
+ * });
364
+ *
365
+ * const certificate = await client.auto({
366
+ * csr: certificateRequest,
367
+ * email: 'test@example.com',
368
+ * termsOfServiceAgreed: true,
369
+ * challengeCreateFn: async (authz, challenge, keyAuthorization) => {
370
+ * // Satisfy challenge here
371
+ * },
372
+ * challengeRemoveFn: async (authz, challenge, keyAuthorization) => {
373
+ * // Clean up challenge here
374
+ * },
375
+ * });
376
+ * ```
377
+ *
378
+ * @example Order a certificate using auto mode with preferred chain
379
+ * ```js
380
+ * const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
381
+ * altNames: ['test.example.com'],
382
+ * });
383
+ *
384
+ * const certificate = await client.auto({
385
+ * csr: certificateRequest,
386
+ * email: 'test@example.com',
387
+ * termsOfServiceAgreed: true,
388
+ * preferredChain: 'DST Root CA X3',
389
+ * challengeCreateFn: async () => {},
390
+ * challengeRemoveFn: async () => {},
391
+ * });
392
+ * ```
393
+ */
394
+ auto(opts: any): Promise<any>;
395
+ }
396
+ export default AcmeClient;