@rushstack/debug-certificate-manager 1.6.14 → 1.7.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/CHANGELOG.json CHANGED
@@ -1,6 +1,29 @@
1
1
  {
2
2
  "name": "@rushstack/debug-certificate-manager",
3
3
  "entries": [
4
+ {
5
+ "version": "1.7.0",
6
+ "tag": "@rushstack/debug-certificate-manager_v1.7.0",
7
+ "date": "Thu, 19 Feb 2026 00:04:52 GMT",
8
+ "comments": {
9
+ "minor": [
10
+ {
11
+ "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`."
12
+ }
13
+ ],
14
+ "dependency": [
15
+ {
16
+ "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`"
17
+ },
18
+ {
19
+ "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`"
20
+ },
21
+ {
22
+ "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`"
23
+ }
24
+ ]
25
+ }
26
+ },
4
27
  {
5
28
  "version": "1.6.14",
6
29
  "tag": "@rushstack/debug-certificate-manager_v1.6.14",
package/CHANGELOG.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # Change Log - @rushstack/debug-certificate-manager
2
2
 
3
- This log was last generated on Sat, 07 Feb 2026 01:13:26 GMT and should not be manually modified.
3
+ This log was last generated on Thu, 19 Feb 2026 00:04:52 GMT and should not be manually modified.
4
+
5
+ ## 1.7.0
6
+ Thu, 19 Feb 2026 00:04:52 GMT
7
+
8
+ ### Minor changes
9
+
10
+ - Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`.
4
11
 
5
12
  ## 1.6.14
6
13
  Sat, 07 Feb 2026 01:13:26 GMT
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.56.2"
8
+ "packageVersion": "7.56.3"
9
9
  }
10
10
  ]
11
11
  }
@@ -0,0 +1,600 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2
+ // See LICENSE in the project root for license information.
3
+ import * as path from 'node:path';
4
+ import { EOL } from 'node:os';
5
+ import { FileSystem } from '@rushstack/node-core-library';
6
+ import { darwinRunSudoAsync, randomTmpPath, runAsync } from './runCommand';
7
+ import { CertificateStore } from './CertificateStore';
8
+ const CA_SERIAL_NUMBER = '731c321744e34650a202e3ef91c3c1b0';
9
+ const TLS_SERIAL_NUMBER = '731c321744e34650a202e3ef00000001';
10
+ const FRIENDLY_NAME = 'debug-certificate-manager Development Certificate';
11
+ const MAC_KEYCHAIN = '/Library/Keychains/System.keychain';
12
+ const CERTUTIL_EXE_NAME = 'certutil';
13
+ const CA_ALT_NAME = 'rushstack-certificate-manager.localhost';
14
+ const ONE_DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
15
+ /**
16
+ * The set of names the certificate should be generated for, by default.
17
+ * @public
18
+ */
19
+ export const DEFAULT_CERTIFICATE_SUBJECT_NAMES = ['localhost'];
20
+ /**
21
+ * The set of ip addresses the certificate should be generated for, by default.
22
+ * @public
23
+ */
24
+ export const DEFAULT_CERTIFICATE_SUBJECT_IP_ADDRESSES = ['127.0.0.1', '::1'];
25
+ const DISABLE_CERT_GENERATION_VARIABLE_NAME = 'RUSHSTACK_DISABLE_DEV_CERT_GENERATION';
26
+ const MAX_CERTIFICATE_VALIDITY_DAYS = 365;
27
+ const VS_CODE_EXTENSION_FIX_MESSAGE = 'Use the "Debug Certificate Manager" Extension for VS Code (ms-RushStack.debug-certificate-manager) and run the ' +
28
+ '"Debug Certificate Manager: Ensure and Sync TLS Certificates" command to fix certificate issues. ';
29
+ /**
30
+ * A utility class to handle generating, trusting, and untrustring a debug certificate.
31
+ * Contains two public methods to `ensureCertificate` and `untrustCertificate`.
32
+ * @public
33
+ */
34
+ export class CertificateManager {
35
+ constructor(options = {}) {
36
+ this.certificateStore = new CertificateStore(options);
37
+ }
38
+ /**
39
+ * Get a development certificate from the store, or optionally, generate a new one
40
+ * and trust it if one doesn't exist in the store.
41
+ *
42
+ * @public
43
+ */
44
+ async ensureCertificateAsync(canGenerateNewCertificate, terminal, options) {
45
+ const optionsWithDefaults = applyDefaultOptions(options);
46
+ if (process.env[DISABLE_CERT_GENERATION_VARIABLE_NAME] === '1') {
47
+ // Allow the environment (e.g. GitHub codespaces) to forcibly disable dev cert generation
48
+ terminal.writeLine(`Found environment variable ${DISABLE_CERT_GENERATION_VARIABLE_NAME}=1, disabling certificate generation. ` +
49
+ VS_CODE_EXTENSION_FIX_MESSAGE);
50
+ canGenerateNewCertificate = false;
51
+ }
52
+ // Validate existing certificates
53
+ const validationResult = await this.validateCertificateAsync(terminal, options);
54
+ if (validationResult.isValid && validationResult.certificate) {
55
+ // Existing certificate is valid, return it
56
+ return validationResult.certificate;
57
+ }
58
+ // Certificate is invalid or doesn't exist
59
+ if (validationResult.validationMessages.length > 0) {
60
+ if (canGenerateNewCertificate) {
61
+ validationResult.validationMessages.push('Attempting to untrust the certificate and generate a new one.');
62
+ terminal.writeWarningLine(validationResult.validationMessages.join(' '));
63
+ if (!(options === null || options === void 0 ? void 0 : options.skipCertificateTrust)) {
64
+ await this.untrustCertificateAsync(terminal);
65
+ }
66
+ return await this._ensureCertificateInternalAsync(optionsWithDefaults, terminal);
67
+ }
68
+ else {
69
+ validationResult.validationMessages.push('Untrust the certificate and generate a new one, or set the ' +
70
+ '`canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`. ' +
71
+ VS_CODE_EXTENSION_FIX_MESSAGE);
72
+ throw new Error(validationResult.validationMessages.join(' '));
73
+ }
74
+ }
75
+ else if (canGenerateNewCertificate) {
76
+ return await this._ensureCertificateInternalAsync(optionsWithDefaults, terminal);
77
+ }
78
+ else {
79
+ throw new Error('No development certificate found. Generate a new certificate manually, or set the ' +
80
+ '`canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`. ' +
81
+ VS_CODE_EXTENSION_FIX_MESSAGE);
82
+ }
83
+ }
84
+ /**
85
+ * Attempt to locate a previously generated debug certificate and untrust it.
86
+ *
87
+ * @public
88
+ */
89
+ async untrustCertificateAsync(terminal) {
90
+ this.certificateStore.certificateData = undefined;
91
+ this.certificateStore.keyData = undefined;
92
+ this.certificateStore.caCertificateData = undefined;
93
+ switch (process.platform) {
94
+ case 'win32':
95
+ const winUntrustResult = await runAsync(CERTUTIL_EXE_NAME, [
96
+ '-user',
97
+ '-delstore',
98
+ 'root',
99
+ CA_SERIAL_NUMBER
100
+ ]);
101
+ if (winUntrustResult.exitCode !== 0) {
102
+ terminal.writeErrorLine(`Error: ${winUntrustResult.stderr.join(' ')}`);
103
+ return false;
104
+ }
105
+ else {
106
+ terminal.writeVerboseLine('Successfully untrusted development certificate.');
107
+ return true;
108
+ }
109
+ case 'darwin':
110
+ terminal.writeVerboseLine('Trying to find the signature of the development certificate.');
111
+ const macFindCertificateResult = await runAsync('security', [
112
+ 'find-certificate',
113
+ '-c',
114
+ CA_ALT_NAME,
115
+ '-a',
116
+ '-Z',
117
+ MAC_KEYCHAIN
118
+ ]);
119
+ if (macFindCertificateResult.exitCode !== 0) {
120
+ terminal.writeErrorLine(`Error finding the development certificate: ${macFindCertificateResult.stderr.join(' ')}`);
121
+ return false;
122
+ }
123
+ const shaHash = this._parseMacOsMatchingCertificateHash(macFindCertificateResult.stdout.join(EOL));
124
+ if (!shaHash) {
125
+ terminal.writeErrorLine('Unable to find the development certificate.');
126
+ return false;
127
+ }
128
+ else {
129
+ terminal.writeVerboseLine(`Found the development certificate. SHA is ${shaHash}`);
130
+ }
131
+ const macUntrustResult = await darwinRunSudoAsync(terminal, 'security', [
132
+ 'delete-certificate',
133
+ '-Z',
134
+ shaHash,
135
+ MAC_KEYCHAIN
136
+ ]);
137
+ if (macUntrustResult.exitCode === 0) {
138
+ terminal.writeVerboseLine('Successfully untrusted development certificate.');
139
+ return true;
140
+ }
141
+ else {
142
+ terminal.writeErrorLine(macUntrustResult.stderr.join(' '));
143
+ return false;
144
+ }
145
+ default:
146
+ // Linux + others: Have the user manually untrust the cert
147
+ terminal.writeLine('Automatic certificate untrust is only implemented for debug-certificate-manager on Windows ' +
148
+ 'and macOS. To untrust the development certificate, remove this certificate from your trusted ' +
149
+ `root certification authorities: "${this.certificateStore.certificatePath}". The ` +
150
+ `certificate has serial number "${CA_SERIAL_NUMBER}".`);
151
+ return false;
152
+ }
153
+ }
154
+ async _createCACertificateAsync(validityInDays, forge) {
155
+ const keys = forge.pki.rsa.generateKeyPair(2048);
156
+ const certificate = forge.pki.createCertificate();
157
+ certificate.publicKey = keys.publicKey;
158
+ certificate.serialNumber = CA_SERIAL_NUMBER;
159
+ const notBefore = new Date();
160
+ const notAfter = new Date(notBefore);
161
+ notAfter.setUTCDate(notBefore.getUTCDate() + validityInDays);
162
+ certificate.validity.notBefore = notBefore;
163
+ certificate.validity.notAfter = notAfter;
164
+ const attrs = [
165
+ {
166
+ name: 'commonName',
167
+ value: CA_ALT_NAME
168
+ }
169
+ ];
170
+ certificate.setSubject(attrs);
171
+ certificate.setIssuer(attrs);
172
+ const altNames = [
173
+ {
174
+ type: 2, // DNS
175
+ value: CA_ALT_NAME
176
+ }
177
+ ];
178
+ certificate.setExtensions([
179
+ {
180
+ name: 'basicConstraints',
181
+ cA: true,
182
+ pathLenConstraint: 0,
183
+ critical: true
184
+ },
185
+ {
186
+ name: 'subjectAltName',
187
+ altNames,
188
+ critical: true
189
+ },
190
+ {
191
+ name: 'issuerAltName',
192
+ altNames,
193
+ critical: false
194
+ },
195
+ {
196
+ name: 'keyUsage',
197
+ keyCertSign: true,
198
+ critical: true
199
+ },
200
+ {
201
+ name: 'extKeyUsage',
202
+ serverAuth: true,
203
+ critical: true
204
+ },
205
+ {
206
+ name: 'friendlyName',
207
+ value: FRIENDLY_NAME
208
+ }
209
+ ]);
210
+ // self-sign certificate
211
+ certificate.sign(keys.privateKey, forge.md.sha256.create());
212
+ return {
213
+ certificate,
214
+ privateKey: keys.privateKey
215
+ };
216
+ }
217
+ async _createDevelopmentCertificateAsync(options) {
218
+ const forge = await import('node-forge');
219
+ const keys = forge.pki.rsa.generateKeyPair(2048);
220
+ const certificate = forge.pki.createCertificate();
221
+ certificate.publicKey = keys.publicKey;
222
+ certificate.serialNumber = TLS_SERIAL_NUMBER;
223
+ const { subjectAltNames: subjectNames, subjectIPAddresses: subjectIpAddresses, validityInDays } = options;
224
+ const { certificate: caCertificate, privateKey: caPrivateKey } = await this._createCACertificateAsync(validityInDays, forge);
225
+ const notBefore = new Date();
226
+ const notAfter = new Date(notBefore);
227
+ notAfter.setUTCDate(notBefore.getUTCDate() + validityInDays);
228
+ certificate.validity.notBefore = notBefore;
229
+ certificate.validity.notAfter = notAfter;
230
+ const subjectAttrs = [
231
+ {
232
+ name: 'commonName',
233
+ value: subjectNames[0]
234
+ }
235
+ ];
236
+ const issuerAttrs = caCertificate.subject.attributes;
237
+ certificate.setSubject(subjectAttrs);
238
+ certificate.setIssuer(issuerAttrs);
239
+ const subjectAltNames = [
240
+ ...subjectNames.map((subjectName) => ({
241
+ type: 2, // DNS
242
+ value: subjectName
243
+ })),
244
+ ...subjectIpAddresses.map((ip) => ({
245
+ type: 7, // IP
246
+ ip
247
+ }))
248
+ ];
249
+ const issuerAltNames = [
250
+ {
251
+ type: 2, // DNS
252
+ value: CA_ALT_NAME
253
+ }
254
+ ];
255
+ certificate.setExtensions([
256
+ {
257
+ name: 'basicConstraints',
258
+ cA: false,
259
+ critical: true
260
+ },
261
+ {
262
+ name: 'subjectAltName',
263
+ altNames: subjectAltNames,
264
+ critical: true
265
+ },
266
+ {
267
+ name: 'issuerAltName',
268
+ altNames: issuerAltNames,
269
+ critical: false
270
+ },
271
+ {
272
+ name: 'keyUsage',
273
+ digitalSignature: true,
274
+ keyEncipherment: true,
275
+ dataEncipherment: true,
276
+ critical: true
277
+ },
278
+ {
279
+ name: 'extKeyUsage',
280
+ serverAuth: true,
281
+ critical: true
282
+ },
283
+ {
284
+ name: 'friendlyName',
285
+ value: FRIENDLY_NAME
286
+ }
287
+ ]);
288
+ // Sign certificate with CA
289
+ certificate.sign(caPrivateKey, forge.md.sha256.create());
290
+ // convert a Forge certificate to PEM
291
+ const caPem = forge.pki.certificateToPem(caCertificate);
292
+ const pem = forge.pki.certificateToPem(certificate);
293
+ const pemKey = forge.pki.privateKeyToPem(keys.privateKey);
294
+ return {
295
+ pemCaCertificate: caPem,
296
+ pemCertificate: pem,
297
+ pemKey: pemKey,
298
+ subjectAltNames: options.subjectAltNames
299
+ };
300
+ }
301
+ async _tryTrustCertificateAsync(certificatePath, terminal) {
302
+ switch (process.platform) {
303
+ case 'win32':
304
+ terminal.writeLine('Attempting to trust a development certificate. This self-signed certificate only points to localhost ' +
305
+ 'and will be stored in your local user profile to be used by other instances of ' +
306
+ 'debug-certificate-manager. If you do not consent to trust this certificate, click "NO" in the dialog.');
307
+ const winTrustResult = await runAsync(CERTUTIL_EXE_NAME, [
308
+ '-user',
309
+ '-addstore',
310
+ 'root',
311
+ certificatePath
312
+ ]);
313
+ if (winTrustResult.exitCode !== 0) {
314
+ terminal.writeErrorLine(`Error: ${winTrustResult.stdout.toString()}`);
315
+ const errorLines = winTrustResult.stdout
316
+ .toString()
317
+ .split(EOL)
318
+ .map((line) => line.trim());
319
+ // Not sure if this is always the status code for "cancelled" - should confirm.
320
+ if (winTrustResult.exitCode === 2147943623 ||
321
+ errorLines[errorLines.length - 1].indexOf('The operation was canceled by the user.') > 0) {
322
+ terminal.writeLine('Certificate trust cancelled.');
323
+ }
324
+ else {
325
+ terminal.writeErrorLine('Certificate trust failed with an unknown error.');
326
+ }
327
+ return false;
328
+ }
329
+ else {
330
+ terminal.writeVerboseLine('Successfully trusted development certificate.');
331
+ return true;
332
+ }
333
+ case 'darwin':
334
+ terminal.writeLine('Attempting to trust a development certificate. This self-signed certificate only points to localhost ' +
335
+ 'and will be stored in your local user profile to be used by other instances of ' +
336
+ 'debug-certificate-manager. If you do not consent to trust this certificate, do not enter your ' +
337
+ 'root password in the prompt.');
338
+ const result = await darwinRunSudoAsync(terminal, 'security', [
339
+ 'add-trusted-cert',
340
+ '-d',
341
+ '-r',
342
+ 'trustRoot',
343
+ '-k',
344
+ MAC_KEYCHAIN,
345
+ certificatePath
346
+ ]);
347
+ if (result.exitCode === 0) {
348
+ terminal.writeVerboseLine('Successfully trusted development certificate.');
349
+ return true;
350
+ }
351
+ else {
352
+ if (result.stderr.some((value) => !!value.match(/The authorization was cancelled by the user\./))) {
353
+ terminal.writeLine('Certificate trust cancelled.');
354
+ return false;
355
+ }
356
+ else {
357
+ terminal.writeErrorLine(`Certificate trust failed with an unknown error. Exit code: ${result.exitCode}. ` +
358
+ `Error: ${result.stderr.join(' ')}`);
359
+ return false;
360
+ }
361
+ }
362
+ default:
363
+ // Linux + others: Have the user manually trust the cert if they want to
364
+ terminal.writeLine('Automatic certificate trust is only implemented for debug-certificate-manager on Windows ' +
365
+ 'and macOS. To trust the development certificate, add this certificate to your trusted root ' +
366
+ `certification authorities: "${certificatePath}".`);
367
+ return true;
368
+ }
369
+ }
370
+ async _detectIfCertificateIsTrustedAsync(terminal) {
371
+ switch (process.platform) {
372
+ case 'win32':
373
+ const winVerifyStoreResult = await runAsync(CERTUTIL_EXE_NAME, [
374
+ '-user',
375
+ '-verifystore',
376
+ 'root',
377
+ CA_SERIAL_NUMBER
378
+ ]);
379
+ if (winVerifyStoreResult.exitCode !== 0) {
380
+ terminal.writeVerboseLine('The development certificate was not found in the store. CertUtil error: ', winVerifyStoreResult.stderr.join(' '));
381
+ return false;
382
+ }
383
+ else {
384
+ terminal.writeVerboseLine('The development certificate was found in the store. CertUtil output: ', winVerifyStoreResult.stdout.join(' '));
385
+ return true;
386
+ }
387
+ case 'darwin':
388
+ terminal.writeVerboseLine('Trying to find the signature of the development certificate.');
389
+ const macFindCertificateResult = await runAsync('security', [
390
+ 'find-certificate',
391
+ '-c',
392
+ CA_ALT_NAME,
393
+ '-a',
394
+ '-Z',
395
+ MAC_KEYCHAIN
396
+ ]);
397
+ if (macFindCertificateResult.exitCode !== 0) {
398
+ terminal.writeVerboseLine('The development certificate was not found in keychain. Find certificate error: ', macFindCertificateResult.stderr.join(' '));
399
+ return false;
400
+ }
401
+ const shaHash = this._parseMacOsMatchingCertificateHash(macFindCertificateResult.stdout.join(EOL));
402
+ if (!shaHash) {
403
+ terminal.writeVerboseLine('The development certificate was not found in keychain. Find certificate output:\n', macFindCertificateResult.stdout.join(' '));
404
+ return false;
405
+ }
406
+ terminal.writeVerboseLine(`The development certificate was found in keychain.`);
407
+ return true;
408
+ default:
409
+ // Linux + others: Have the user manually verify the cert is trusted
410
+ terminal.writeVerboseLine('Automatic certificate trust validation is only implemented for debug-certificate-manager on Windows ' +
411
+ 'and macOS. Manually verify this development certificate is present in your trusted ' +
412
+ `root certification authorities: "${this.certificateStore.certificatePath}". ` +
413
+ `The certificate has serial number "${CA_SERIAL_NUMBER}".`);
414
+ // Always return true on Linux to prevent breaking flow.
415
+ return true;
416
+ }
417
+ }
418
+ async _trySetFriendlyNameAsync(certificatePath, terminal) {
419
+ if (process.platform === 'win32') {
420
+ const basePath = path.dirname(certificatePath);
421
+ const fileName = path.basename(certificatePath, path.extname(certificatePath));
422
+ const friendlyNamePath = path.join(basePath, `${fileName}.inf`);
423
+ const friendlyNameFile = [
424
+ '[Version]',
425
+ 'Signature = "$Windows NT$"',
426
+ '[Properties]',
427
+ `11 = "{text}${FRIENDLY_NAME}"`,
428
+ ''
429
+ ].join(EOL);
430
+ await FileSystem.writeFileAsync(friendlyNamePath, friendlyNameFile);
431
+ const repairStoreResult = await runAsync(CERTUTIL_EXE_NAME, [
432
+ '-repairstore',
433
+ '-user',
434
+ 'root',
435
+ CA_SERIAL_NUMBER,
436
+ friendlyNamePath
437
+ ]);
438
+ if (repairStoreResult.exitCode !== 0) {
439
+ terminal.writeVerboseLine(`CertUtil Error: ${repairStoreResult.stderr.join('')}`);
440
+ terminal.writeVerboseLine(`CertUtil: ${repairStoreResult.stdout.join('')}`);
441
+ return false;
442
+ }
443
+ else {
444
+ terminal.writeVerboseLine('Successfully set certificate name.');
445
+ return true;
446
+ }
447
+ }
448
+ else {
449
+ // No equivalent concept outside of Windows
450
+ return true;
451
+ }
452
+ }
453
+ async _ensureCertificateInternalAsync(options, terminal) {
454
+ const certificateStore = this.certificateStore;
455
+ const generatedCertificate = await this._createDevelopmentCertificateAsync(options);
456
+ const certificateName = Date.now().toString();
457
+ const tempDirName = randomTmpPath('rushstack', 'temp');
458
+ await FileSystem.ensureFolderAsync(tempDirName);
459
+ const tempCertificatePath = path.join(tempDirName, `${certificateName}.pem`);
460
+ const pemFileContents = generatedCertificate.pemCaCertificate;
461
+ if (pemFileContents) {
462
+ await FileSystem.writeFileAsync(tempCertificatePath, pemFileContents, {
463
+ ensureFolderExists: true
464
+ });
465
+ }
466
+ const trustCertificateResult = options.skipCertificateTrust
467
+ ? true
468
+ : await this._tryTrustCertificateAsync(tempCertificatePath, terminal);
469
+ let subjectAltNames;
470
+ if (trustCertificateResult) {
471
+ certificateStore.caCertificateData = generatedCertificate.pemCaCertificate;
472
+ certificateStore.certificateData = generatedCertificate.pemCertificate;
473
+ certificateStore.keyData = generatedCertificate.pemKey;
474
+ subjectAltNames = generatedCertificate.subjectAltNames;
475
+ // Try to set the friendly name, and warn if we can't
476
+ if (!(await this._trySetFriendlyNameAsync(tempCertificatePath, terminal))) {
477
+ terminal.writeWarningLine("Unable to set the certificate's friendly name.");
478
+ }
479
+ }
480
+ else {
481
+ // Clear out the existing store data, if any exists
482
+ certificateStore.caCertificateData = undefined;
483
+ certificateStore.certificateData = undefined;
484
+ certificateStore.keyData = undefined;
485
+ }
486
+ await FileSystem.deleteFileAsync(tempCertificatePath);
487
+ return {
488
+ pemCaCertificate: certificateStore.caCertificateData,
489
+ pemCertificate: certificateStore.certificateData,
490
+ pemKey: certificateStore.keyData,
491
+ subjectAltNames
492
+ };
493
+ }
494
+ /**
495
+ * Validate existing certificates to check if they are usable.
496
+ *
497
+ * @public
498
+ */
499
+ async validateCertificateAsync(terminal, options) {
500
+ const optionsWithDefaults = applyDefaultOptions(options);
501
+ const { certificateData: existingCert, keyData: existingKey } = this.certificateStore;
502
+ if (!existingCert || !existingKey) {
503
+ return {
504
+ isValid: false,
505
+ validationMessages: ['No development certificate found.']
506
+ };
507
+ }
508
+ const messages = [];
509
+ const forge = await import('node-forge');
510
+ const parsedCertificate = forge.pki.certificateFromPem(existingCert);
511
+ const altNamesExtension = parsedCertificate.getExtension('subjectAltName');
512
+ if (!altNamesExtension) {
513
+ messages.push('The existing development certificate is missing the subjectAltName ' +
514
+ 'property and will not work with the latest versions of some browsers.');
515
+ }
516
+ else {
517
+ const missingSubjectNames = new Set(optionsWithDefaults.subjectAltNames);
518
+ for (const altName of altNamesExtension.altNames) {
519
+ missingSubjectNames.delete(isIPAddress(altName) ? altName.ip : altName.value);
520
+ }
521
+ if (missingSubjectNames.size) {
522
+ messages.push(`The existing development certificate does not include the following expected subjectAltName values: ` +
523
+ Array.from(missingSubjectNames, (name) => `"${name}"`).join(', '));
524
+ }
525
+ }
526
+ const { notBefore, notAfter } = parsedCertificate.validity;
527
+ const now = new Date();
528
+ if (now < notBefore) {
529
+ messages.push(`The existing development certificate's validity period does not start until ${notBefore}. It is currently ${now}.`);
530
+ }
531
+ if (now > notAfter) {
532
+ messages.push(`The existing development certificate's validity period ended ${notAfter}. It is currently ${now}.`);
533
+ }
534
+ now.setUTCDate(now.getUTCDate() + optionsWithDefaults.validityInDays);
535
+ if (notAfter > now) {
536
+ messages.push(`The existing development certificate's expiration date ${notAfter} exceeds the allowed limit ${now}. ` +
537
+ `This will be rejected by many browsers.`);
538
+ }
539
+ if (notBefore.getTime() - notAfter.getTime() >
540
+ optionsWithDefaults.validityInDays * ONE_DAY_IN_MILLISECONDS) {
541
+ messages.push("The existing development certificate's validity period is longer " +
542
+ `than ${optionsWithDefaults.validityInDays} days.`);
543
+ }
544
+ const { caCertificateData } = this.certificateStore;
545
+ if (!caCertificateData) {
546
+ messages.push('The existing development certificate is missing a separate CA cert as the root ' +
547
+ 'of trust and will not work with the latest versions of some browsers.');
548
+ }
549
+ const isTrusted = await this._detectIfCertificateIsTrustedAsync(terminal);
550
+ if (!isTrusted) {
551
+ messages.push('The existing development certificate is not currently trusted by your system.');
552
+ }
553
+ const isValid = messages.length === 0;
554
+ const validCertificate = isValid
555
+ ? {
556
+ pemCaCertificate: caCertificateData,
557
+ pemCertificate: existingCert,
558
+ pemKey: existingKey,
559
+ subjectAltNames: altNamesExtension === null || altNamesExtension === void 0 ? void 0 : altNamesExtension.altNames.map((entry) => isIPAddress(entry) ? entry.ip : entry.value)
560
+ }
561
+ : undefined;
562
+ return {
563
+ isValid,
564
+ validationMessages: messages,
565
+ certificate: validCertificate
566
+ };
567
+ }
568
+ _parseMacOsMatchingCertificateHash(findCertificateOuput) {
569
+ let shaHash = undefined;
570
+ for (const line of findCertificateOuput.split(EOL)) {
571
+ // Sets `shaHash` to the current certificate SHA-1 as we progress through the lines of certificate text.
572
+ const shaHashMatch = line.match(/^SHA-1 hash: (.+)$/);
573
+ if (shaHashMatch) {
574
+ shaHash = shaHashMatch[1];
575
+ }
576
+ const snbrMatch = line.match(/^\s*"snbr"<blob>=0x([^\s]+).+$/);
577
+ if (snbrMatch && (snbrMatch[1] || '').toLowerCase() === CA_SERIAL_NUMBER) {
578
+ return shaHash;
579
+ }
580
+ }
581
+ }
582
+ }
583
+ function applyDefaultOptions(options) {
584
+ var _a;
585
+ const subjectNames = options === null || options === void 0 ? void 0 : options.subjectAltNames;
586
+ const subjectIpAddresses = options === null || options === void 0 ? void 0 : options.subjectIPAddresses;
587
+ const skipCertificateTrust = (options === null || options === void 0 ? void 0 : options.skipCertificateTrust) || false;
588
+ return {
589
+ subjectAltNames: (subjectNames === null || subjectNames === void 0 ? void 0 : subjectNames.length) ? subjectNames : DEFAULT_CERTIFICATE_SUBJECT_NAMES,
590
+ subjectIPAddresses: (subjectIpAddresses === null || subjectIpAddresses === void 0 ? void 0 : subjectIpAddresses.length)
591
+ ? subjectIpAddresses
592
+ : DEFAULT_CERTIFICATE_SUBJECT_IP_ADDRESSES,
593
+ validityInDays: Math.min(MAX_CERTIFICATE_VALIDITY_DAYS, (_a = options === null || options === void 0 ? void 0 : options.validityInDays) !== null && _a !== void 0 ? _a : MAX_CERTIFICATE_VALIDITY_DAYS),
594
+ skipCertificateTrust: skipCertificateTrust
595
+ };
596
+ }
597
+ function isIPAddress(altName) {
598
+ return altName.type === 7;
599
+ }
600
+ //# sourceMappingURL=CertificateManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CertificateManager.js","sourceRoot":"","sources":["../src/CertificateManager.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as path from 'node:path';\nimport { EOL } from 'node:os';\n\nimport type { pki } from 'node-forge';\n\nimport { FileSystem } from '@rushstack/node-core-library';\nimport type { ITerminal } from '@rushstack/terminal';\n\nimport { darwinRunSudoAsync, type IRunResult, randomTmpPath, runAsync } from './runCommand';\nimport { CertificateStore, type ICertificateStoreOptions } from './CertificateStore';\n\nconst CA_SERIAL_NUMBER: string = '731c321744e34650a202e3ef91c3c1b0';\nconst TLS_SERIAL_NUMBER: string = '731c321744e34650a202e3ef00000001';\nconst FRIENDLY_NAME: string = 'debug-certificate-manager Development Certificate';\nconst MAC_KEYCHAIN: string = '/Library/Keychains/System.keychain';\nconst CERTUTIL_EXE_NAME: string = 'certutil';\nconst CA_ALT_NAME: string = 'rushstack-certificate-manager.localhost';\nconst ONE_DAY_IN_MILLISECONDS: number = 24 * 60 * 60 * 1000;\n\n/**\n * The set of names the certificate should be generated for, by default.\n * @public\n */\nexport const DEFAULT_CERTIFICATE_SUBJECT_NAMES: ReadonlyArray<string> = ['localhost'];\n\n/**\n * The set of ip addresses the certificate should be generated for, by default.\n * @public\n */\nexport const DEFAULT_CERTIFICATE_SUBJECT_IP_ADDRESSES: ReadonlyArray<string> = ['127.0.0.1', '::1'];\n\nconst DISABLE_CERT_GENERATION_VARIABLE_NAME: 'RUSHSTACK_DISABLE_DEV_CERT_GENERATION' =\n 'RUSHSTACK_DISABLE_DEV_CERT_GENERATION';\n\n/**\n * The interface for a debug certificate instance\n *\n * @public\n */\nexport interface ICertificate {\n /**\n * Generated pem Certificate Authority certificate contents\n */\n pemCaCertificate: string | undefined;\n\n /**\n * Generated pem TLS Server certificate contents\n */\n pemCertificate: string | undefined;\n\n /**\n * Private key for the TLS server certificate, used to sign TLS communications\n */\n pemKey: string | undefined;\n\n /**\n * The subject names the TLS server certificate is valid for\n */\n subjectAltNames: readonly string[] | undefined;\n}\n\n/**\n * Information about certificate validation results\n * @public\n */\nexport interface ICertificateValidationResult {\n /**\n * Whether valid certificates exist and are usable\n */\n isValid: boolean;\n\n /**\n * List of validation messages/issues found\n */\n validationMessages: string[];\n\n /**\n * The existing certificate if it exists and is valid\n */\n certificate?: ICertificate;\n}\n\ninterface ICaCertificate {\n /**\n * Certificate\n */\n certificate: pki.Certificate;\n\n /**\n * Private key for the CA cert. Delete after signing the TLS cert.\n */\n privateKey: pki.PrivateKey;\n}\n\ninterface ISubjectAltNameExtension {\n altNames: readonly IAltName[];\n}\n\n/**\n * Fields for a Subject Alternative Name of type DNS Name\n */\ninterface IDnsAltName {\n type: 2;\n value: string;\n}\n/**\n * Fields for a Subject Alternative Name of type IP Address\n * `node-forge` requires the field name to be \"ip\" instead of \"value\", likely due to subtle encoding differences.\n */\ninterface IIPAddressAltName {\n type: 7;\n ip: string;\n}\ntype IAltName = IDnsAltName | IIPAddressAltName;\n\n/**\n * Options to use if needing to generate a new certificate\n * @public\n */\nexport interface ICertificateGenerationOptions {\n /**\n * The DNS Subject names to issue the certificate for. Defaults to ['localhost'].\n */\n subjectAltNames?: ReadonlyArray<string>;\n /**\n * The IP Address Subject names to issue the certificate for. Defaults to ['127.0.0.1'].\n */\n subjectIPAddresses?: ReadonlyArray<string>;\n /**\n * How many days the certificate should be valid for.\n */\n validityInDays?: number;\n /**\n * Skip trusting a certificate. Defaults to false.\n */\n skipCertificateTrust?: boolean;\n}\n\n/**\n * Options for configuring the `CertificateManager`.\n * @public\n */\nexport interface ICertificateManagerOptions extends ICertificateStoreOptions {}\n\nconst MAX_CERTIFICATE_VALIDITY_DAYS: 365 = 365;\n\nconst VS_CODE_EXTENSION_FIX_MESSAGE: string =\n 'Use the \"Debug Certificate Manager\" Extension for VS Code (ms-RushStack.debug-certificate-manager) and run the ' +\n '\"Debug Certificate Manager: Ensure and Sync TLS Certificates\" command to fix certificate issues. ';\n\n/**\n * A utility class to handle generating, trusting, and untrustring a debug certificate.\n * Contains two public methods to `ensureCertificate` and `untrustCertificate`.\n * @public\n */\nexport class CertificateManager {\n /**\n * Get the certificate store used by this manager.\n * @public\n */\n public readonly certificateStore: CertificateStore;\n\n public constructor(options: ICertificateManagerOptions = {}) {\n this.certificateStore = new CertificateStore(options);\n }\n\n /**\n * Get a development certificate from the store, or optionally, generate a new one\n * and trust it if one doesn't exist in the store.\n *\n * @public\n */\n public async ensureCertificateAsync(\n canGenerateNewCertificate: boolean,\n terminal: ITerminal,\n options?: ICertificateGenerationOptions\n ): Promise<ICertificate> {\n const optionsWithDefaults: Required<ICertificateGenerationOptions> = applyDefaultOptions(options);\n\n if (process.env[DISABLE_CERT_GENERATION_VARIABLE_NAME] === '1') {\n // Allow the environment (e.g. GitHub codespaces) to forcibly disable dev cert generation\n terminal.writeLine(\n `Found environment variable ${DISABLE_CERT_GENERATION_VARIABLE_NAME}=1, disabling certificate generation. ` +\n VS_CODE_EXTENSION_FIX_MESSAGE\n );\n canGenerateNewCertificate = false;\n }\n\n // Validate existing certificates\n const validationResult: ICertificateValidationResult = await this.validateCertificateAsync(\n terminal,\n options\n );\n\n if (validationResult.isValid && validationResult.certificate) {\n // Existing certificate is valid, return it\n return validationResult.certificate;\n }\n\n // Certificate is invalid or doesn't exist\n if (validationResult.validationMessages.length > 0) {\n if (canGenerateNewCertificate) {\n validationResult.validationMessages.push(\n 'Attempting to untrust the certificate and generate a new one.'\n );\n terminal.writeWarningLine(validationResult.validationMessages.join(' '));\n if (!options?.skipCertificateTrust) {\n await this.untrustCertificateAsync(terminal);\n }\n return await this._ensureCertificateInternalAsync(optionsWithDefaults, terminal);\n } else {\n validationResult.validationMessages.push(\n 'Untrust the certificate and generate a new one, or set the ' +\n '`canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`. ' +\n VS_CODE_EXTENSION_FIX_MESSAGE\n );\n throw new Error(validationResult.validationMessages.join(' '));\n }\n } else if (canGenerateNewCertificate) {\n return await this._ensureCertificateInternalAsync(optionsWithDefaults, terminal);\n } else {\n throw new Error(\n 'No development certificate found. Generate a new certificate manually, or set the ' +\n '`canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`. ' +\n VS_CODE_EXTENSION_FIX_MESSAGE\n );\n }\n }\n\n /**\n * Attempt to locate a previously generated debug certificate and untrust it.\n *\n * @public\n */\n public async untrustCertificateAsync(terminal: ITerminal): Promise<boolean> {\n this.certificateStore.certificateData = undefined;\n this.certificateStore.keyData = undefined;\n this.certificateStore.caCertificateData = undefined;\n\n switch (process.platform) {\n case 'win32':\n const winUntrustResult: IRunResult = await runAsync(CERTUTIL_EXE_NAME, [\n '-user',\n '-delstore',\n 'root',\n CA_SERIAL_NUMBER\n ]);\n\n if (winUntrustResult.exitCode !== 0) {\n terminal.writeErrorLine(`Error: ${winUntrustResult.stderr.join(' ')}`);\n return false;\n } else {\n terminal.writeVerboseLine('Successfully untrusted development certificate.');\n return true;\n }\n\n case 'darwin':\n terminal.writeVerboseLine('Trying to find the signature of the development certificate.');\n\n const macFindCertificateResult: IRunResult = await runAsync('security', [\n 'find-certificate',\n '-c',\n CA_ALT_NAME,\n '-a',\n '-Z',\n MAC_KEYCHAIN\n ]);\n if (macFindCertificateResult.exitCode !== 0) {\n terminal.writeErrorLine(\n `Error finding the development certificate: ${macFindCertificateResult.stderr.join(' ')}`\n );\n return false;\n }\n\n const shaHash: string | undefined = this._parseMacOsMatchingCertificateHash(\n macFindCertificateResult.stdout.join(EOL)\n );\n\n if (!shaHash) {\n terminal.writeErrorLine('Unable to find the development certificate.');\n return false;\n } else {\n terminal.writeVerboseLine(`Found the development certificate. SHA is ${shaHash}`);\n }\n\n const macUntrustResult: IRunResult = await darwinRunSudoAsync(terminal, 'security', [\n 'delete-certificate',\n '-Z',\n shaHash,\n MAC_KEYCHAIN\n ]);\n\n if (macUntrustResult.exitCode === 0) {\n terminal.writeVerboseLine('Successfully untrusted development certificate.');\n return true;\n } else {\n terminal.writeErrorLine(macUntrustResult.stderr.join(' '));\n return false;\n }\n\n default:\n // Linux + others: Have the user manually untrust the cert\n terminal.writeLine(\n 'Automatic certificate untrust is only implemented for debug-certificate-manager on Windows ' +\n 'and macOS. To untrust the development certificate, remove this certificate from your trusted ' +\n `root certification authorities: \"${this.certificateStore.certificatePath}\". The ` +\n `certificate has serial number \"${CA_SERIAL_NUMBER}\".`\n );\n return false;\n }\n }\n\n private async _createCACertificateAsync(\n validityInDays: number,\n forge: typeof import('node-forge')\n ): Promise<ICaCertificate> {\n const keys: pki.KeyPair = forge.pki.rsa.generateKeyPair(2048);\n const certificate: pki.Certificate = forge.pki.createCertificate();\n certificate.publicKey = keys.publicKey;\n\n certificate.serialNumber = CA_SERIAL_NUMBER;\n\n const notBefore: Date = new Date();\n const notAfter: Date = new Date(notBefore);\n notAfter.setUTCDate(notBefore.getUTCDate() + validityInDays);\n certificate.validity.notBefore = notBefore;\n certificate.validity.notAfter = notAfter;\n\n const attrs: pki.CertificateField[] = [\n {\n name: 'commonName',\n value: CA_ALT_NAME\n }\n ];\n\n certificate.setSubject(attrs);\n certificate.setIssuer(attrs);\n\n const altNames: readonly IAltName[] = [\n {\n type: 2, // DNS\n value: CA_ALT_NAME\n }\n ];\n\n certificate.setExtensions([\n {\n name: 'basicConstraints',\n cA: true,\n pathLenConstraint: 0,\n critical: true\n },\n {\n name: 'subjectAltName',\n altNames,\n critical: true\n },\n {\n name: 'issuerAltName',\n altNames,\n critical: false\n },\n {\n name: 'keyUsage',\n keyCertSign: true,\n critical: true\n },\n {\n name: 'extKeyUsage',\n serverAuth: true,\n critical: true\n },\n {\n name: 'friendlyName',\n value: FRIENDLY_NAME\n }\n ]);\n\n // self-sign certificate\n certificate.sign(keys.privateKey, forge.md.sha256.create());\n\n return {\n certificate,\n privateKey: keys.privateKey\n };\n }\n\n private async _createDevelopmentCertificateAsync(\n options: Required<ICertificateGenerationOptions>\n ): Promise<ICertificate> {\n const forge: typeof import('node-forge') = await import('node-forge');\n const keys: pki.KeyPair = forge.pki.rsa.generateKeyPair(2048);\n const certificate: pki.Certificate = forge.pki.createCertificate();\n\n certificate.publicKey = keys.publicKey;\n certificate.serialNumber = TLS_SERIAL_NUMBER;\n\n const { subjectAltNames: subjectNames, subjectIPAddresses: subjectIpAddresses, validityInDays } = options;\n\n const { certificate: caCertificate, privateKey: caPrivateKey } = await this._createCACertificateAsync(\n validityInDays,\n forge\n );\n\n const notBefore: Date = new Date();\n const notAfter: Date = new Date(notBefore);\n notAfter.setUTCDate(notBefore.getUTCDate() + validityInDays);\n certificate.validity.notBefore = notBefore;\n certificate.validity.notAfter = notAfter;\n\n const subjectAttrs: pki.CertificateField[] = [\n {\n name: 'commonName',\n value: subjectNames[0]\n }\n ];\n const issuerAttrs: pki.CertificateField[] = caCertificate.subject.attributes;\n\n certificate.setSubject(subjectAttrs);\n certificate.setIssuer(issuerAttrs);\n\n const subjectAltNames: IAltName[] = [\n ...subjectNames.map<IDnsAltName>((subjectName) => ({\n type: 2, // DNS\n value: subjectName\n })),\n ...subjectIpAddresses.map<IIPAddressAltName>((ip) => ({\n type: 7, // IP\n ip\n }))\n ];\n\n const issuerAltNames: readonly IAltName[] = [\n {\n type: 2, // DNS\n value: CA_ALT_NAME\n }\n ];\n\n certificate.setExtensions([\n {\n name: 'basicConstraints',\n cA: false,\n critical: true\n },\n {\n name: 'subjectAltName',\n altNames: subjectAltNames,\n critical: true\n },\n {\n name: 'issuerAltName',\n altNames: issuerAltNames,\n critical: false\n },\n {\n name: 'keyUsage',\n digitalSignature: true,\n keyEncipherment: true,\n dataEncipherment: true,\n critical: true\n },\n {\n name: 'extKeyUsage',\n serverAuth: true,\n critical: true\n },\n {\n name: 'friendlyName',\n value: FRIENDLY_NAME\n }\n ]);\n\n // Sign certificate with CA\n certificate.sign(caPrivateKey, forge.md.sha256.create());\n\n // convert a Forge certificate to PEM\n const caPem: string = forge.pki.certificateToPem(caCertificate);\n const pem: string = forge.pki.certificateToPem(certificate);\n const pemKey: string = forge.pki.privateKeyToPem(keys.privateKey);\n\n return {\n pemCaCertificate: caPem,\n pemCertificate: pem,\n pemKey: pemKey,\n subjectAltNames: options.subjectAltNames\n };\n }\n\n private async _tryTrustCertificateAsync(certificatePath: string, terminal: ITerminal): Promise<boolean> {\n switch (process.platform) {\n case 'win32':\n terminal.writeLine(\n 'Attempting to trust a development certificate. This self-signed certificate only points to localhost ' +\n 'and will be stored in your local user profile to be used by other instances of ' +\n 'debug-certificate-manager. If you do not consent to trust this certificate, click \"NO\" in the dialog.'\n );\n\n const winTrustResult: IRunResult = await runAsync(CERTUTIL_EXE_NAME, [\n '-user',\n '-addstore',\n 'root',\n certificatePath\n ]);\n\n if (winTrustResult.exitCode !== 0) {\n terminal.writeErrorLine(`Error: ${winTrustResult.stdout.toString()}`);\n\n const errorLines: string[] = winTrustResult.stdout\n .toString()\n .split(EOL)\n .map((line: string) => line.trim());\n\n // Not sure if this is always the status code for \"cancelled\" - should confirm.\n if (\n winTrustResult.exitCode === 2147943623 ||\n errorLines[errorLines.length - 1].indexOf('The operation was canceled by the user.') > 0\n ) {\n terminal.writeLine('Certificate trust cancelled.');\n } else {\n terminal.writeErrorLine('Certificate trust failed with an unknown error.');\n }\n\n return false;\n } else {\n terminal.writeVerboseLine('Successfully trusted development certificate.');\n\n return true;\n }\n\n case 'darwin':\n terminal.writeLine(\n 'Attempting to trust a development certificate. This self-signed certificate only points to localhost ' +\n 'and will be stored in your local user profile to be used by other instances of ' +\n 'debug-certificate-manager. If you do not consent to trust this certificate, do not enter your ' +\n 'root password in the prompt.'\n );\n\n const result: IRunResult = await darwinRunSudoAsync(terminal, 'security', [\n 'add-trusted-cert',\n '-d',\n '-r',\n 'trustRoot',\n '-k',\n MAC_KEYCHAIN,\n certificatePath\n ]);\n\n if (result.exitCode === 0) {\n terminal.writeVerboseLine('Successfully trusted development certificate.');\n return true;\n } else {\n if (\n result.stderr.some(\n (value: string) => !!value.match(/The authorization was cancelled by the user\\./)\n )\n ) {\n terminal.writeLine('Certificate trust cancelled.');\n return false;\n } else {\n terminal.writeErrorLine(\n `Certificate trust failed with an unknown error. Exit code: ${result.exitCode}. ` +\n `Error: ${result.stderr.join(' ')}`\n );\n return false;\n }\n }\n\n default:\n // Linux + others: Have the user manually trust the cert if they want to\n terminal.writeLine(\n 'Automatic certificate trust is only implemented for debug-certificate-manager on Windows ' +\n 'and macOS. To trust the development certificate, add this certificate to your trusted root ' +\n `certification authorities: \"${certificatePath}\".`\n );\n return true;\n }\n }\n\n private async _detectIfCertificateIsTrustedAsync(terminal: ITerminal): Promise<boolean> {\n switch (process.platform) {\n case 'win32':\n const winVerifyStoreResult: IRunResult = await runAsync(CERTUTIL_EXE_NAME, [\n '-user',\n '-verifystore',\n 'root',\n CA_SERIAL_NUMBER\n ]);\n\n if (winVerifyStoreResult.exitCode !== 0) {\n terminal.writeVerboseLine(\n 'The development certificate was not found in the store. CertUtil error: ',\n winVerifyStoreResult.stderr.join(' ')\n );\n return false;\n } else {\n terminal.writeVerboseLine(\n 'The development certificate was found in the store. CertUtil output: ',\n winVerifyStoreResult.stdout.join(' ')\n );\n return true;\n }\n\n case 'darwin':\n terminal.writeVerboseLine('Trying to find the signature of the development certificate.');\n\n const macFindCertificateResult: IRunResult = await runAsync('security', [\n 'find-certificate',\n '-c',\n CA_ALT_NAME,\n '-a',\n '-Z',\n MAC_KEYCHAIN\n ]);\n\n if (macFindCertificateResult.exitCode !== 0) {\n terminal.writeVerboseLine(\n 'The development certificate was not found in keychain. Find certificate error: ',\n macFindCertificateResult.stderr.join(' ')\n );\n return false;\n }\n\n const shaHash: string | undefined = this._parseMacOsMatchingCertificateHash(\n macFindCertificateResult.stdout.join(EOL)\n );\n\n if (!shaHash) {\n terminal.writeVerboseLine(\n 'The development certificate was not found in keychain. Find certificate output:\\n',\n macFindCertificateResult.stdout.join(' ')\n );\n return false;\n }\n\n terminal.writeVerboseLine(`The development certificate was found in keychain.`);\n return true;\n\n default:\n // Linux + others: Have the user manually verify the cert is trusted\n terminal.writeVerboseLine(\n 'Automatic certificate trust validation is only implemented for debug-certificate-manager on Windows ' +\n 'and macOS. Manually verify this development certificate is present in your trusted ' +\n `root certification authorities: \"${this.certificateStore.certificatePath}\". ` +\n `The certificate has serial number \"${CA_SERIAL_NUMBER}\".`\n );\n // Always return true on Linux to prevent breaking flow.\n return true;\n }\n }\n\n private async _trySetFriendlyNameAsync(certificatePath: string, terminal: ITerminal): Promise<boolean> {\n if (process.platform === 'win32') {\n const basePath: string = path.dirname(certificatePath);\n const fileName: string = path.basename(certificatePath, path.extname(certificatePath));\n const friendlyNamePath: string = path.join(basePath, `${fileName}.inf`);\n\n const friendlyNameFile: string = [\n '[Version]',\n 'Signature = \"$Windows NT$\"',\n '[Properties]',\n `11 = \"{text}${FRIENDLY_NAME}\"`,\n ''\n ].join(EOL);\n\n await FileSystem.writeFileAsync(friendlyNamePath, friendlyNameFile);\n\n const repairStoreResult: IRunResult = await runAsync(CERTUTIL_EXE_NAME, [\n '-repairstore',\n '-user',\n 'root',\n CA_SERIAL_NUMBER,\n friendlyNamePath\n ]);\n\n if (repairStoreResult.exitCode !== 0) {\n terminal.writeVerboseLine(`CertUtil Error: ${repairStoreResult.stderr.join('')}`);\n terminal.writeVerboseLine(`CertUtil: ${repairStoreResult.stdout.join('')}`);\n return false;\n } else {\n terminal.writeVerboseLine('Successfully set certificate name.');\n return true;\n }\n } else {\n // No equivalent concept outside of Windows\n return true;\n }\n }\n\n private async _ensureCertificateInternalAsync(\n options: Required<ICertificateGenerationOptions>,\n terminal: ITerminal\n ): Promise<ICertificate> {\n const certificateStore: CertificateStore = this.certificateStore;\n const generatedCertificate: ICertificate = await this._createDevelopmentCertificateAsync(options);\n\n const certificateName: string = Date.now().toString();\n const tempDirName: string = randomTmpPath('rushstack', 'temp');\n await FileSystem.ensureFolderAsync(tempDirName);\n\n const tempCertificatePath: string = path.join(tempDirName, `${certificateName}.pem`);\n const pemFileContents: string | undefined = generatedCertificate.pemCaCertificate;\n if (pemFileContents) {\n await FileSystem.writeFileAsync(tempCertificatePath, pemFileContents, {\n ensureFolderExists: true\n });\n }\n\n const trustCertificateResult: boolean = options.skipCertificateTrust\n ? true\n : await this._tryTrustCertificateAsync(tempCertificatePath, terminal);\n\n let subjectAltNames: readonly string[] | undefined;\n if (trustCertificateResult) {\n certificateStore.caCertificateData = generatedCertificate.pemCaCertificate;\n certificateStore.certificateData = generatedCertificate.pemCertificate;\n certificateStore.keyData = generatedCertificate.pemKey;\n subjectAltNames = generatedCertificate.subjectAltNames;\n\n // Try to set the friendly name, and warn if we can't\n if (!(await this._trySetFriendlyNameAsync(tempCertificatePath, terminal))) {\n terminal.writeWarningLine(\"Unable to set the certificate's friendly name.\");\n }\n } else {\n // Clear out the existing store data, if any exists\n certificateStore.caCertificateData = undefined;\n certificateStore.certificateData = undefined;\n certificateStore.keyData = undefined;\n }\n\n await FileSystem.deleteFileAsync(tempCertificatePath);\n\n return {\n pemCaCertificate: certificateStore.caCertificateData,\n pemCertificate: certificateStore.certificateData,\n pemKey: certificateStore.keyData,\n subjectAltNames\n };\n }\n\n /**\n * Validate existing certificates to check if they are usable.\n *\n * @public\n */\n public async validateCertificateAsync(\n terminal: ITerminal,\n options?: ICertificateGenerationOptions\n ): Promise<ICertificateValidationResult> {\n const optionsWithDefaults: Required<ICertificateGenerationOptions> = applyDefaultOptions(options);\n const { certificateData: existingCert, keyData: existingKey } = this.certificateStore;\n\n if (!existingCert || !existingKey) {\n return {\n isValid: false,\n validationMessages: ['No development certificate found.']\n };\n }\n\n const messages: string[] = [];\n\n const forge: typeof import('node-forge') = await import('node-forge');\n const parsedCertificate: pki.Certificate = forge.pki.certificateFromPem(existingCert);\n const altNamesExtension: ISubjectAltNameExtension | undefined = parsedCertificate.getExtension(\n 'subjectAltName'\n ) as ISubjectAltNameExtension;\n\n if (!altNamesExtension) {\n messages.push(\n 'The existing development certificate is missing the subjectAltName ' +\n 'property and will not work with the latest versions of some browsers.'\n );\n } else {\n const missingSubjectNames: Set<string> = new Set(optionsWithDefaults.subjectAltNames);\n for (const altName of altNamesExtension.altNames) {\n missingSubjectNames.delete(isIPAddress(altName) ? altName.ip : altName.value);\n }\n if (missingSubjectNames.size) {\n messages.push(\n `The existing development certificate does not include the following expected subjectAltName values: ` +\n Array.from(missingSubjectNames, (name: string) => `\"${name}\"`).join(', ')\n );\n }\n }\n\n const { notBefore, notAfter } = parsedCertificate.validity;\n const now: Date = new Date();\n if (now < notBefore) {\n messages.push(\n `The existing development certificate's validity period does not start until ${notBefore}. It is currently ${now}.`\n );\n }\n\n if (now > notAfter) {\n messages.push(\n `The existing development certificate's validity period ended ${notAfter}. It is currently ${now}.`\n );\n }\n\n now.setUTCDate(now.getUTCDate() + optionsWithDefaults.validityInDays);\n if (notAfter > now) {\n messages.push(\n `The existing development certificate's expiration date ${notAfter} exceeds the allowed limit ${now}. ` +\n `This will be rejected by many browsers.`\n );\n }\n\n if (\n notBefore.getTime() - notAfter.getTime() >\n optionsWithDefaults.validityInDays * ONE_DAY_IN_MILLISECONDS\n ) {\n messages.push(\n \"The existing development certificate's validity period is longer \" +\n `than ${optionsWithDefaults.validityInDays} days.`\n );\n }\n\n const { caCertificateData } = this.certificateStore;\n\n if (!caCertificateData) {\n messages.push(\n 'The existing development certificate is missing a separate CA cert as the root ' +\n 'of trust and will not work with the latest versions of some browsers.'\n );\n }\n\n const isTrusted: boolean = await this._detectIfCertificateIsTrustedAsync(terminal);\n if (!isTrusted) {\n messages.push('The existing development certificate is not currently trusted by your system.');\n }\n\n const isValid: boolean = messages.length === 0;\n const validCertificate: ICertificate | undefined = isValid\n ? {\n pemCaCertificate: caCertificateData,\n pemCertificate: existingCert,\n pemKey: existingKey,\n subjectAltNames: altNamesExtension?.altNames.map((entry) =>\n isIPAddress(entry) ? entry.ip : entry.value\n )\n }\n : undefined;\n\n return {\n isValid,\n validationMessages: messages,\n certificate: validCertificate\n };\n }\n\n private _parseMacOsMatchingCertificateHash(findCertificateOuput: string): string | undefined {\n let shaHash: string | undefined = undefined;\n for (const line of findCertificateOuput.split(EOL)) {\n // Sets `shaHash` to the current certificate SHA-1 as we progress through the lines of certificate text.\n const shaHashMatch: string[] | null = line.match(/^SHA-1 hash: (.+)$/);\n if (shaHashMatch) {\n shaHash = shaHashMatch[1];\n }\n\n const snbrMatch: string[] | null = line.match(/^\\s*\"snbr\"<blob>=0x([^\\s]+).+$/);\n if (snbrMatch && (snbrMatch[1] || '').toLowerCase() === CA_SERIAL_NUMBER) {\n return shaHash;\n }\n }\n }\n}\n\nfunction applyDefaultOptions(\n options: ICertificateGenerationOptions | undefined\n): Required<ICertificateGenerationOptions> {\n const subjectNames: ReadonlyArray<string> | undefined = options?.subjectAltNames;\n const subjectIpAddresses: ReadonlyArray<string> | undefined = options?.subjectIPAddresses;\n const skipCertificateTrust: boolean | undefined = options?.skipCertificateTrust || false;\n return {\n subjectAltNames: subjectNames?.length ? subjectNames : DEFAULT_CERTIFICATE_SUBJECT_NAMES,\n subjectIPAddresses: subjectIpAddresses?.length\n ? subjectIpAddresses\n : DEFAULT_CERTIFICATE_SUBJECT_IP_ADDRESSES,\n validityInDays: Math.min(\n MAX_CERTIFICATE_VALIDITY_DAYS,\n options?.validityInDays ?? MAX_CERTIFICATE_VALIDITY_DAYS\n ),\n skipCertificateTrust: skipCertificateTrust\n };\n}\n\nfunction isIPAddress(altName: IAltName): altName is IIPAddressAltName {\n return altName.type === 7;\n}\n"]}
@@ -0,0 +1,163 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2
+ // See LICENSE in the project root for license information.
3
+ import * as path from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ import { FileSystem } from '@rushstack/node-core-library';
6
+ /**
7
+ * Store to retrieve and save debug certificate data.
8
+ * @public
9
+ */
10
+ export class CertificateStore {
11
+ constructor(options = {}) {
12
+ var _a, _b, _c, _d, _e, _f;
13
+ const requestedStorePath = options.storePath;
14
+ let storePath;
15
+ let debugCertificateManagerConfig = undefined;
16
+ if (requestedStorePath) {
17
+ storePath = path.resolve(requestedStorePath);
18
+ }
19
+ else {
20
+ // TLS Sync extension configuration lives in `.vscode/debug-certificate-manager.json`
21
+ let currentDir = process.cwd();
22
+ while (currentDir) {
23
+ const debugCertificateManagerConfigFile = path.join(currentDir, '.vscode', 'debug-certificate-manager.json');
24
+ if (FileSystem.exists(debugCertificateManagerConfigFile)) {
25
+ const configContent = FileSystem.readFile(debugCertificateManagerConfigFile);
26
+ debugCertificateManagerConfig = JSON.parse(configContent);
27
+ if (debugCertificateManagerConfig.storePath) {
28
+ storePath = debugCertificateManagerConfig.storePath;
29
+ if (storePath.startsWith('~')) {
30
+ storePath = path.join(homedir(), storePath.slice(2));
31
+ }
32
+ else {
33
+ storePath = path.resolve(currentDir, debugCertificateManagerConfig.storePath);
34
+ }
35
+ }
36
+ break; // found the config file, stop searching
37
+ }
38
+ const parentDir = path.dirname(currentDir);
39
+ if (parentDir === currentDir) {
40
+ break; // reached the root directory
41
+ }
42
+ currentDir = parentDir;
43
+ }
44
+ if (!storePath) {
45
+ // Fallback to the user's home directory under `.rushstack`
46
+ const unresolvedUserFolder = homedir();
47
+ const userProfilePath = path.resolve(unresolvedUserFolder);
48
+ if (!FileSystem.exists(userProfilePath)) {
49
+ throw new Error("Unable to determine the current user's home directory");
50
+ }
51
+ storePath = path.join(userProfilePath, '.rushstack');
52
+ }
53
+ }
54
+ FileSystem.ensureFolder(storePath);
55
+ const caCertificatePath = path.join(storePath, (_b = (_a = options.caCertificateFilename) !== null && _a !== void 0 ? _a : debugCertificateManagerConfig === null || debugCertificateManagerConfig === void 0 ? void 0 : debugCertificateManagerConfig.caCertificateFilename) !== null && _b !== void 0 ? _b : 'rushstack-ca.pem');
56
+ const certificatePath = path.join(storePath, (_d = (_c = options.certificateFilename) !== null && _c !== void 0 ? _c : debugCertificateManagerConfig === null || debugCertificateManagerConfig === void 0 ? void 0 : debugCertificateManagerConfig.certificateFilename) !== null && _d !== void 0 ? _d : 'rushstack-serve.pem');
57
+ const keyPath = path.join(storePath, (_f = (_e = options.keyFilename) !== null && _e !== void 0 ? _e : debugCertificateManagerConfig === null || debugCertificateManagerConfig === void 0 ? void 0 : debugCertificateManagerConfig.keyFilename) !== null && _f !== void 0 ? _f : 'rushstack-serve.key');
58
+ this._storePath = storePath;
59
+ this._caCertificatePath = caCertificatePath;
60
+ this._certificatePath = certificatePath;
61
+ this._keyPath = keyPath;
62
+ }
63
+ /**
64
+ * Path to the directory where the debug certificates are stored.
65
+ */
66
+ get storePath() {
67
+ return this._storePath;
68
+ }
69
+ /**
70
+ * Path to the saved debug CA certificate
71
+ */
72
+ get caCertificatePath() {
73
+ return this._caCertificatePath;
74
+ }
75
+ /**
76
+ * Path to the saved debug TLS certificate
77
+ */
78
+ get certificatePath() {
79
+ return this._certificatePath;
80
+ }
81
+ /**
82
+ * Path to the saved debug TLS key
83
+ */
84
+ get keyPath() {
85
+ return this._keyPath;
86
+ }
87
+ /**
88
+ * Debug Certificate Authority certificate pem file contents.
89
+ */
90
+ get caCertificateData() {
91
+ if (!this._caCertificateData) {
92
+ try {
93
+ this._caCertificateData = FileSystem.readFile(this._caCertificatePath);
94
+ }
95
+ catch (err) {
96
+ if (!FileSystem.isNotExistError(err)) {
97
+ throw err;
98
+ }
99
+ }
100
+ }
101
+ return this._caCertificateData;
102
+ }
103
+ set caCertificateData(certificate) {
104
+ if (certificate) {
105
+ FileSystem.writeFile(this._caCertificatePath, certificate);
106
+ }
107
+ else if (FileSystem.exists(this._caCertificatePath)) {
108
+ FileSystem.deleteFile(this._caCertificatePath);
109
+ }
110
+ this._caCertificateData = certificate;
111
+ }
112
+ /**
113
+ * Debug TLS Server certificate pem file contents.
114
+ */
115
+ get certificateData() {
116
+ if (!this._certificateData) {
117
+ try {
118
+ this._certificateData = FileSystem.readFile(this._certificatePath);
119
+ }
120
+ catch (err) {
121
+ if (!FileSystem.isNotExistError(err)) {
122
+ throw err;
123
+ }
124
+ }
125
+ }
126
+ return this._certificateData;
127
+ }
128
+ set certificateData(certificate) {
129
+ if (certificate) {
130
+ FileSystem.writeFile(this._certificatePath, certificate);
131
+ }
132
+ else if (FileSystem.exists(this._certificatePath)) {
133
+ FileSystem.deleteFile(this._certificatePath);
134
+ }
135
+ this._certificateData = certificate;
136
+ }
137
+ /**
138
+ * Key used to sign the debug pem certificate.
139
+ */
140
+ get keyData() {
141
+ if (!this._keyData) {
142
+ try {
143
+ this._keyData = FileSystem.readFile(this._keyPath);
144
+ }
145
+ catch (err) {
146
+ if (!FileSystem.isNotExistError(err)) {
147
+ throw err;
148
+ }
149
+ }
150
+ }
151
+ return this._keyData;
152
+ }
153
+ set keyData(key) {
154
+ if (key) {
155
+ FileSystem.writeFile(this._keyPath, key);
156
+ }
157
+ else if (FileSystem.exists(this._keyPath)) {
158
+ FileSystem.deleteFile(this._keyPath);
159
+ }
160
+ this._keyData = key;
161
+ }
162
+ }
163
+ //# sourceMappingURL=CertificateStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CertificateStore.js","sourceRoot":"","sources":["../src/CertificateStore.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport * as path from 'node:path';\nimport { homedir } from 'node:os';\n\nimport { FileSystem } from '@rushstack/node-core-library';\n\n/**\n * Options for configuring paths and filenames used by the `CertificateStore`.\n * @public\n */\nexport interface ICertificateStoreOptions {\n /**\n * Path to the directory where the certificate store will be created.\n * If not provided, it defaults to `<homedir>/.rushstack`.\n */\n storePath?: string;\n /**\n * Filename of the CA certificate file within the store directory.\n * If not provided, it defaults to `rushstack-ca.pem`.\n */\n caCertificateFilename?: string;\n /**\n * Filename of the TLS certificate file within the store directory.\n * If not provided, it defaults to `rushstack-serve.pem`.\n */\n certificateFilename?: string;\n /**\n * Filename of the TLS key file within the store directory.\n * If not provided, it defaults to `rushstack-serve.key`.\n */\n keyFilename?: string;\n}\n\n/**\n * Store to retrieve and save debug certificate data.\n * @public\n */\nexport class CertificateStore {\n private readonly _caCertificatePath: string;\n private readonly _certificatePath: string;\n private readonly _keyPath: string;\n private readonly _storePath: string;\n\n private _caCertificateData: string | undefined;\n private _certificateData: string | undefined;\n private _keyData: string | undefined;\n\n public constructor(options: ICertificateStoreOptions = {}) {\n const requestedStorePath: string | undefined = options.storePath;\n\n let storePath: string | undefined;\n let debugCertificateManagerConfig: ICertificateStoreOptions | undefined = undefined;\n\n if (requestedStorePath) {\n storePath = path.resolve(requestedStorePath);\n } else {\n // TLS Sync extension configuration lives in `.vscode/debug-certificate-manager.json`\n let currentDir: string | undefined = process.cwd();\n while (currentDir) {\n const debugCertificateManagerConfigFile: string = path.join(\n currentDir,\n '.vscode',\n 'debug-certificate-manager.json'\n );\n if (FileSystem.exists(debugCertificateManagerConfigFile)) {\n const configContent: string = FileSystem.readFile(debugCertificateManagerConfigFile);\n debugCertificateManagerConfig = JSON.parse(configContent) as ICertificateStoreOptions;\n if (debugCertificateManagerConfig.storePath) {\n storePath = debugCertificateManagerConfig.storePath;\n if (storePath.startsWith('~')) {\n storePath = path.join(homedir(), storePath.slice(2));\n } else {\n storePath = path.resolve(currentDir, debugCertificateManagerConfig.storePath);\n }\n }\n break; // found the config file, stop searching\n }\n const parentDir: string | undefined = path.dirname(currentDir);\n if (parentDir === currentDir) {\n break; // reached the root directory\n }\n currentDir = parentDir;\n }\n\n if (!storePath) {\n // Fallback to the user's home directory under `.rushstack`\n const unresolvedUserFolder: string = homedir();\n const userProfilePath: string = path.resolve(unresolvedUserFolder);\n if (!FileSystem.exists(userProfilePath)) {\n throw new Error(\"Unable to determine the current user's home directory\");\n }\n storePath = path.join(userProfilePath, '.rushstack');\n }\n }\n FileSystem.ensureFolder(storePath);\n\n const caCertificatePath: string = path.join(\n storePath,\n options.caCertificateFilename ??\n debugCertificateManagerConfig?.caCertificateFilename ??\n 'rushstack-ca.pem'\n );\n const certificatePath: string = path.join(\n storePath,\n options.certificateFilename ??\n debugCertificateManagerConfig?.certificateFilename ??\n 'rushstack-serve.pem'\n );\n const keyPath: string = path.join(\n storePath,\n options.keyFilename ?? debugCertificateManagerConfig?.keyFilename ?? 'rushstack-serve.key'\n );\n\n this._storePath = storePath;\n this._caCertificatePath = caCertificatePath;\n this._certificatePath = certificatePath;\n this._keyPath = keyPath;\n }\n\n /**\n * Path to the directory where the debug certificates are stored.\n */\n public get storePath(): string {\n return this._storePath;\n }\n\n /**\n * Path to the saved debug CA certificate\n */\n public get caCertificatePath(): string {\n return this._caCertificatePath;\n }\n\n /**\n * Path to the saved debug TLS certificate\n */\n public get certificatePath(): string {\n return this._certificatePath;\n }\n\n /**\n * Path to the saved debug TLS key\n */\n public get keyPath(): string {\n return this._keyPath;\n }\n\n /**\n * Debug Certificate Authority certificate pem file contents.\n */\n public get caCertificateData(): string | undefined {\n if (!this._caCertificateData) {\n try {\n this._caCertificateData = FileSystem.readFile(this._caCertificatePath);\n } catch (err) {\n if (!FileSystem.isNotExistError(err)) {\n throw err;\n }\n }\n }\n\n return this._caCertificateData;\n }\n\n public set caCertificateData(certificate: string | undefined) {\n if (certificate) {\n FileSystem.writeFile(this._caCertificatePath, certificate);\n } else if (FileSystem.exists(this._caCertificatePath)) {\n FileSystem.deleteFile(this._caCertificatePath);\n }\n\n this._caCertificateData = certificate;\n }\n\n /**\n * Debug TLS Server certificate pem file contents.\n */\n public get certificateData(): string | undefined {\n if (!this._certificateData) {\n try {\n this._certificateData = FileSystem.readFile(this._certificatePath);\n } catch (err) {\n if (!FileSystem.isNotExistError(err)) {\n throw err;\n }\n }\n }\n\n return this._certificateData;\n }\n\n public set certificateData(certificate: string | undefined) {\n if (certificate) {\n FileSystem.writeFile(this._certificatePath, certificate);\n } else if (FileSystem.exists(this._certificatePath)) {\n FileSystem.deleteFile(this._certificatePath);\n }\n\n this._certificateData = certificate;\n }\n\n /**\n * Key used to sign the debug pem certificate.\n */\n public get keyData(): string | undefined {\n if (!this._keyData) {\n try {\n this._keyData = FileSystem.readFile(this._keyPath);\n } catch (err) {\n if (!FileSystem.isNotExistError(err)) {\n throw err;\n }\n }\n }\n\n return this._keyData;\n }\n\n public set keyData(key: string | undefined) {\n if (key) {\n FileSystem.writeFile(this._keyPath, key);\n } else if (FileSystem.exists(this._keyPath)) {\n FileSystem.deleteFile(this._keyPath);\n }\n\n this._keyData = key;\n }\n}\n"]}
@@ -0,0 +1,20 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2
+ // See LICENSE in the project root for license information.
3
+ /**
4
+ * This package is used to manage debug certificates for development servers.
5
+ *
6
+ * This package provides the following utilities:
7
+ *
8
+ * - `CertificateStore` to handle retrieving and saving a debug certificate.
9
+ *
10
+ * - `CertificateManager` is a utility class containing the following public methods:
11
+ *
12
+ * - `ensureCertificate` will find or optionally create a debug certificate and trust it.
13
+ *
14
+ * - `untrustCertificate` will untrust a debug certificate.
15
+ *
16
+ * @packageDocumentation
17
+ */
18
+ export { CertificateManager, DEFAULT_CERTIFICATE_SUBJECT_NAMES } from './CertificateManager';
19
+ export { CertificateStore } from './CertificateStore';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,2DAA2D;AAE3D;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAEL,kBAAkB,EAIlB,iCAAiC,EAClC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAiC,MAAM,oBAAoB,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * This package is used to manage debug certificates for development servers.\n *\n * This package provides the following utilities:\n *\n * - `CertificateStore` to handle retrieving and saving a debug certificate.\n *\n * - `CertificateManager` is a utility class containing the following public methods:\n *\n * - `ensureCertificate` will find or optionally create a debug certificate and trust it.\n *\n * - `untrustCertificate` will untrust a debug certificate.\n *\n * @packageDocumentation\n */\n\nexport {\n type ICertificate,\n CertificateManager,\n type ICertificateGenerationOptions,\n type ICertificateManagerOptions,\n type ICertificateValidationResult,\n DEFAULT_CERTIFICATE_SUBJECT_NAMES\n} from './CertificateManager';\nexport { CertificateStore, type ICertificateStoreOptions } from './CertificateStore';\n"]}
@@ -0,0 +1,84 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2
+ // See LICENSE in the project root for license information.
3
+ import * as path from 'node:path';
4
+ import * as os from 'node:os';
5
+ import { Executable, FileSystem, Text } from '@rushstack/node-core-library';
6
+ export function randomTmpPath(prefix, suffix) {
7
+ return path.join(os.tmpdir(), `${prefix || 'tmp-'}${Math.random().toString(36).slice(2)}${suffix || ''}`);
8
+ }
9
+ export async function darwinRunSudoAsync(terminal, command, params) {
10
+ if (process.platform !== 'darwin') {
11
+ throw new Error('This function is only supported on macOS.');
12
+ }
13
+ const basename = randomTmpPath('sudo-runner-');
14
+ const stdoutFile = `${basename}.stdout`;
15
+ const stderrFile = `${basename}.stderr`;
16
+ const exitFile = `${basename}.exit`;
17
+ const scriptFile = `${basename}.script`;
18
+ const commandStr = `${command} ${params.join(' ')}`;
19
+ terminal.writeLine(`Running command with elevated privileges: ${commandStr}`);
20
+ // Wrap the shell command in a bash command and capture stdout, stderr, and exit code
21
+ const shellScript = `#!/bin/bash
22
+ set -v
23
+ echo "\\n\\nRunning command with elevated privileges: ${commandStr}";
24
+ sudo ${commandStr} > >(tee -a ${stdoutFile}) 2> >(tee -a ${stderrFile} >&2)
25
+ echo $? > "${exitFile}"
26
+ `;
27
+ FileSystem.writeFile(scriptFile, shellScript);
28
+ // This AppleScript opens a new Terminal window, runs the shell script, waits for it to finish and then closes the Terminal window.
29
+ const appleScript = `
30
+ tell application "Terminal"
31
+ activate
32
+ set win to do script "bash '${scriptFile}'"
33
+ repeat
34
+ delay 0.5
35
+ if not busy of window 1 then exit repeat
36
+ end repeat
37
+ close window 1
38
+ end tell
39
+ `;
40
+ terminal.writeLine(`Running AppleScript: ${appleScript}`);
41
+ const child = Executable.spawn('osascript', ['-e', appleScript]);
42
+ await Executable.waitForExitAsync(child);
43
+ const [stdoutContent, stderrContent, exitCodeStr] = await Promise.all([
44
+ FileSystem.readFileAsync(stdoutFile),
45
+ FileSystem.readFileAsync(stderrFile),
46
+ FileSystem.readFileAsync(exitFile)
47
+ ]);
48
+ const stdout = Text.splitByNewLines(stdoutContent);
49
+ const stderr = Text.splitByNewLines(stderrContent);
50
+ const exitCode = exitCodeStr ? Number(exitCodeStr) : -1;
51
+ await Promise.all([
52
+ FileSystem.deleteFileAsync(stdoutFile),
53
+ FileSystem.deleteFileAsync(stderrFile),
54
+ FileSystem.deleteFileAsync(exitFile),
55
+ FileSystem.deleteFileAsync(scriptFile)
56
+ ]);
57
+ return {
58
+ stdout,
59
+ stderr,
60
+ exitCode
61
+ };
62
+ }
63
+ export async function runAsync(command, params) {
64
+ const result = Executable.spawn(command, params);
65
+ return await _handleChildProcess(result);
66
+ }
67
+ async function _handleChildProcess(childProcess) {
68
+ return await new Promise((resolve) => {
69
+ var _a, _b;
70
+ const stderr = [];
71
+ (_a = childProcess.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
72
+ stderr.push(data.toString());
73
+ });
74
+ const stdout = [];
75
+ (_b = childProcess.stdout) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
76
+ stdout.push(data.toString());
77
+ });
78
+ childProcess.on('close', (exitCode, signal) => {
79
+ const normalizedExitCode = typeof exitCode === 'number' ? exitCode : signal ? -1 : 0;
80
+ resolve({ exitCode: normalizedExitCode, stdout, stderr });
81
+ });
82
+ });
83
+ }
84
+ //# sourceMappingURL=runCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runCommand.js","sourceRoot":"","sources":["../src/runCommand.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type * as child_process from 'node:child_process';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\n\nimport type { ITerminal } from '@rushstack/terminal';\nimport { Executable, FileSystem, Text } from '@rushstack/node-core-library';\n\nexport interface IRunResult {\n stdout: string[];\n stderr: string[];\n /**\n * The exit code, or -1 if the child process was terminated by a signal\n */\n exitCode: number;\n}\n\nexport function randomTmpPath(prefix?: string, suffix?: string): string {\n return path.join(os.tmpdir(), `${prefix || 'tmp-'}${Math.random().toString(36).slice(2)}${suffix || ''}`);\n}\n\nexport async function darwinRunSudoAsync(\n terminal: ITerminal,\n command: string,\n params: string[]\n): Promise<IRunResult> {\n if (process.platform !== 'darwin') {\n throw new Error('This function is only supported on macOS.');\n }\n\n const basename: string = randomTmpPath('sudo-runner-');\n const stdoutFile: string = `${basename}.stdout`;\n const stderrFile: string = `${basename}.stderr`;\n const exitFile: string = `${basename}.exit`;\n const scriptFile: string = `${basename}.script`;\n\n const commandStr: string = `${command} ${params.join(' ')}`;\n terminal.writeLine(`Running command with elevated privileges: ${commandStr}`);\n\n // Wrap the shell command in a bash command and capture stdout, stderr, and exit code\n const shellScript: string = `#!/bin/bash\nset -v\necho \"\\\\n\\\\nRunning command with elevated privileges: ${commandStr}\";\nsudo ${commandStr} > >(tee -a ${stdoutFile}) 2> >(tee -a ${stderrFile} >&2)\necho $? > \"${exitFile}\"\n`;\n\n FileSystem.writeFile(scriptFile, shellScript);\n\n // This AppleScript opens a new Terminal window, runs the shell script, waits for it to finish and then closes the Terminal window.\n const appleScript: string = `\n tell application \"Terminal\"\n activate\n set win to do script \"bash '${scriptFile}'\"\n repeat\n delay 0.5\n if not busy of window 1 then exit repeat\n end repeat\n close window 1\n end tell\n `;\n\n terminal.writeLine(`Running AppleScript: ${appleScript}`);\n\n const child: child_process.ChildProcess = Executable.spawn('osascript', ['-e', appleScript]);\n\n await Executable.waitForExitAsync(child);\n\n const [stdoutContent, stderrContent, exitCodeStr] = await Promise.all([\n FileSystem.readFileAsync(stdoutFile),\n FileSystem.readFileAsync(stderrFile),\n FileSystem.readFileAsync(exitFile)\n ]);\n\n const stdout: string[] = Text.splitByNewLines(stdoutContent);\n const stderr: string[] = Text.splitByNewLines(stderrContent);\n const exitCode: number = exitCodeStr ? Number(exitCodeStr) : -1;\n\n await Promise.all([\n FileSystem.deleteFileAsync(stdoutFile),\n FileSystem.deleteFileAsync(stderrFile),\n FileSystem.deleteFileAsync(exitFile),\n FileSystem.deleteFileAsync(scriptFile)\n ]);\n\n return {\n stdout,\n stderr,\n exitCode\n };\n}\n\nexport async function runAsync(command: string, params: string[]): Promise<IRunResult> {\n const result: child_process.ChildProcess = Executable.spawn(command, params);\n return await _handleChildProcess(result);\n}\n\nasync function _handleChildProcess(childProcess: child_process.ChildProcess): Promise<IRunResult> {\n return await new Promise((resolve: (result: IRunResult) => void) => {\n const stderr: string[] = [];\n childProcess.stderr?.on('data', (data: Buffer) => {\n stderr.push(data.toString());\n });\n\n const stdout: string[] = [];\n childProcess.stdout?.on('data', (data: Buffer) => {\n stdout.push(data.toString());\n });\n\n childProcess.on('close', (exitCode: number | null, signal: NodeJS.Signals | null) => {\n const normalizedExitCode: number = typeof exitCode === 'number' ? exitCode : signal ? -1 : 0;\n resolve({ exitCode: normalizedExitCode, stdout, stderr });\n });\n });\n}\n"]}
package/package.json CHANGED
@@ -1,9 +1,30 @@
1
1
  {
2
2
  "name": "@rushstack/debug-certificate-manager",
3
- "version": "1.6.14",
3
+ "version": "1.7.0",
4
4
  "description": "Cross-platform functionality to create debug ssl certificates.",
5
- "main": "lib/index.js",
6
- "typings": "dist/debug-certificate-manager.d.ts",
5
+ "main": "./lib-commonjs/index.js",
6
+ "module": "./lib-esm/index.js",
7
+ "types": "./dist/debug-certificate-manager.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/debug-certificate-manager.d.ts",
11
+ "import": "./lib-esm/index.js",
12
+ "require": "./lib-commonjs/index.js"
13
+ },
14
+ "./lib/*": {
15
+ "types": "./lib-dts/*.d.ts",
16
+ "import": "./lib-esm/*.js",
17
+ "require": "./lib-commonjs/*.js"
18
+ },
19
+ "./package.json": "./package.json"
20
+ },
21
+ "typesVersions": {
22
+ "*": {
23
+ "lib/*": [
24
+ "lib-dts/*"
25
+ ]
26
+ }
27
+ },
7
28
  "license": "MIT",
8
29
  "repository": {
9
30
  "url": "https://github.com/microsoft/rushstack.git",
@@ -12,15 +33,16 @@
12
33
  },
13
34
  "dependencies": {
14
35
  "node-forge": "~1.3.1",
15
- "@rushstack/node-core-library": "5.19.1",
16
- "@rushstack/terminal": "0.21.0"
36
+ "@rushstack/node-core-library": "5.20.0",
37
+ "@rushstack/terminal": "0.22.0"
17
38
  },
18
39
  "devDependencies": {
19
40
  "@types/node-forge": "1.0.4",
20
41
  "eslint": "~9.37.0",
21
42
  "local-node-rig": "1.0.0",
22
- "@rushstack/heft": "1.1.14"
43
+ "@rushstack/heft": "1.2.0"
23
44
  },
45
+ "sideEffects": false,
24
46
  "scripts": {
25
47
  "build": "heft build --clean",
26
48
  "_phase:build": "heft run --only build -- --clean"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes