@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.
- package/dist/api.d.ts +151 -0
- package/{src → dist}/api.js +2 -38
- package/dist/auto.d.ts +9 -0
- package/{src → dist}/auto.js +45 -79
- package/dist/axios.d.ts +8 -0
- package/{src → dist}/axios.js +3 -31
- package/dist/client.d.ts +396 -0
- package/{src → dist}/client.js +16 -108
- package/dist/crypto/forge.d.ts +174 -0
- package/{src → dist}/crypto/forge.js +7 -63
- package/dist/crypto/index.d.ts +215 -0
- package/{src → dist}/crypto/index.js +2 -87
- package/dist/error.d.ts +3 -0
- package/{src → dist}/error.js +1 -3
- package/dist/http.d.ts +135 -0
- package/{src → dist}/http.js +3 -65
- package/dist/index.d.ts +58 -0
- package/dist/index.js +90 -0
- package/dist/logger.d.ts +15 -0
- package/{src → dist}/logger.js +4 -9
- package/dist/rfc8555.d.ts +106 -0
- package/dist/rfc8555.js +25 -0
- package/dist/types.d.ts +117 -0
- package/dist/types.js +1 -0
- package/dist/util.d.ts +85 -0
- package/{src → dist}/util.js +11 -78
- package/dist/verify.d.ts +14 -0
- package/{src → dist}/verify.js +46 -78
- package/dist/wait.d.ts +1 -0
- package/{src → dist}/wait.js +1 -0
- package/package.json +18 -12
- package/types/index.d.ts +14 -5
- package/types/index.test-d.ts +10 -3
- package/src/index.js +0 -106
- package/src/logs/app.log +0 -0
package/{src → dist}/client.js
RENAMED
|
@@ -1,35 +1,30 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
/**
|
|
2
3
|
* ACME client
|
|
3
4
|
*
|
|
4
5
|
* @namespace Client
|
|
5
6
|
*/
|
|
6
7
|
import { createHash } from 'crypto';
|
|
7
|
-
import
|
|
8
|
+
import { getPemBodyAsB64u } from './crypto/index.js';
|
|
8
9
|
import HttpClient from './http.js';
|
|
9
10
|
import AcmeApi from './api.js';
|
|
10
|
-
import {createChallengeFn} from './verify.js';
|
|
11
|
+
import { createChallengeFn } from './verify.js';
|
|
11
12
|
import * as util from './util.js';
|
|
12
13
|
import auto from './auto.js';
|
|
13
14
|
import { CancelError } from './error.js';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
15
|
/**
|
|
18
16
|
* ACME states
|
|
19
17
|
*
|
|
20
18
|
* @private
|
|
21
19
|
*/
|
|
22
|
-
|
|
23
20
|
const validStates = ['ready', 'valid'];
|
|
24
21
|
const pendingStates = ['pending', 'processing'];
|
|
25
22
|
const invalidStates = ['invalid'];
|
|
26
|
-
|
|
27
23
|
/**
|
|
28
24
|
* Default options
|
|
29
25
|
*
|
|
30
26
|
* @private
|
|
31
27
|
*/
|
|
32
|
-
|
|
33
28
|
const defaultOpts = {
|
|
34
29
|
directoryUrl: undefined,
|
|
35
30
|
accountKey: undefined,
|
|
@@ -39,7 +34,6 @@ const defaultOpts = {
|
|
|
39
34
|
backoffMin: 5000,
|
|
40
35
|
backoffMax: 30000,
|
|
41
36
|
};
|
|
42
|
-
|
|
43
37
|
/**
|
|
44
38
|
* AcmeClient
|
|
45
39
|
*
|
|
@@ -87,33 +81,27 @@ const defaultOpts = {
|
|
|
87
81
|
* });
|
|
88
82
|
* ```
|
|
89
83
|
*/
|
|
90
|
-
|
|
91
84
|
class AcmeClient {
|
|
92
|
-
sslProvider
|
|
93
85
|
constructor(opts) {
|
|
94
86
|
if (!Buffer.isBuffer(opts.accountKey)) {
|
|
95
87
|
opts.accountKey = Buffer.from(opts.accountKey);
|
|
96
88
|
}
|
|
97
89
|
this.sslProvider = opts.sslProvider;
|
|
98
|
-
|
|
99
90
|
this.opts = { ...defaultOpts, ...opts };
|
|
100
91
|
this.backoffOpts = {
|
|
101
92
|
attempts: this.opts.backoffAttempts,
|
|
102
93
|
min: this.opts.backoffMin,
|
|
103
94
|
max: this.opts.backoffMax,
|
|
104
95
|
};
|
|
105
|
-
|
|
106
|
-
const cacheNonce = true
|
|
96
|
+
const cacheNonce = true;
|
|
107
97
|
// const cacheNonce = this.sslProvider === 'litessl';
|
|
108
98
|
this.http = new HttpClient(this.opts.directoryUrl, this.opts.accountKey, this.opts.externalAccountBinding, this.opts.urlMapping, opts.logger, cacheNonce);
|
|
109
99
|
this.api = new AcmeApi(this.http, this.opts.accountUrl);
|
|
110
100
|
this.logger = opts.logger;
|
|
111
101
|
}
|
|
112
|
-
|
|
113
102
|
log(...args) {
|
|
114
103
|
this.logger.info(...args);
|
|
115
104
|
}
|
|
116
|
-
|
|
117
105
|
/**
|
|
118
106
|
* Get Terms of Service URL if available
|
|
119
107
|
*
|
|
@@ -128,11 +116,9 @@ class AcmeClient {
|
|
|
128
116
|
* }
|
|
129
117
|
* ```
|
|
130
118
|
*/
|
|
131
|
-
|
|
132
119
|
getTermsOfServiceUrl() {
|
|
133
120
|
return this.api.getTermsOfServiceUrl();
|
|
134
121
|
}
|
|
135
|
-
|
|
136
122
|
/**
|
|
137
123
|
* Get current account URL
|
|
138
124
|
*
|
|
@@ -149,11 +135,9 @@ class AcmeClient {
|
|
|
149
135
|
* }
|
|
150
136
|
* ```
|
|
151
137
|
*/
|
|
152
|
-
|
|
153
138
|
getAccountUrl() {
|
|
154
139
|
return this.api.getAccountUrl();
|
|
155
140
|
}
|
|
156
|
-
|
|
157
141
|
/**
|
|
158
142
|
* Create a new account
|
|
159
143
|
*
|
|
@@ -177,28 +161,23 @@ class AcmeClient {
|
|
|
177
161
|
* });
|
|
178
162
|
* ```
|
|
179
163
|
*/
|
|
180
|
-
|
|
181
164
|
async createAccount(data = {}) {
|
|
182
165
|
try {
|
|
183
166
|
this.getAccountUrl();
|
|
184
|
-
|
|
185
167
|
/* Account URL exists */
|
|
186
168
|
this.log('Account URL exists, returning updateAccount()');
|
|
187
169
|
return this.updateAccount(data);
|
|
188
170
|
}
|
|
189
171
|
catch (e) {
|
|
190
172
|
const resp = await this.api.createAccount(data);
|
|
191
|
-
|
|
192
173
|
/* HTTP 200: Account exists */
|
|
193
174
|
if (resp.status === 200) {
|
|
194
175
|
this.log('Account already exists (HTTP 200), returning updateAccount()');
|
|
195
176
|
return this.updateAccount(data);
|
|
196
177
|
}
|
|
197
|
-
|
|
198
178
|
return resp.data;
|
|
199
179
|
}
|
|
200
180
|
}
|
|
201
|
-
|
|
202
181
|
/**
|
|
203
182
|
* Update existing account
|
|
204
183
|
*
|
|
@@ -214,7 +193,6 @@ class AcmeClient {
|
|
|
214
193
|
* });
|
|
215
194
|
* ```
|
|
216
195
|
*/
|
|
217
|
-
|
|
218
196
|
async updateAccount(data = {}) {
|
|
219
197
|
try {
|
|
220
198
|
this.api.getAccountUrl();
|
|
@@ -223,21 +201,17 @@ class AcmeClient {
|
|
|
223
201
|
this.log('No account URL found, returning createAccount()');
|
|
224
202
|
return this.createAccount(data);
|
|
225
203
|
}
|
|
226
|
-
|
|
227
204
|
/* Remove data only applicable to createAccount() */
|
|
228
205
|
if ('onlyReturnExisting' in data) {
|
|
229
206
|
delete data.onlyReturnExisting;
|
|
230
207
|
}
|
|
231
|
-
|
|
232
208
|
/* POST-as-GET */
|
|
233
209
|
if (Object.keys(data).length === 0) {
|
|
234
210
|
data = null;
|
|
235
211
|
}
|
|
236
|
-
|
|
237
212
|
const resp = await this.api.updateAccount(data);
|
|
238
213
|
return resp.data;
|
|
239
214
|
}
|
|
240
|
-
|
|
241
215
|
/**
|
|
242
216
|
* Update account private key
|
|
243
217
|
*
|
|
@@ -253,36 +227,27 @@ class AcmeClient {
|
|
|
253
227
|
* const result = await client.updateAccountKey(newAccountKey);
|
|
254
228
|
* ```
|
|
255
229
|
*/
|
|
256
|
-
|
|
257
230
|
async updateAccountKey(newAccountKey, data = {}) {
|
|
258
231
|
if (!Buffer.isBuffer(newAccountKey)) {
|
|
259
232
|
newAccountKey = Buffer.from(newAccountKey);
|
|
260
233
|
}
|
|
261
|
-
|
|
262
234
|
const accountUrl = this.api.getAccountUrl();
|
|
263
|
-
|
|
264
235
|
/* Create new HTTP and API clients using new key */
|
|
265
236
|
const newHttpClient = new HttpClient(this.opts.directoryUrl, newAccountKey, this.opts.externalAccountBinding);
|
|
266
237
|
const newApiClient = new AcmeApi(newHttpClient, accountUrl);
|
|
267
|
-
|
|
268
238
|
/* Get old JWK */
|
|
269
239
|
data.account = accountUrl;
|
|
270
240
|
data.oldKey = this.http.getJwk();
|
|
271
|
-
|
|
272
241
|
/* Get signed request body from new client */
|
|
273
242
|
const url = await newHttpClient.getResourceUrl('keyChange');
|
|
274
243
|
const body = newHttpClient.createSignedBody(url, data);
|
|
275
|
-
|
|
276
244
|
/* Change key using old client */
|
|
277
245
|
const resp = await this.api.updateAccountKey(body);
|
|
278
|
-
|
|
279
246
|
/* Replace existing HTTP and API client */
|
|
280
247
|
this.http = newHttpClient;
|
|
281
248
|
this.api = newApiClient;
|
|
282
|
-
|
|
283
249
|
return resp.data;
|
|
284
250
|
}
|
|
285
|
-
|
|
286
251
|
/**
|
|
287
252
|
* Create a new order
|
|
288
253
|
*
|
|
@@ -301,20 +266,15 @@ class AcmeClient {
|
|
|
301
266
|
* });
|
|
302
267
|
* ```
|
|
303
268
|
*/
|
|
304
|
-
|
|
305
269
|
async createOrder(data) {
|
|
306
270
|
const resp = await this.api.createOrder(data);
|
|
307
|
-
|
|
308
271
|
if (!resp.headers.location) {
|
|
309
272
|
throw new Error('Creating a new order did not return an order link');
|
|
310
273
|
}
|
|
311
|
-
|
|
312
274
|
/* Add URL to response */
|
|
313
275
|
resp.data.url = this.api.getLocationFromHeader(resp);
|
|
314
|
-
|
|
315
276
|
return resp.data;
|
|
316
277
|
}
|
|
317
|
-
|
|
318
278
|
/**
|
|
319
279
|
* Refresh order object from CA
|
|
320
280
|
*
|
|
@@ -329,19 +289,15 @@ class AcmeClient {
|
|
|
329
289
|
* const result = await client.getOrder(order);
|
|
330
290
|
* ```
|
|
331
291
|
*/
|
|
332
|
-
|
|
333
292
|
async getOrder(order) {
|
|
334
293
|
if (!order.url) {
|
|
335
294
|
throw new Error('Unable to get order, URL not found');
|
|
336
295
|
}
|
|
337
|
-
|
|
338
296
|
const resp = await this.api.getOrder(order.url);
|
|
339
|
-
|
|
340
297
|
/* Add URL to response */
|
|
341
298
|
resp.data.url = order.url;
|
|
342
299
|
return resp.data;
|
|
343
300
|
}
|
|
344
|
-
|
|
345
301
|
/**
|
|
346
302
|
* Finalize order
|
|
347
303
|
*
|
|
@@ -358,24 +314,19 @@ class AcmeClient {
|
|
|
358
314
|
* const result = await client.finalizeOrder(order, csr);
|
|
359
315
|
* ```
|
|
360
316
|
*/
|
|
361
|
-
|
|
362
317
|
async finalizeOrder(order, csr) {
|
|
363
318
|
if (!order.finalize) {
|
|
364
319
|
throw new Error('Unable to finalize order, URL not found');
|
|
365
320
|
}
|
|
366
|
-
|
|
367
321
|
if (!Buffer.isBuffer(csr)) {
|
|
368
322
|
csr = Buffer.from(csr);
|
|
369
323
|
}
|
|
370
|
-
|
|
371
324
|
const data = { csr: getPemBodyAsB64u(csr) };
|
|
372
325
|
const resp = await this.api.finalizeOrder(order.finalize, data);
|
|
373
|
-
|
|
374
326
|
/* Add URL to response */
|
|
375
327
|
resp.data.url = order.url;
|
|
376
328
|
return resp.data;
|
|
377
329
|
}
|
|
378
|
-
|
|
379
330
|
/**
|
|
380
331
|
* Get identifier authorizations from order
|
|
381
332
|
*
|
|
@@ -394,17 +345,14 @@ class AcmeClient {
|
|
|
394
345
|
* });
|
|
395
346
|
* ```
|
|
396
347
|
*/
|
|
397
|
-
|
|
398
348
|
async getAuthorizations(order) {
|
|
399
349
|
return Promise.all((order.authorizations || []).map(async (url) => {
|
|
400
350
|
const resp = await this.api.getAuthorization(url);
|
|
401
|
-
|
|
402
351
|
/* Add URL to response */
|
|
403
352
|
resp.data.url = url;
|
|
404
353
|
return resp.data;
|
|
405
354
|
}));
|
|
406
355
|
}
|
|
407
|
-
|
|
408
356
|
/**
|
|
409
357
|
* Deactivate identifier authorization
|
|
410
358
|
*
|
|
@@ -419,20 +367,16 @@ class AcmeClient {
|
|
|
419
367
|
* const result = await client.deactivateAuthorization(authz);
|
|
420
368
|
* ```
|
|
421
369
|
*/
|
|
422
|
-
|
|
423
370
|
async deactivateAuthorization(authz) {
|
|
424
371
|
if (!authz.url) {
|
|
425
372
|
throw new Error('Unable to deactivate identifier authorization, URL not found');
|
|
426
373
|
}
|
|
427
|
-
|
|
428
374
|
const data = { status: 'deactivated' };
|
|
429
375
|
const resp = await this.api.updateAuthorization(authz.url, data);
|
|
430
|
-
|
|
431
376
|
/* Add URL to response */
|
|
432
377
|
resp.data.url = authz.url;
|
|
433
378
|
return resp.data;
|
|
434
379
|
}
|
|
435
|
-
|
|
436
380
|
/**
|
|
437
381
|
* Get key authorization for ACME challenge
|
|
438
382
|
*
|
|
@@ -449,31 +393,25 @@ class AcmeClient {
|
|
|
449
393
|
* // Write key somewhere to satisfy challenge
|
|
450
394
|
* ```
|
|
451
395
|
*/
|
|
452
|
-
|
|
453
396
|
async getChallengeKeyAuthorization(challenge) {
|
|
454
397
|
const jwk = this.http.getJwk();
|
|
455
398
|
const keysum = createHash('sha256').update(JSON.stringify(jwk));
|
|
456
399
|
const thumbprint = keysum.digest('base64url');
|
|
457
400
|
const result = `${challenge.token}.${thumbprint}`;
|
|
458
|
-
|
|
459
401
|
/* https://datatracker.ietf.org/doc/html/rfc8555#section-8.3 */
|
|
460
402
|
if (challenge.type === 'http-01') {
|
|
461
403
|
return result;
|
|
462
404
|
}
|
|
463
|
-
|
|
464
405
|
/* https://datatracker.ietf.org/doc/html/rfc8555#section-8.4 */
|
|
465
406
|
if (challenge.type === 'dns-01') {
|
|
466
407
|
return createHash('sha256').update(result).digest('base64url');
|
|
467
408
|
}
|
|
468
|
-
|
|
469
409
|
/* https://datatracker.ietf.org/doc/html/rfc8737 */
|
|
470
410
|
if (challenge.type === 'tls-alpn-01') {
|
|
471
411
|
return result;
|
|
472
412
|
}
|
|
473
|
-
|
|
474
413
|
throw new Error(`Unable to produce key authorization, unknown challenge type: ${challenge.type}`);
|
|
475
414
|
}
|
|
476
|
-
|
|
477
415
|
/**
|
|
478
416
|
* Verify that ACME challenge is satisfied
|
|
479
417
|
*
|
|
@@ -488,21 +426,16 @@ class AcmeClient {
|
|
|
488
426
|
* await client.verifyChallenge(authz, challenge);
|
|
489
427
|
* ```
|
|
490
428
|
*/
|
|
491
|
-
|
|
492
429
|
async verifyChallenge(authz, challenge) {
|
|
493
430
|
if (!authz.url || !challenge.url) {
|
|
494
431
|
throw new Error('Unable to verify ACME challenge, URL not found');
|
|
495
432
|
}
|
|
496
|
-
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
const verify = challenges
|
|
433
|
+
const { challenges } = createChallengeFn({ logger: this.logger, walkFromAuthoritative: this.opts.walkFromAuthoritative });
|
|
434
|
+
const verify = challenges;
|
|
500
435
|
if (typeof verify[challenge.type] === 'undefined') {
|
|
501
436
|
throw new Error(`Unable to verify ACME challenge, unknown type: ${challenge.type}`);
|
|
502
437
|
}
|
|
503
|
-
|
|
504
438
|
const keyAuthorization = await this.getChallengeKeyAuthorization(challenge);
|
|
505
|
-
|
|
506
439
|
const verifyFn = async (abort) => {
|
|
507
440
|
if (this.opts.signal && this.opts.signal.aborted) {
|
|
508
441
|
abort();
|
|
@@ -510,16 +443,12 @@ class AcmeClient {
|
|
|
510
443
|
}
|
|
511
444
|
await verify[challenge.type](authz, challenge, keyAuthorization);
|
|
512
445
|
};
|
|
513
|
-
|
|
514
446
|
this.log('Waiting for ACME challenge verification(等待ACME检查验证)');
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
}
|
|
520
|
-
return util.retry(verifyFn, this.backoffOpts,log);
|
|
447
|
+
const log = (...args) => {
|
|
448
|
+
this.logger.info(...args);
|
|
449
|
+
};
|
|
450
|
+
return util.retry(verifyFn, this.backoffOpts, log);
|
|
521
451
|
}
|
|
522
|
-
|
|
523
452
|
/**
|
|
524
453
|
* Notify CA that challenge has been completed
|
|
525
454
|
*
|
|
@@ -534,7 +463,6 @@ class AcmeClient {
|
|
|
534
463
|
* const result = await client.completeChallenge(challenge);
|
|
535
464
|
* ```
|
|
536
465
|
*/
|
|
537
|
-
|
|
538
466
|
async completeChallenge(challenge) {
|
|
539
467
|
if (this.opts.signal && this.opts.signal.aborted) {
|
|
540
468
|
throw new CancelError('用户取消');
|
|
@@ -542,7 +470,6 @@ class AcmeClient {
|
|
|
542
470
|
const resp = await this.api.completeChallenge(challenge.url, {});
|
|
543
471
|
return resp.data;
|
|
544
472
|
}
|
|
545
|
-
|
|
546
473
|
/**
|
|
547
474
|
* Wait for ACME provider to verify status on a order, authorization or challenge
|
|
548
475
|
*
|
|
@@ -569,23 +496,18 @@ class AcmeClient {
|
|
|
569
496
|
* await client.waitForValidStatus(order);
|
|
570
497
|
* ```
|
|
571
498
|
*/
|
|
572
|
-
|
|
573
|
-
async waitForValidStatus(item,d) {
|
|
499
|
+
async waitForValidStatus(item, d) {
|
|
574
500
|
if (!item.url) {
|
|
575
501
|
throw new Error(`[${d}] Unable to verify status of item, URL not found`);
|
|
576
502
|
}
|
|
577
|
-
|
|
578
503
|
const verifyFn = async (abort) => {
|
|
579
504
|
if (this.opts.signal && this.opts.signal.aborted) {
|
|
580
505
|
abort(true);
|
|
581
506
|
throw new CancelError('用户取消');
|
|
582
507
|
}
|
|
583
|
-
|
|
584
508
|
const resp = await this.api.apiRequest(item.url, null, [200]);
|
|
585
|
-
|
|
586
509
|
/* Verify status */
|
|
587
510
|
this.log(`[${d}] Item has status(检查状态): ${resp.data.status}`);
|
|
588
|
-
|
|
589
511
|
if (invalidStates.includes(resp.data.status)) {
|
|
590
512
|
abort();
|
|
591
513
|
this.log(`[${d}] : 检查状态 = ${resp.data.status} : ${JSON.stringify(resp.data)}`);
|
|
@@ -597,17 +519,14 @@ class AcmeClient {
|
|
|
597
519
|
else if (validStates.includes(resp.data.status)) {
|
|
598
520
|
return resp.data;
|
|
599
521
|
}
|
|
600
|
-
|
|
601
522
|
throw new Error(`[${d}] Unexpected item status: ${resp.data.status}`);
|
|
602
523
|
};
|
|
603
|
-
|
|
604
524
|
this.log(`[${d}] Waiting for valid status (等待valid状态): ${item.url}`, JSON.stringify(this.backoffOpts));
|
|
605
|
-
const log = (...args)=>{
|
|
606
|
-
this.logger.info(...args)
|
|
607
|
-
}
|
|
608
|
-
return util.retry(verifyFn, this.backoffOpts,log);
|
|
525
|
+
const log = (...args) => {
|
|
526
|
+
this.logger.info(...args);
|
|
527
|
+
};
|
|
528
|
+
return util.retry(verifyFn, this.backoffOpts, log);
|
|
609
529
|
}
|
|
610
|
-
|
|
611
530
|
/**
|
|
612
531
|
* Get certificate from ACME order
|
|
613
532
|
*
|
|
@@ -629,31 +548,24 @@ class AcmeClient {
|
|
|
629
548
|
* const certificate = await client.getCertificate(order, 'DST Root CA X3');
|
|
630
549
|
* ```
|
|
631
550
|
*/
|
|
632
|
-
|
|
633
551
|
async getCertificate(order, preferredChain = null) {
|
|
634
552
|
if (!validStates.includes(order.status)) {
|
|
635
553
|
order = await this.waitForValidStatus(order);
|
|
636
554
|
}
|
|
637
|
-
|
|
638
555
|
if (!order.certificate) {
|
|
639
556
|
throw new Error('Unable to download certificate, URL not found');
|
|
640
557
|
}
|
|
641
|
-
|
|
642
558
|
const resp = await this.api.apiRequest(order.certificate, null, [200]);
|
|
643
|
-
|
|
644
559
|
/* Handle alternate certificate chains */
|
|
645
560
|
if (preferredChain && resp.headers.link) {
|
|
646
561
|
const alternateLinks = util.parseLinkHeader(resp.headers.link);
|
|
647
562
|
const alternates = await Promise.all(alternateLinks.map(async (link) => this.api.apiRequest(link, null, [200])));
|
|
648
563
|
const certificates = [resp].concat(alternates).map((c) => c.data);
|
|
649
|
-
|
|
650
564
|
return util.findCertificateChainForIssuer(certificates, preferredChain);
|
|
651
565
|
}
|
|
652
|
-
|
|
653
566
|
/* Return default certificate chain */
|
|
654
567
|
return resp.data;
|
|
655
568
|
}
|
|
656
|
-
|
|
657
569
|
/**
|
|
658
570
|
* Revoke certificate
|
|
659
571
|
*
|
|
@@ -677,13 +589,11 @@ class AcmeClient {
|
|
|
677
589
|
* });
|
|
678
590
|
* ```
|
|
679
591
|
*/
|
|
680
|
-
|
|
681
592
|
async revokeCertificate(cert, data = {}) {
|
|
682
593
|
data.certificate = getPemBodyAsB64u(cert);
|
|
683
594
|
const resp = await this.api.revokeCert(data);
|
|
684
595
|
return resp.data;
|
|
685
596
|
}
|
|
686
|
-
|
|
687
597
|
/**
|
|
688
598
|
* Auto mode
|
|
689
599
|
*
|
|
@@ -733,11 +643,9 @@ class AcmeClient {
|
|
|
733
643
|
* });
|
|
734
644
|
* ```
|
|
735
645
|
*/
|
|
736
|
-
|
|
737
646
|
auto(opts) {
|
|
738
647
|
return auto(this, opts);
|
|
739
648
|
}
|
|
740
649
|
}
|
|
741
|
-
|
|
742
650
|
/* Export client */
|
|
743
|
-
export default
|
|
651
|
+
export default AcmeClient;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a private RSA key
|
|
3
|
+
*
|
|
4
|
+
* @param {number} [size] Size of the key, default: `2048`
|
|
5
|
+
* @returns {Promise<buffer>} PEM encoded private RSA key
|
|
6
|
+
*
|
|
7
|
+
* @example Generate private RSA key
|
|
8
|
+
* ```js
|
|
9
|
+
* const privateKey = await acme.forge.createPrivateKey();
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* @example Private RSA key with defined size
|
|
13
|
+
* ```js
|
|
14
|
+
* const privateKey = await acme.forge.createPrivateKey(4096);
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function createPrivateKey(size?: number): Promise<Buffer>;
|
|
18
|
+
/**
|
|
19
|
+
* Create public key from a private RSA key
|
|
20
|
+
*
|
|
21
|
+
* @param {buffer|string} key PEM encoded private RSA key
|
|
22
|
+
* @returns {Promise<buffer>} PEM encoded public RSA key
|
|
23
|
+
*
|
|
24
|
+
* @example Create public key
|
|
25
|
+
* ```js
|
|
26
|
+
* const publicKey = await acme.forge.createPublicKey(privateKey);
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare const createPublicKey: (key: any) => Promise<Buffer>;
|
|
30
|
+
/**
|
|
31
|
+
* Parse body of PEM encoded object from buffer or string
|
|
32
|
+
* If multiple objects are chained, the first body will be returned
|
|
33
|
+
*
|
|
34
|
+
* @param {buffer|string} str PEM encoded buffer or string
|
|
35
|
+
* @returns {string} PEM body
|
|
36
|
+
*/
|
|
37
|
+
export declare const getPemBody: (str: any) => any;
|
|
38
|
+
/**
|
|
39
|
+
* Split chain of PEM encoded objects from buffer or string into array
|
|
40
|
+
*
|
|
41
|
+
* @param {buffer|string} str PEM encoded buffer or string
|
|
42
|
+
* @returns {string[]} Array of PEM bodies
|
|
43
|
+
*/
|
|
44
|
+
export declare const splitPemChain: (str: any) => any;
|
|
45
|
+
/**
|
|
46
|
+
* Get modulus
|
|
47
|
+
*
|
|
48
|
+
* @param {buffer|string} input PEM encoded private key, certificate or CSR
|
|
49
|
+
* @returns {Promise<buffer>} Modulus
|
|
50
|
+
*
|
|
51
|
+
* @example Get modulus
|
|
52
|
+
* ```js
|
|
53
|
+
* const m1 = await acme.forge.getModulus(privateKey);
|
|
54
|
+
* const m2 = await acme.forge.getModulus(certificate);
|
|
55
|
+
* const m3 = await acme.forge.getModulus(certificateRequest);
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare const getModulus: (input: any) => Promise<Buffer>;
|
|
59
|
+
/**
|
|
60
|
+
* Get public exponent
|
|
61
|
+
*
|
|
62
|
+
* @param {buffer|string} input PEM encoded private key, certificate or CSR
|
|
63
|
+
* @returns {Promise<buffer>} Exponent
|
|
64
|
+
*
|
|
65
|
+
* @example Get public exponent
|
|
66
|
+
* ```js
|
|
67
|
+
* const e1 = await acme.forge.getPublicExponent(privateKey);
|
|
68
|
+
* const e2 = await acme.forge.getPublicExponent(certificate);
|
|
69
|
+
* const e3 = await acme.forge.getPublicExponent(certificateRequest);
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export declare const getPublicExponent: (input: any) => Promise<Buffer>;
|
|
73
|
+
/**
|
|
74
|
+
* Read domains from a Certificate Signing Request
|
|
75
|
+
*
|
|
76
|
+
* @param {buffer|string} csr PEM encoded Certificate Signing Request
|
|
77
|
+
* @returns {Promise<object>} {commonName, altNames}
|
|
78
|
+
*
|
|
79
|
+
* @example Read Certificate Signing Request domains
|
|
80
|
+
* ```js
|
|
81
|
+
* const { commonName, altNames } = await acme.forge.readCsrDomains(certificateRequest);
|
|
82
|
+
*
|
|
83
|
+
* console.log(`Common name: ${commonName}`);
|
|
84
|
+
* console.log(`Alt names: ${altNames.join(', ')}`);
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export declare const readCsrDomains: (csr: any) => Promise<{
|
|
88
|
+
commonName: any;
|
|
89
|
+
altNames: any[];
|
|
90
|
+
}>;
|
|
91
|
+
/**
|
|
92
|
+
* Read information from a certificate
|
|
93
|
+
*
|
|
94
|
+
* @param {buffer|string} cert PEM encoded certificate
|
|
95
|
+
* @returns {Promise<object>} Certificate info
|
|
96
|
+
*
|
|
97
|
+
* @example Read certificate information
|
|
98
|
+
* ```js
|
|
99
|
+
* const info = await acme.forge.readCertificateInfo(certificate);
|
|
100
|
+
* const { commonName, altNames } = info.domains;
|
|
101
|
+
*
|
|
102
|
+
* console.log(`Not after: ${info.notAfter}`);
|
|
103
|
+
* console.log(`Not before: ${info.notBefore}`);
|
|
104
|
+
*
|
|
105
|
+
* console.log(`Common name: ${commonName}`);
|
|
106
|
+
* console.log(`Alt names: ${altNames.join(', ')}`);
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export declare const readCertificateInfo: (cert: any) => Promise<{
|
|
110
|
+
issuer: {
|
|
111
|
+
commonName: any;
|
|
112
|
+
};
|
|
113
|
+
domains: {
|
|
114
|
+
commonName: any;
|
|
115
|
+
altNames: any[];
|
|
116
|
+
};
|
|
117
|
+
notAfter: any;
|
|
118
|
+
notBefore: any;
|
|
119
|
+
}>;
|
|
120
|
+
/**
|
|
121
|
+
* Create a Certificate Signing Request
|
|
122
|
+
*
|
|
123
|
+
* @param {object} data
|
|
124
|
+
* @param {number} [data.keySize] Size of newly created private key, default: `2048`
|
|
125
|
+
* @param {string} [data.commonName]
|
|
126
|
+
* @param {string[]} [data.altNames] default: `[]`
|
|
127
|
+
* @param {string} [data.country]
|
|
128
|
+
* @param {string} [data.state]
|
|
129
|
+
* @param {string} [data.locality]
|
|
130
|
+
* @param {string} [data.organization]
|
|
131
|
+
* @param {string} [data.organizationUnit]
|
|
132
|
+
* @param {string} [data.emailAddress]
|
|
133
|
+
* @param {buffer|string} [key] CSR private key
|
|
134
|
+
* @returns {Promise<buffer[]>} [privateKey, certificateSigningRequest]
|
|
135
|
+
*
|
|
136
|
+
* @example Create a Certificate Signing Request
|
|
137
|
+
* ```js
|
|
138
|
+
* const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
|
139
|
+
* altNames: ['test.example.com'],
|
|
140
|
+
* });
|
|
141
|
+
* ```
|
|
142
|
+
*
|
|
143
|
+
* @example Certificate Signing Request with both common and alternative names
|
|
144
|
+
* > *Warning*: Certificate subject common name has been [deprecated](https://letsencrypt.org/docs/glossary/#def-CN) and its use is [discouraged](https://cabforum.org/uploads/BRv1.2.3.pdf).
|
|
145
|
+
* ```js
|
|
146
|
+
* const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
|
147
|
+
* keySize: 4096,
|
|
148
|
+
* commonName: 'test.example.com',
|
|
149
|
+
* altNames: ['foo.example.com', 'bar.example.com'],
|
|
150
|
+
* });
|
|
151
|
+
* ```
|
|
152
|
+
*
|
|
153
|
+
* @example Certificate Signing Request with additional information
|
|
154
|
+
* ```js
|
|
155
|
+
* const [certificateKey, certificateRequest] = await acme.forge.createCsr({
|
|
156
|
+
* altNames: ['test.example.com'],
|
|
157
|
+
* country: 'US',
|
|
158
|
+
* state: 'California',
|
|
159
|
+
* locality: 'Los Angeles',
|
|
160
|
+
* organization: 'The Company Inc.',
|
|
161
|
+
* organizationUnit: 'IT Department',
|
|
162
|
+
* emailAddress: 'contact@example.com',
|
|
163
|
+
* });
|
|
164
|
+
* ```
|
|
165
|
+
*
|
|
166
|
+
* @example Certificate Signing Request with predefined private key
|
|
167
|
+
* ```js
|
|
168
|
+
* const certificateKey = await acme.forge.createPrivateKey();
|
|
169
|
+
*
|
|
170
|
+
* const [, certificateRequest] = await acme.forge.createCsr({
|
|
171
|
+
* altNames: ['test.example.com'],
|
|
172
|
+
* }, certificateKey);
|
|
173
|
+
*/
|
|
174
|
+
export declare const createCsr: (data: any, keyType?: any) => Promise<any[]>;
|