@rushstack/debug-certificate-manager 1.1.11 → 1.1.15

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,63 @@
1
1
  {
2
2
  "name": "@rushstack/debug-certificate-manager",
3
3
  "entries": [
4
+ {
5
+ "version": "1.1.15",
6
+ "tag": "@rushstack/debug-certificate-manager_v1.1.15",
7
+ "date": "Fri, 03 Dec 2021 03:05:22 GMT",
8
+ "comments": {
9
+ "dependency": [
10
+ {
11
+ "comment": "Updating dependency \"@rushstack/node-core-library\" to `3.44.0`"
12
+ },
13
+ {
14
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.42.4`"
15
+ },
16
+ {
17
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.33`"
18
+ }
19
+ ]
20
+ }
21
+ },
22
+ {
23
+ "version": "1.1.14",
24
+ "tag": "@rushstack/debug-certificate-manager_v1.1.14",
25
+ "date": "Tue, 30 Nov 2021 20:18:41 GMT",
26
+ "comments": {
27
+ "dependency": [
28
+ {
29
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.32`"
30
+ }
31
+ ]
32
+ }
33
+ },
34
+ {
35
+ "version": "1.1.13",
36
+ "tag": "@rushstack/debug-certificate-manager_v1.1.13",
37
+ "date": "Mon, 29 Nov 2021 07:26:16 GMT",
38
+ "comments": {
39
+ "dependency": [
40
+ {
41
+ "comment": "Updating dependency \"@rushstack/heft\" to `0.42.3`"
42
+ },
43
+ {
44
+ "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `1.2.31`"
45
+ }
46
+ ]
47
+ }
48
+ },
49
+ {
50
+ "version": "1.1.12",
51
+ "tag": "@rushstack/debug-certificate-manager_v1.1.12",
52
+ "date": "Tue, 09 Nov 2021 16:08:07 GMT",
53
+ "comments": {
54
+ "patch": [
55
+ {
56
+ "comment": "Fix a bug where ensureCertificateAsync would assume a previously generated certificate was trusted."
57
+ }
58
+ ]
59
+ }
60
+ },
4
61
  {
5
62
  "version": "1.1.11",
6
63
  "tag": "@rushstack/debug-certificate-manager_v1.1.11",
package/CHANGELOG.md CHANGED
@@ -1,6 +1,28 @@
1
1
  # Change Log - @rushstack/debug-certificate-manager
2
2
 
3
- This log was last generated on Sat, 06 Nov 2021 00:09:13 GMT and should not be manually modified.
3
+ This log was last generated on Fri, 03 Dec 2021 03:05:22 GMT and should not be manually modified.
4
+
5
+ ## 1.1.15
6
+ Fri, 03 Dec 2021 03:05:22 GMT
7
+
8
+ _Version update only_
9
+
10
+ ## 1.1.14
11
+ Tue, 30 Nov 2021 20:18:41 GMT
12
+
13
+ _Version update only_
14
+
15
+ ## 1.1.13
16
+ Mon, 29 Nov 2021 07:26:16 GMT
17
+
18
+ _Version update only_
19
+
20
+ ## 1.1.12
21
+ Tue, 09 Nov 2021 16:08:07 GMT
22
+
23
+ ### Patches
24
+
25
+ - Fix a bug where ensureCertificateAsync would assume a previously generated certificate was trusted.
4
26
 
5
27
  ## 1.1.11
6
28
  Sat, 06 Nov 2021 00:09:13 GMT
package/README.md CHANGED
@@ -28,7 +28,7 @@ Set data using the same property names `certificateData: string | undefined` and
28
28
 
29
29
  ## `ensureCertificate`
30
30
 
31
- Get a dev certificate from the store, or optionally, generate a new one and trust it if one does not exist in the store. Returns a certificate object following the `ICertificate` interface.
31
+ Get a development certificate from the store, or optionally, generate a new one and trust it if one does not exist in the store. Returns a certificate object following the `ICertificate` interface.
32
32
 
33
33
  ```typescript
34
34
  export interface ICertificate {
@@ -24,7 +24,7 @@ export declare class CertificateManager {
24
24
  private _certificateStore;
25
25
  constructor();
26
26
  /**
27
- * Get a dev certificate from the store, or optionally, generate a new one
27
+ * Get a development certificate from the store, or optionally, generate a new one
28
28
  * and trust it if one doesn't exist in the store.
29
29
  *
30
30
  * @public
@@ -38,9 +38,11 @@ export declare class CertificateManager {
38
38
  untrustCertificateAsync(terminal: ITerminal): Promise<boolean>;
39
39
  private _createDevelopmentCertificate;
40
40
  private _tryTrustCertificateAsync;
41
+ private _detectIfCertificateIsTrustedAsync;
41
42
  private _trySetFriendlyNameAsync;
42
43
  private _ensureCertificateInternalAsync;
43
44
  private _certificateHasSubjectAltName;
45
+ private _parseMacOsMatchingCertificateHash;
44
46
  }
45
47
 
46
48
  /**
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.18.18"
8
+ "packageVersion": "7.18.19"
9
9
  }
10
10
  ]
11
11
  }
@@ -23,7 +23,7 @@ export declare class CertificateManager {
23
23
  private _certificateStore;
24
24
  constructor();
25
25
  /**
26
- * Get a dev certificate from the store, or optionally, generate a new one
26
+ * Get a development certificate from the store, or optionally, generate a new one
27
27
  * and trust it if one doesn't exist in the store.
28
28
  *
29
29
  * @public
@@ -37,8 +37,10 @@ export declare class CertificateManager {
37
37
  untrustCertificateAsync(terminal: ITerminal): Promise<boolean>;
38
38
  private _createDevelopmentCertificate;
39
39
  private _tryTrustCertificateAsync;
40
+ private _detectIfCertificateIsTrustedAsync;
40
41
  private _trySetFriendlyNameAsync;
41
42
  private _ensureCertificateInternalAsync;
42
43
  private _certificateHasSubjectAltName;
44
+ private _parseMacOsMatchingCertificateHash;
43
45
  }
44
46
  //# sourceMappingURL=CertificateManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CertificateManager.d.ts","sourceRoot":"","sources":["../src/CertificateManager.ts"],"names":[],"mappings":"AAOA,OAAO,EAAc,SAAS,EAAU,MAAM,8BAA8B,CAAC;AAY7E;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IAEnC;;OAEG;IACH,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED;;;;GAIG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,iBAAiB,CAAmB;;IAM5C;;;;;OAKG;IACU,sBAAsB,CACjC,yBAAyB,EAAE,OAAO,EAClC,QAAQ,EAAE,SAAS,GAClB,OAAO,CAAC,YAAY,CAAC;IA8BxB;;;;OAIG;IACU,uBAAuB,CAAC,QAAQ,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAiF3E,OAAO,CAAC,6BAA6B;YA6DvB,yBAAyB;YA0FzB,wBAAwB;YAqCxB,+BAA+B;IAqC7C,OAAO,CAAC,6BAA6B;CAQtC"}
1
+ {"version":3,"file":"CertificateManager.d.ts","sourceRoot":"","sources":["../src/CertificateManager.ts"],"names":[],"mappings":"AAMA,OAAO,EAAc,SAAS,EAAU,MAAM,8BAA8B,CAAC;AAY7E;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IAEnC;;OAEG;IACH,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED;;;;GAIG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,iBAAiB,CAAmB;;IAM5C;;;;;OAKG;IACU,sBAAsB,CACjC,yBAAyB,EAAE,OAAO,EAClC,QAAQ,EAAE,SAAS,GAClB,OAAO,CAAC,YAAY,CAAC;IA+CxB;;;;OAIG;IACU,uBAAuB,CAAC,QAAQ,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IA6E3E,OAAO,CAAC,6BAA6B;YA6DvB,yBAAyB;YA0FzB,kCAAkC;YAwElC,wBAAwB;YAqCxB,+BAA+B;IAqC7C,OAAO,CAAC,6BAA6B;IASrC,OAAO,CAAC,kCAAkC;CAe3C"}
@@ -23,10 +23,9 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
24
  exports.CertificateManager = void 0;
25
25
  const path = __importStar(require("path"));
26
- const child_process = __importStar(require("child_process"));
27
26
  const os_1 = require("os");
28
27
  const node_core_library_1 = require("@rushstack/node-core-library");
29
- const exec_1 = require("./exec");
28
+ const runCommand_1 = require("./runCommand");
30
29
  const CertificateStore_1 = require("./CertificateStore");
31
30
  const forge = node_core_library_1.Import.lazy('node-forge', require);
32
31
  const SERIAL_NUMBER = '731c321744e34650a202e3ef91c3c1b0';
@@ -43,32 +42,45 @@ class CertificateManager {
43
42
  this._certificateStore = new CertificateStore_1.CertificateStore();
44
43
  }
45
44
  /**
46
- * Get a dev certificate from the store, or optionally, generate a new one
45
+ * Get a development certificate from the store, or optionally, generate a new one
47
46
  * and trust it if one doesn't exist in the store.
48
47
  *
49
48
  * @public
50
49
  */
51
50
  async ensureCertificateAsync(canGenerateNewCertificate, terminal) {
52
51
  if (this._certificateStore.certificateData && this._certificateStore.keyData) {
52
+ let invalidCertificate = false;
53
+ const messages = [];
53
54
  if (!this._certificateHasSubjectAltName()) {
54
- let warningMessage = 'The existing development certificate is missing the subjectAltName ' +
55
- 'property and will not work with the latest versions of some browsers. ';
56
- if (canGenerateNewCertificate) {
57
- warningMessage += ' Attempting to untrust the certificate and generate a new one.';
58
- }
59
- else {
60
- warningMessage += ' Untrust the certificate and generate a new one.';
61
- }
62
- terminal.writeWarningLine(warningMessage);
55
+ invalidCertificate = true;
56
+ messages.push('The existing development certificate is missing the subjectAltName ' +
57
+ 'property and will not work with the latest versions of some browsers.');
58
+ }
59
+ if (!(await this._detectIfCertificateIsTrustedAsync(terminal))) {
60
+ invalidCertificate = true;
61
+ messages.push('The existing development certificate is not currently trusted by your system.');
62
+ }
63
+ if (invalidCertificate) {
63
64
  if (canGenerateNewCertificate) {
65
+ messages.push('Attempting to untrust the certificate and generate a new one.');
66
+ terminal.writeWarningLine(messages.join(' '));
64
67
  await this.untrustCertificateAsync(terminal);
65
68
  await this._ensureCertificateInternalAsync(terminal);
66
69
  }
70
+ else {
71
+ messages.push('Untrust the certificate and generate a new one, or set the ' +
72
+ '`canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`.');
73
+ throw new Error(messages.join(' '));
74
+ }
67
75
  }
68
76
  }
69
77
  else if (canGenerateNewCertificate) {
70
78
  await this._ensureCertificateInternalAsync(terminal);
71
79
  }
80
+ else {
81
+ throw new Error('No development certificate found. Generate a new certificate manually, or set the ' +
82
+ '`canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`.');
83
+ }
72
84
  return {
73
85
  pemCertificate: this._certificateStore.certificateData,
74
86
  pemKey: this._certificateStore.keyData
@@ -80,11 +92,18 @@ class CertificateManager {
80
92
  * @public
81
93
  */
82
94
  async untrustCertificateAsync(terminal) {
95
+ this._certificateStore.certificateData = undefined;
96
+ this._certificateStore.keyData = undefined;
83
97
  switch (process.platform) {
84
98
  case 'win32':
85
- const winUntrustResult = child_process.spawnSync(CERTUTIL_EXE_NAME, ['-user', '-delstore', 'root', SERIAL_NUMBER]);
86
- if (winUntrustResult.status !== 0) {
87
- terminal.writeErrorLine(`Error: ${winUntrustResult.stdout.toString()}`);
99
+ const winUntrustResult = await (0, runCommand_1.runAsync)(CERTUTIL_EXE_NAME, [
100
+ '-user',
101
+ '-delstore',
102
+ 'root',
103
+ SERIAL_NUMBER
104
+ ]);
105
+ if (winUntrustResult.code !== 0) {
106
+ terminal.writeErrorLine(`Error: ${winUntrustResult.stderr.join(' ')}`);
88
107
  return false;
89
108
  }
90
109
  else {
@@ -92,40 +111,35 @@ class CertificateManager {
92
111
  return true;
93
112
  }
94
113
  case 'darwin':
95
- terminal.writeVerboseLine('Trying to find the signature of the dev cert');
96
- const macFindCertificateResult = child_process.spawnSync('security', ['find-certificate', '-c', 'localhost', '-a', '-Z', MAC_KEYCHAIN]);
97
- if (macFindCertificateResult.status !== 0) {
98
- terminal.writeErrorLine(`Error finding the dev certificate: ${macFindCertificateResult.output.join(' ')}`);
114
+ terminal.writeVerboseLine('Trying to find the signature of the development certificate.');
115
+ const macFindCertificateResult = await (0, runCommand_1.runAsync)('security', [
116
+ 'find-certificate',
117
+ '-c',
118
+ 'localhost',
119
+ '-a',
120
+ '-Z',
121
+ MAC_KEYCHAIN
122
+ ]);
123
+ if (macFindCertificateResult.code !== 0) {
124
+ terminal.writeErrorLine(`Error finding the development certificate: ${macFindCertificateResult.stderr.join(' ')}`);
99
125
  return false;
100
126
  }
101
- const outputLines = macFindCertificateResult.stdout.toString().split(os_1.EOL);
102
- let found = false;
103
- let shaHash = '';
104
- for (let i = 0; i < outputLines.length; i++) {
105
- const line = outputLines[i];
106
- const shaMatch = line.match(/^SHA-1 hash: (.+)$/);
107
- if (shaMatch) {
108
- shaHash = shaMatch[1];
109
- }
110
- const snbrMatch = line.match(/^\s*"snbr"<blob>=0x([^\s]+).+$/);
111
- if (snbrMatch && (snbrMatch[1] || '').toLowerCase() === SERIAL_NUMBER) {
112
- found = true;
113
- break;
114
- }
115
- }
116
- if (!found) {
117
- terminal.writeErrorLine('Unable to find the dev certificate.');
127
+ const shaHash = this._parseMacOsMatchingCertificateHash(macFindCertificateResult.stdout.join(os_1.EOL));
128
+ if (!shaHash) {
129
+ terminal.writeErrorLine('Unable to find the development certificate.');
118
130
  return false;
119
131
  }
120
- terminal.writeVerboseLine(`Found the dev cert. SHA is ${shaHash}`);
121
- const macUntrustResult = await (0, exec_1.runSudoAsync)('security', [
132
+ else {
133
+ terminal.writeVerboseLine(`Found the development certificate. SHA is ${shaHash}`);
134
+ }
135
+ const macUntrustResult = await (0, runCommand_1.runSudoAsync)('security', [
122
136
  'delete-certificate',
123
137
  '-Z',
124
138
  shaHash,
125
139
  MAC_KEYCHAIN
126
140
  ]);
127
141
  if (macUntrustResult.code === 0) {
128
- terminal.writeVerboseLine('Successfully untrusted dev certificate.');
142
+ terminal.writeVerboseLine('Successfully untrusted development certificate.');
129
143
  return true;
130
144
  }
131
145
  else {
@@ -196,10 +210,10 @@ class CertificateManager {
196
210
  async _tryTrustCertificateAsync(certificatePath, terminal) {
197
211
  switch (process.platform) {
198
212
  case 'win32':
199
- terminal.writeLine('Attempting to trust a dev certificate. This self-signed certificate only points to localhost ' +
213
+ terminal.writeLine('Attempting to trust a development certificate. This self-signed certificate only points to localhost ' +
200
214
  'and will be stored in your local user profile to be used by other instances of ' +
201
215
  'debug-certificate-manager. If you do not consent to trust this certificate, click "NO" in the dialog.');
202
- const winTrustResult = await (0, exec_1.runAsync)(CERTUTIL_EXE_NAME, [
216
+ const winTrustResult = await (0, runCommand_1.runAsync)(CERTUTIL_EXE_NAME, [
203
217
  '-user',
204
218
  '-addstore',
205
219
  'root',
@@ -226,11 +240,11 @@ class CertificateManager {
226
240
  return true;
227
241
  }
228
242
  case 'darwin':
229
- terminal.writeLine('Attempting to trust a dev certificate. This self-signed certificate only points to localhost ' +
243
+ terminal.writeLine('Attempting to trust a development certificate. This self-signed certificate only points to localhost ' +
230
244
  'and will be stored in your local user profile to be used by other instances of ' +
231
245
  'debug-certificate-manager. If you do not consent to trust this certificate, do not enter your ' +
232
246
  'root password in the prompt.');
233
- const result = await (0, exec_1.runSudoAsync)('security', [
247
+ const result = await (0, runCommand_1.runSudoAsync)('security', [
234
248
  'add-trusted-cert',
235
249
  '-d',
236
250
  '-r',
@@ -262,6 +276,54 @@ class CertificateManager {
262
276
  return true;
263
277
  }
264
278
  }
279
+ async _detectIfCertificateIsTrustedAsync(terminal) {
280
+ switch (process.platform) {
281
+ case 'win32':
282
+ const winVerifyStoreResult = await (0, runCommand_1.runAsync)(CERTUTIL_EXE_NAME, [
283
+ '-user',
284
+ '-verifystore',
285
+ 'root',
286
+ SERIAL_NUMBER
287
+ ]);
288
+ if (winVerifyStoreResult.code !== 0) {
289
+ terminal.writeVerboseLine('The development certificate was not found in the store. CertUtil error: ', winVerifyStoreResult.stderr.join(' '));
290
+ return false;
291
+ }
292
+ else {
293
+ terminal.writeVerboseLine('The development certificate was found in the store. CertUtil output: ', winVerifyStoreResult.stdout.join(' '));
294
+ return true;
295
+ }
296
+ case 'darwin':
297
+ terminal.writeVerboseLine('Trying to find the signature of the development certificate.');
298
+ const macFindCertificateResult = await (0, runCommand_1.runAsync)('security', [
299
+ 'find-certificate',
300
+ '-c',
301
+ 'localhost',
302
+ '-a',
303
+ '-Z',
304
+ MAC_KEYCHAIN
305
+ ]);
306
+ if (macFindCertificateResult.code !== 0) {
307
+ terminal.writeVerboseLine('The development certificate was not found in keychain. Find certificate error: ', macFindCertificateResult.stderr.join(' '));
308
+ return false;
309
+ }
310
+ const shaHash = this._parseMacOsMatchingCertificateHash(macFindCertificateResult.stdout.join(os_1.EOL));
311
+ if (!shaHash) {
312
+ terminal.writeVerboseLine('The development certificate was not found in keychain. Find certificate output:\n', macFindCertificateResult.stdout.join(' '));
313
+ return false;
314
+ }
315
+ terminal.writeVerboseLine(`The development certificate was found in keychain.`);
316
+ return true;
317
+ default:
318
+ // Linux + others: Have the user manually verify the cert is trusted
319
+ terminal.writeVerboseLine('Automatic certificate trust validation is only implemented for debug-certificate-manager on Windows ' +
320
+ 'and macOS. Manually verify this development certificate is present in your trusted ' +
321
+ `root certification authorities: "${this._certificateStore.certificatePath}". ` +
322
+ `The certificate has serial number "${SERIAL_NUMBER}".`);
323
+ // Always return true on Linux to prevent breaking flow.
324
+ return true;
325
+ }
326
+ }
265
327
  async _trySetFriendlyNameAsync(certificatePath, terminal) {
266
328
  if (process.platform === 'win32') {
267
329
  const basePath = path.dirname(certificatePath);
@@ -275,10 +337,15 @@ class CertificateManager {
275
337
  ''
276
338
  ].join(os_1.EOL);
277
339
  await node_core_library_1.FileSystem.writeFileAsync(friendlyNamePath, friendlyNameFile);
278
- const commands = ['–repairstore', '–user', 'root', SERIAL_NUMBER, friendlyNamePath];
279
- const repairStoreResult = child_process.spawnSync(CERTUTIL_EXE_NAME, commands);
280
- if (repairStoreResult.status !== 0) {
281
- terminal.writeErrorLine(`CertUtil Error: ${repairStoreResult.stdout.toString()}`);
340
+ const repairStoreResult = await (0, runCommand_1.runAsync)(CERTUTIL_EXE_NAME, [
341
+ '–repairstore',
342
+ '–user',
343
+ 'root',
344
+ SERIAL_NUMBER,
345
+ friendlyNamePath
346
+ ]);
347
+ if (repairStoreResult.code !== 0) {
348
+ terminal.writeErrorLine(`CertUtil Error: ${repairStoreResult.stderr.join('')}`);
282
349
  return false;
283
350
  }
284
351
  else {
@@ -300,7 +367,7 @@ class CertificateManager {
300
367
  const tempCertificatePath = path.join(tempDirName, `${certificateName}.pem`);
301
368
  const pemFileContents = generatedCertificate.pemCertificate;
302
369
  if (pemFileContents) {
303
- node_core_library_1.FileSystem.writeFile(tempCertificatePath, pemFileContents, {
370
+ await node_core_library_1.FileSystem.writeFileAsync(tempCertificatePath, pemFileContents, {
304
371
  ensureFolderExists: true
305
372
  });
306
373
  }
@@ -328,6 +395,20 @@ class CertificateManager {
328
395
  const certificate = forge.pki.certificateFromPem(certificateData);
329
396
  return !!certificate.getExtension('subjectAltName');
330
397
  }
398
+ _parseMacOsMatchingCertificateHash(findCertificateOuput) {
399
+ let shaHash = undefined;
400
+ for (const line of findCertificateOuput.split(os_1.EOL)) {
401
+ // Sets `shaHash` to the current certificate SHA-1 as we progress through the lines of certificate text.
402
+ const shaHashMatch = line.match(/^SHA-1 hash: (.+)$/);
403
+ if (shaHashMatch) {
404
+ shaHash = shaHashMatch[1];
405
+ }
406
+ const snbrMatch = line.match(/^\s*"snbr"<blob>=0x([^\s]+).+$/);
407
+ if (snbrMatch && (snbrMatch[1] || '').toLowerCase() === SERIAL_NUMBER) {
408
+ return shaHash;
409
+ }
410
+ }
411
+ }
331
412
  }
332
413
  exports.CertificateManager = CertificateManager;
333
414
  //# sourceMappingURL=CertificateManager.js.map
@@ -1 +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.\r\n// See LICENSE in the project root for license information.\r\n\r\nimport type { pki } from 'node-forge';\r\nimport * as path from 'path';\r\nimport * as child_process from 'child_process';\r\nimport { EOL } from 'os';\r\nimport { FileSystem, ITerminal, Import } from '@rushstack/node-core-library';\r\n\r\nimport { runSudoAsync, IRunResult, runAsync } from './exec';\r\nimport { CertificateStore } from './CertificateStore';\r\n\r\nconst forge: typeof import('node-forge') = Import.lazy('node-forge', require);\r\n\r\nconst SERIAL_NUMBER: string = '731c321744e34650a202e3ef91c3c1b0';\r\nconst FRIENDLY_NAME: string = 'debug-certificate-manager Development Certificate';\r\nconst MAC_KEYCHAIN: string = '/Library/Keychains/System.keychain';\r\nconst CERTUTIL_EXE_NAME: string = 'certutil';\r\n\r\n/**\r\n * The interface for a debug certificate instance\r\n *\r\n * @public\r\n */\r\nexport interface ICertificate {\r\n /**\r\n * Generated pem certificate contents\r\n */\r\n pemCertificate: string | undefined;\r\n\r\n /**\r\n * Private key used to sign the pem certificate\r\n */\r\n pemKey: string | undefined;\r\n}\r\n\r\n/**\r\n * A utility class to handle generating, trusting, and untrustring a debug certificate.\r\n * Contains two public methods to `ensureCertificate` and `untrustCertificate`.\r\n * @public\r\n */\r\nexport class CertificateManager {\r\n private _certificateStore: CertificateStore;\r\n\r\n public constructor() {\r\n this._certificateStore = new CertificateStore();\r\n }\r\n\r\n /**\r\n * Get a dev certificate from the store, or optionally, generate a new one\r\n * and trust it if one doesn't exist in the store.\r\n *\r\n * @public\r\n */\r\n public async ensureCertificateAsync(\r\n canGenerateNewCertificate: boolean,\r\n terminal: ITerminal\r\n ): Promise<ICertificate> {\r\n if (this._certificateStore.certificateData && this._certificateStore.keyData) {\r\n if (!this._certificateHasSubjectAltName()) {\r\n let warningMessage: string =\r\n 'The existing development certificate is missing the subjectAltName ' +\r\n 'property and will not work with the latest versions of some browsers. ';\r\n\r\n if (canGenerateNewCertificate) {\r\n warningMessage += ' Attempting to untrust the certificate and generate a new one.';\r\n } else {\r\n warningMessage += ' Untrust the certificate and generate a new one.';\r\n }\r\n\r\n terminal.writeWarningLine(warningMessage);\r\n\r\n if (canGenerateNewCertificate) {\r\n await this.untrustCertificateAsync(terminal);\r\n await this._ensureCertificateInternalAsync(terminal);\r\n }\r\n }\r\n } else if (canGenerateNewCertificate) {\r\n await this._ensureCertificateInternalAsync(terminal);\r\n }\r\n\r\n return {\r\n pemCertificate: this._certificateStore.certificateData,\r\n pemKey: this._certificateStore.keyData\r\n };\r\n }\r\n\r\n /**\r\n * Attempt to locate a previously generated debug certificate and untrust it.\r\n *\r\n * @public\r\n */\r\n public async untrustCertificateAsync(terminal: ITerminal): Promise<boolean> {\r\n switch (process.platform) {\r\n case 'win32':\r\n const winUntrustResult: child_process.SpawnSyncReturns<string> = child_process.spawnSync(\r\n CERTUTIL_EXE_NAME,\r\n ['-user', '-delstore', 'root', SERIAL_NUMBER]\r\n );\r\n\r\n if (winUntrustResult.status !== 0) {\r\n terminal.writeErrorLine(`Error: ${winUntrustResult.stdout.toString()}`);\r\n return false;\r\n } else {\r\n terminal.writeVerboseLine('Successfully untrusted development certificate.');\r\n return true;\r\n }\r\n\r\n case 'darwin':\r\n terminal.writeVerboseLine('Trying to find the signature of the dev cert');\r\n\r\n const macFindCertificateResult: child_process.SpawnSyncReturns<string> = child_process.spawnSync(\r\n 'security',\r\n ['find-certificate', '-c', 'localhost', '-a', '-Z', MAC_KEYCHAIN]\r\n );\r\n if (macFindCertificateResult.status !== 0) {\r\n terminal.writeErrorLine(\r\n `Error finding the dev certificate: ${macFindCertificateResult.output.join(' ')}`\r\n );\r\n return false;\r\n }\r\n\r\n const outputLines: string[] = macFindCertificateResult.stdout.toString().split(EOL);\r\n let found: boolean = false;\r\n let shaHash: string = '';\r\n for (let i: number = 0; i < outputLines.length; i++) {\r\n const line: string = outputLines[i];\r\n const shaMatch: string[] | null = line.match(/^SHA-1 hash: (.+)$/);\r\n if (shaMatch) {\r\n shaHash = shaMatch[1];\r\n }\r\n\r\n const snbrMatch: string[] | null = line.match(/^\\s*\"snbr\"<blob>=0x([^\\s]+).+$/);\r\n if (snbrMatch && (snbrMatch[1] || '').toLowerCase() === SERIAL_NUMBER) {\r\n found = true;\r\n break;\r\n }\r\n }\r\n\r\n if (!found) {\r\n terminal.writeErrorLine('Unable to find the dev certificate.');\r\n return false;\r\n }\r\n\r\n terminal.writeVerboseLine(`Found the dev cert. SHA is ${shaHash}`);\r\n\r\n const macUntrustResult: IRunResult = await runSudoAsync('security', [\r\n 'delete-certificate',\r\n '-Z',\r\n shaHash,\r\n MAC_KEYCHAIN\r\n ]);\r\n\r\n if (macUntrustResult.code === 0) {\r\n terminal.writeVerboseLine('Successfully untrusted dev certificate.');\r\n return true;\r\n } else {\r\n terminal.writeErrorLine(macUntrustResult.stderr.join(' '));\r\n return false;\r\n }\r\n\r\n default:\r\n // Linux + others: Have the user manually untrust the cert\r\n terminal.writeLine(\r\n 'Automatic certificate untrust is only implemented for debug-certificate-manager on Windows ' +\r\n 'and macOS. To untrust the development certificate, remove this certificate from your trusted ' +\r\n `root certification authorities: \"${this._certificateStore.certificatePath}\". The ` +\r\n `certificate has serial number \"${SERIAL_NUMBER}\".`\r\n );\r\n return false;\r\n }\r\n }\r\n\r\n private _createDevelopmentCertificate(): ICertificate {\r\n const keys: pki.KeyPair = forge.pki.rsa.generateKeyPair(2048);\r\n const certificate: pki.Certificate = forge.pki.createCertificate();\r\n certificate.publicKey = keys.publicKey;\r\n\r\n certificate.serialNumber = SERIAL_NUMBER;\r\n\r\n const now: Date = new Date();\r\n certificate.validity.notBefore = now;\r\n // Valid for 3 years\r\n certificate.validity.notAfter.setFullYear(certificate.validity.notBefore.getFullYear() + 3);\r\n\r\n const attrs: pki.CertificateField[] = [\r\n {\r\n name: 'commonName',\r\n value: 'localhost'\r\n }\r\n ];\r\n\r\n certificate.setSubject(attrs);\r\n certificate.setIssuer(attrs);\r\n\r\n certificate.setExtensions([\r\n {\r\n name: 'subjectAltName',\r\n altNames: [\r\n {\r\n type: 2, // DNS\r\n value: 'localhost'\r\n }\r\n ]\r\n },\r\n {\r\n name: 'keyUsage',\r\n digitalSignature: true,\r\n keyEncipherment: true,\r\n dataEncipherment: true\r\n },\r\n {\r\n name: 'extKeyUsage',\r\n serverAuth: true\r\n },\r\n {\r\n name: 'friendlyName',\r\n value: FRIENDLY_NAME\r\n }\r\n ]);\r\n\r\n // self-sign certificate\r\n certificate.sign(keys.privateKey, forge.md.sha256.create());\r\n\r\n // convert a Forge certificate to PEM\r\n const pem: string = forge.pki.certificateToPem(certificate);\r\n const pemKey: string = forge.pki.privateKeyToPem(keys.privateKey);\r\n\r\n return {\r\n pemCertificate: pem,\r\n pemKey: pemKey\r\n };\r\n }\r\n\r\n private async _tryTrustCertificateAsync(certificatePath: string, terminal: ITerminal): Promise<boolean> {\r\n switch (process.platform) {\r\n case 'win32':\r\n terminal.writeLine(\r\n 'Attempting to trust a dev certificate. This self-signed certificate only points to localhost ' +\r\n 'and will be stored in your local user profile to be used by other instances of ' +\r\n 'debug-certificate-manager. If you do not consent to trust this certificate, click \"NO\" in the dialog.'\r\n );\r\n\r\n const winTrustResult: IRunResult = await runAsync(CERTUTIL_EXE_NAME, [\r\n '-user',\r\n '-addstore',\r\n 'root',\r\n certificatePath\r\n ]);\r\n\r\n if (winTrustResult.code !== 0) {\r\n terminal.writeErrorLine(`Error: ${winTrustResult.stdout.toString()}`);\r\n\r\n const errorLines: string[] = winTrustResult.stdout\r\n .toString()\r\n .split(EOL)\r\n .map((line: string) => line.trim());\r\n\r\n // Not sure if this is always the status code for \"cancelled\" - should confirm.\r\n if (\r\n winTrustResult.code === 2147943623 ||\r\n errorLines[errorLines.length - 1].indexOf('The operation was canceled by the user.') > 0\r\n ) {\r\n terminal.writeLine('Certificate trust cancelled.');\r\n } else {\r\n terminal.writeErrorLine('Certificate trust failed with an unknown error.');\r\n }\r\n\r\n return false;\r\n } else {\r\n terminal.writeVerboseLine('Successfully trusted development certificate.');\r\n\r\n return true;\r\n }\r\n\r\n case 'darwin':\r\n terminal.writeLine(\r\n 'Attempting to trust a dev certificate. This self-signed certificate only points to localhost ' +\r\n 'and will be stored in your local user profile to be used by other instances of ' +\r\n 'debug-certificate-manager. If you do not consent to trust this certificate, do not enter your ' +\r\n 'root password in the prompt.'\r\n );\r\n\r\n const result: IRunResult = await runSudoAsync('security', [\r\n 'add-trusted-cert',\r\n '-d',\r\n '-r',\r\n 'trustRoot',\r\n '-k',\r\n MAC_KEYCHAIN,\r\n certificatePath\r\n ]);\r\n\r\n if (result.code === 0) {\r\n terminal.writeVerboseLine('Successfully trusted development certificate.');\r\n return true;\r\n } else {\r\n if (\r\n result.stderr.some(\r\n (value: string) => !!value.match(/The authorization was cancelled by the user\\./)\r\n )\r\n ) {\r\n terminal.writeLine('Certificate trust cancelled.');\r\n return false;\r\n } else {\r\n terminal.writeErrorLine(\r\n `Certificate trust failed with an unknown error. Exit code: ${result.code}. ` +\r\n `Error: ${result.stderr.join(' ')}`\r\n );\r\n return false;\r\n }\r\n }\r\n\r\n default:\r\n // Linux + others: Have the user manually trust the cert if they want to\r\n terminal.writeLine(\r\n 'Automatic certificate trust is only implemented for debug-certificate-manager on Windows ' +\r\n 'and macOS. To trust the development certificate, add this certificate to your trusted root ' +\r\n `certification authorities: \"${certificatePath}\".`\r\n );\r\n return true;\r\n }\r\n }\r\n\r\n private async _trySetFriendlyNameAsync(certificatePath: string, terminal: ITerminal): Promise<boolean> {\r\n if (process.platform === 'win32') {\r\n const basePath: string = path.dirname(certificatePath);\r\n const fileName: string = path.basename(certificatePath, path.extname(certificatePath));\r\n const friendlyNamePath: string = path.join(basePath, `${fileName}.inf`);\r\n\r\n const friendlyNameFile: string = [\r\n '[Version]',\r\n 'Signature = \"$Windows NT$\"',\r\n '[Properties]',\r\n `11 = \"{text}${FRIENDLY_NAME}\"`,\r\n ''\r\n ].join(EOL);\r\n\r\n await FileSystem.writeFileAsync(friendlyNamePath, friendlyNameFile);\r\n\r\n const commands: string[] = ['–repairstore', '–user', 'root', SERIAL_NUMBER, friendlyNamePath];\r\n const repairStoreResult: child_process.SpawnSyncReturns<string> = child_process.spawnSync(\r\n CERTUTIL_EXE_NAME,\r\n commands\r\n );\r\n\r\n if (repairStoreResult.status !== 0) {\r\n terminal.writeErrorLine(`CertUtil Error: ${repairStoreResult.stdout.toString()}`);\r\n\r\n return false;\r\n } else {\r\n terminal.writeVerboseLine('Successfully set certificate name.');\r\n\r\n return true;\r\n }\r\n } else {\r\n // No equivalent concept outside of Windows\r\n return true;\r\n }\r\n }\r\n\r\n private async _ensureCertificateInternalAsync(terminal: ITerminal): Promise<void> {\r\n const certificateStore: CertificateStore = this._certificateStore;\r\n const generatedCertificate: ICertificate = this._createDevelopmentCertificate();\r\n\r\n const now: Date = new Date();\r\n const certificateName: string = now.getTime().toString();\r\n const tempDirName: string = path.join(__dirname, '..', 'temp');\r\n\r\n const tempCertificatePath: string = path.join(tempDirName, `${certificateName}.pem`);\r\n const pemFileContents: string | undefined = generatedCertificate.pemCertificate;\r\n if (pemFileContents) {\r\n FileSystem.writeFile(tempCertificatePath, pemFileContents, {\r\n ensureFolderExists: true\r\n });\r\n }\r\n\r\n const trustCertificateResult: boolean = await this._tryTrustCertificateAsync(\r\n tempCertificatePath,\r\n terminal\r\n );\r\n if (trustCertificateResult) {\r\n certificateStore.certificateData = generatedCertificate.pemCertificate;\r\n certificateStore.keyData = generatedCertificate.pemKey;\r\n\r\n // Try to set the friendly name, and warn if we can't\r\n if (!this._trySetFriendlyNameAsync(tempCertificatePath, terminal)) {\r\n terminal.writeWarningLine(\"Unable to set the certificate's friendly name.\");\r\n }\r\n } else {\r\n // Clear out the existing store data, if any exists\r\n certificateStore.certificateData = undefined;\r\n certificateStore.keyData = undefined;\r\n }\r\n\r\n await FileSystem.deleteFileAsync(tempCertificatePath);\r\n }\r\n\r\n private _certificateHasSubjectAltName(): boolean {\r\n const certificateData: string | undefined = this._certificateStore.certificateData;\r\n if (!certificateData) {\r\n return false;\r\n }\r\n const certificate: pki.Certificate = forge.pki.certificateFromPem(certificateData);\r\n return !!certificate.getExtension('subjectAltName');\r\n }\r\n}\r\n"]}
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.\r\n// See LICENSE in the project root for license information.\r\n\r\nimport type { pki } from 'node-forge';\r\nimport * as path from 'path';\r\nimport { EOL } from 'os';\r\nimport { FileSystem, ITerminal, Import } from '@rushstack/node-core-library';\r\n\r\nimport { runSudoAsync, IRunResult, runAsync } from './runCommand';\r\nimport { CertificateStore } from './CertificateStore';\r\n\r\nconst forge: typeof import('node-forge') = Import.lazy('node-forge', require);\r\n\r\nconst SERIAL_NUMBER: string = '731c321744e34650a202e3ef91c3c1b0';\r\nconst FRIENDLY_NAME: string = 'debug-certificate-manager Development Certificate';\r\nconst MAC_KEYCHAIN: string = '/Library/Keychains/System.keychain';\r\nconst CERTUTIL_EXE_NAME: string = 'certutil';\r\n\r\n/**\r\n * The interface for a debug certificate instance\r\n *\r\n * @public\r\n */\r\nexport interface ICertificate {\r\n /**\r\n * Generated pem certificate contents\r\n */\r\n pemCertificate: string | undefined;\r\n\r\n /**\r\n * Private key used to sign the pem certificate\r\n */\r\n pemKey: string | undefined;\r\n}\r\n\r\n/**\r\n * A utility class to handle generating, trusting, and untrustring a debug certificate.\r\n * Contains two public methods to `ensureCertificate` and `untrustCertificate`.\r\n * @public\r\n */\r\nexport class CertificateManager {\r\n private _certificateStore: CertificateStore;\r\n\r\n public constructor() {\r\n this._certificateStore = new CertificateStore();\r\n }\r\n\r\n /**\r\n * Get a development certificate from the store, or optionally, generate a new one\r\n * and trust it if one doesn't exist in the store.\r\n *\r\n * @public\r\n */\r\n public async ensureCertificateAsync(\r\n canGenerateNewCertificate: boolean,\r\n terminal: ITerminal\r\n ): Promise<ICertificate> {\r\n if (this._certificateStore.certificateData && this._certificateStore.keyData) {\r\n let invalidCertificate: boolean = false;\r\n const messages: string[] = [];\r\n\r\n if (!this._certificateHasSubjectAltName()) {\r\n invalidCertificate = true;\r\n messages.push(\r\n 'The existing development certificate is missing the subjectAltName ' +\r\n 'property and will not work with the latest versions of some browsers.'\r\n );\r\n }\r\n\r\n if (!(await this._detectIfCertificateIsTrustedAsync(terminal))) {\r\n invalidCertificate = true;\r\n messages.push('The existing development certificate is not currently trusted by your system.');\r\n }\r\n\r\n if (invalidCertificate) {\r\n if (canGenerateNewCertificate) {\r\n messages.push('Attempting to untrust the certificate and generate a new one.');\r\n terminal.writeWarningLine(messages.join(' '));\r\n await this.untrustCertificateAsync(terminal);\r\n await this._ensureCertificateInternalAsync(terminal);\r\n } else {\r\n messages.push(\r\n 'Untrust the certificate and generate a new one, or set the ' +\r\n '`canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`.'\r\n );\r\n throw new Error(messages.join(' '));\r\n }\r\n }\r\n } else if (canGenerateNewCertificate) {\r\n await this._ensureCertificateInternalAsync(terminal);\r\n } else {\r\n throw new Error(\r\n 'No development certificate found. Generate a new certificate manually, or set the ' +\r\n '`canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`.'\r\n );\r\n }\r\n\r\n return {\r\n pemCertificate: this._certificateStore.certificateData,\r\n pemKey: this._certificateStore.keyData\r\n };\r\n }\r\n\r\n /**\r\n * Attempt to locate a previously generated debug certificate and untrust it.\r\n *\r\n * @public\r\n */\r\n public async untrustCertificateAsync(terminal: ITerminal): Promise<boolean> {\r\n this._certificateStore.certificateData = undefined;\r\n this._certificateStore.keyData = undefined;\r\n\r\n switch (process.platform) {\r\n case 'win32':\r\n const winUntrustResult: IRunResult = await runAsync(CERTUTIL_EXE_NAME, [\r\n '-user',\r\n '-delstore',\r\n 'root',\r\n SERIAL_NUMBER\r\n ]);\r\n\r\n if (winUntrustResult.code !== 0) {\r\n terminal.writeErrorLine(`Error: ${winUntrustResult.stderr.join(' ')}`);\r\n return false;\r\n } else {\r\n terminal.writeVerboseLine('Successfully untrusted development certificate.');\r\n return true;\r\n }\r\n\r\n case 'darwin':\r\n terminal.writeVerboseLine('Trying to find the signature of the development certificate.');\r\n\r\n const macFindCertificateResult: IRunResult = await runAsync('security', [\r\n 'find-certificate',\r\n '-c',\r\n 'localhost',\r\n '-a',\r\n '-Z',\r\n MAC_KEYCHAIN\r\n ]);\r\n if (macFindCertificateResult.code !== 0) {\r\n terminal.writeErrorLine(\r\n `Error finding the development certificate: ${macFindCertificateResult.stderr.join(' ')}`\r\n );\r\n return false;\r\n }\r\n\r\n const shaHash: string | undefined = this._parseMacOsMatchingCertificateHash(\r\n macFindCertificateResult.stdout.join(EOL)\r\n );\r\n\r\n if (!shaHash) {\r\n terminal.writeErrorLine('Unable to find the development certificate.');\r\n return false;\r\n } else {\r\n terminal.writeVerboseLine(`Found the development certificate. SHA is ${shaHash}`);\r\n }\r\n\r\n const macUntrustResult: IRunResult = await runSudoAsync('security', [\r\n 'delete-certificate',\r\n '-Z',\r\n shaHash,\r\n MAC_KEYCHAIN\r\n ]);\r\n\r\n if (macUntrustResult.code === 0) {\r\n terminal.writeVerboseLine('Successfully untrusted development certificate.');\r\n return true;\r\n } else {\r\n terminal.writeErrorLine(macUntrustResult.stderr.join(' '));\r\n return false;\r\n }\r\n\r\n default:\r\n // Linux + others: Have the user manually untrust the cert\r\n terminal.writeLine(\r\n 'Automatic certificate untrust is only implemented for debug-certificate-manager on Windows ' +\r\n 'and macOS. To untrust the development certificate, remove this certificate from your trusted ' +\r\n `root certification authorities: \"${this._certificateStore.certificatePath}\". The ` +\r\n `certificate has serial number \"${SERIAL_NUMBER}\".`\r\n );\r\n return false;\r\n }\r\n }\r\n\r\n private _createDevelopmentCertificate(): ICertificate {\r\n const keys: pki.KeyPair = forge.pki.rsa.generateKeyPair(2048);\r\n const certificate: pki.Certificate = forge.pki.createCertificate();\r\n certificate.publicKey = keys.publicKey;\r\n\r\n certificate.serialNumber = SERIAL_NUMBER;\r\n\r\n const now: Date = new Date();\r\n certificate.validity.notBefore = now;\r\n // Valid for 3 years\r\n certificate.validity.notAfter.setFullYear(certificate.validity.notBefore.getFullYear() + 3);\r\n\r\n const attrs: pki.CertificateField[] = [\r\n {\r\n name: 'commonName',\r\n value: 'localhost'\r\n }\r\n ];\r\n\r\n certificate.setSubject(attrs);\r\n certificate.setIssuer(attrs);\r\n\r\n certificate.setExtensions([\r\n {\r\n name: 'subjectAltName',\r\n altNames: [\r\n {\r\n type: 2, // DNS\r\n value: 'localhost'\r\n }\r\n ]\r\n },\r\n {\r\n name: 'keyUsage',\r\n digitalSignature: true,\r\n keyEncipherment: true,\r\n dataEncipherment: true\r\n },\r\n {\r\n name: 'extKeyUsage',\r\n serverAuth: true\r\n },\r\n {\r\n name: 'friendlyName',\r\n value: FRIENDLY_NAME\r\n }\r\n ]);\r\n\r\n // self-sign certificate\r\n certificate.sign(keys.privateKey, forge.md.sha256.create());\r\n\r\n // convert a Forge certificate to PEM\r\n const pem: string = forge.pki.certificateToPem(certificate);\r\n const pemKey: string = forge.pki.privateKeyToPem(keys.privateKey);\r\n\r\n return {\r\n pemCertificate: pem,\r\n pemKey: pemKey\r\n };\r\n }\r\n\r\n private async _tryTrustCertificateAsync(certificatePath: string, terminal: ITerminal): Promise<boolean> {\r\n switch (process.platform) {\r\n case 'win32':\r\n terminal.writeLine(\r\n 'Attempting to trust a development certificate. This self-signed certificate only points to localhost ' +\r\n 'and will be stored in your local user profile to be used by other instances of ' +\r\n 'debug-certificate-manager. If you do not consent to trust this certificate, click \"NO\" in the dialog.'\r\n );\r\n\r\n const winTrustResult: IRunResult = await runAsync(CERTUTIL_EXE_NAME, [\r\n '-user',\r\n '-addstore',\r\n 'root',\r\n certificatePath\r\n ]);\r\n\r\n if (winTrustResult.code !== 0) {\r\n terminal.writeErrorLine(`Error: ${winTrustResult.stdout.toString()}`);\r\n\r\n const errorLines: string[] = winTrustResult.stdout\r\n .toString()\r\n .split(EOL)\r\n .map((line: string) => line.trim());\r\n\r\n // Not sure if this is always the status code for \"cancelled\" - should confirm.\r\n if (\r\n winTrustResult.code === 2147943623 ||\r\n errorLines[errorLines.length - 1].indexOf('The operation was canceled by the user.') > 0\r\n ) {\r\n terminal.writeLine('Certificate trust cancelled.');\r\n } else {\r\n terminal.writeErrorLine('Certificate trust failed with an unknown error.');\r\n }\r\n\r\n return false;\r\n } else {\r\n terminal.writeVerboseLine('Successfully trusted development certificate.');\r\n\r\n return true;\r\n }\r\n\r\n case 'darwin':\r\n terminal.writeLine(\r\n 'Attempting to trust a development certificate. This self-signed certificate only points to localhost ' +\r\n 'and will be stored in your local user profile to be used by other instances of ' +\r\n 'debug-certificate-manager. If you do not consent to trust this certificate, do not enter your ' +\r\n 'root password in the prompt.'\r\n );\r\n\r\n const result: IRunResult = await runSudoAsync('security', [\r\n 'add-trusted-cert',\r\n '-d',\r\n '-r',\r\n 'trustRoot',\r\n '-k',\r\n MAC_KEYCHAIN,\r\n certificatePath\r\n ]);\r\n\r\n if (result.code === 0) {\r\n terminal.writeVerboseLine('Successfully trusted development certificate.');\r\n return true;\r\n } else {\r\n if (\r\n result.stderr.some(\r\n (value: string) => !!value.match(/The authorization was cancelled by the user\\./)\r\n )\r\n ) {\r\n terminal.writeLine('Certificate trust cancelled.');\r\n return false;\r\n } else {\r\n terminal.writeErrorLine(\r\n `Certificate trust failed with an unknown error. Exit code: ${result.code}. ` +\r\n `Error: ${result.stderr.join(' ')}`\r\n );\r\n return false;\r\n }\r\n }\r\n\r\n default:\r\n // Linux + others: Have the user manually trust the cert if they want to\r\n terminal.writeLine(\r\n 'Automatic certificate trust is only implemented for debug-certificate-manager on Windows ' +\r\n 'and macOS. To trust the development certificate, add this certificate to your trusted root ' +\r\n `certification authorities: \"${certificatePath}\".`\r\n );\r\n return true;\r\n }\r\n }\r\n\r\n private async _detectIfCertificateIsTrustedAsync(terminal: ITerminal): Promise<boolean> {\r\n switch (process.platform) {\r\n case 'win32':\r\n const winVerifyStoreResult: IRunResult = await runAsync(CERTUTIL_EXE_NAME, [\r\n '-user',\r\n '-verifystore',\r\n 'root',\r\n SERIAL_NUMBER\r\n ]);\r\n\r\n if (winVerifyStoreResult.code !== 0) {\r\n terminal.writeVerboseLine(\r\n 'The development certificate was not found in the store. CertUtil error: ',\r\n winVerifyStoreResult.stderr.join(' ')\r\n );\r\n return false;\r\n } else {\r\n terminal.writeVerboseLine(\r\n 'The development certificate was found in the store. CertUtil output: ',\r\n winVerifyStoreResult.stdout.join(' ')\r\n );\r\n return true;\r\n }\r\n\r\n case 'darwin':\r\n terminal.writeVerboseLine('Trying to find the signature of the development certificate.');\r\n\r\n const macFindCertificateResult: IRunResult = await runAsync('security', [\r\n 'find-certificate',\r\n '-c',\r\n 'localhost',\r\n '-a',\r\n '-Z',\r\n MAC_KEYCHAIN\r\n ]);\r\n\r\n if (macFindCertificateResult.code !== 0) {\r\n terminal.writeVerboseLine(\r\n 'The development certificate was not found in keychain. Find certificate error: ',\r\n macFindCertificateResult.stderr.join(' ')\r\n );\r\n return false;\r\n }\r\n\r\n const shaHash: string | undefined = this._parseMacOsMatchingCertificateHash(\r\n macFindCertificateResult.stdout.join(EOL)\r\n );\r\n\r\n if (!shaHash) {\r\n terminal.writeVerboseLine(\r\n 'The development certificate was not found in keychain. Find certificate output:\\n',\r\n macFindCertificateResult.stdout.join(' ')\r\n );\r\n return false;\r\n }\r\n\r\n terminal.writeVerboseLine(`The development certificate was found in keychain.`);\r\n return true;\r\n\r\n default:\r\n // Linux + others: Have the user manually verify the cert is trusted\r\n terminal.writeVerboseLine(\r\n 'Automatic certificate trust validation is only implemented for debug-certificate-manager on Windows ' +\r\n 'and macOS. Manually verify this development certificate is present in your trusted ' +\r\n `root certification authorities: \"${this._certificateStore.certificatePath}\". ` +\r\n `The certificate has serial number \"${SERIAL_NUMBER}\".`\r\n );\r\n // Always return true on Linux to prevent breaking flow.\r\n return true;\r\n }\r\n }\r\n\r\n private async _trySetFriendlyNameAsync(certificatePath: string, terminal: ITerminal): Promise<boolean> {\r\n if (process.platform === 'win32') {\r\n const basePath: string = path.dirname(certificatePath);\r\n const fileName: string = path.basename(certificatePath, path.extname(certificatePath));\r\n const friendlyNamePath: string = path.join(basePath, `${fileName}.inf`);\r\n\r\n const friendlyNameFile: string = [\r\n '[Version]',\r\n 'Signature = \"$Windows NT$\"',\r\n '[Properties]',\r\n `11 = \"{text}${FRIENDLY_NAME}\"`,\r\n ''\r\n ].join(EOL);\r\n\r\n await FileSystem.writeFileAsync(friendlyNamePath, friendlyNameFile);\r\n\r\n const repairStoreResult: IRunResult = await runAsync(CERTUTIL_EXE_NAME, [\r\n '–repairstore',\r\n '–user',\r\n 'root',\r\n SERIAL_NUMBER,\r\n friendlyNamePath\r\n ]);\r\n\r\n if (repairStoreResult.code !== 0) {\r\n terminal.writeErrorLine(`CertUtil Error: ${repairStoreResult.stderr.join('')}`);\r\n return false;\r\n } else {\r\n terminal.writeVerboseLine('Successfully set certificate name.');\r\n return true;\r\n }\r\n } else {\r\n // No equivalent concept outside of Windows\r\n return true;\r\n }\r\n }\r\n\r\n private async _ensureCertificateInternalAsync(terminal: ITerminal): Promise<void> {\r\n const certificateStore: CertificateStore = this._certificateStore;\r\n const generatedCertificate: ICertificate = this._createDevelopmentCertificate();\r\n\r\n const now: Date = new Date();\r\n const certificateName: string = now.getTime().toString();\r\n const tempDirName: string = path.join(__dirname, '..', 'temp');\r\n\r\n const tempCertificatePath: string = path.join(tempDirName, `${certificateName}.pem`);\r\n const pemFileContents: string | undefined = generatedCertificate.pemCertificate;\r\n if (pemFileContents) {\r\n await FileSystem.writeFileAsync(tempCertificatePath, pemFileContents, {\r\n ensureFolderExists: true\r\n });\r\n }\r\n\r\n const trustCertificateResult: boolean = await this._tryTrustCertificateAsync(\r\n tempCertificatePath,\r\n terminal\r\n );\r\n if (trustCertificateResult) {\r\n certificateStore.certificateData = generatedCertificate.pemCertificate;\r\n certificateStore.keyData = generatedCertificate.pemKey;\r\n\r\n // Try to set the friendly name, and warn if we can't\r\n if (!this._trySetFriendlyNameAsync(tempCertificatePath, terminal)) {\r\n terminal.writeWarningLine(\"Unable to set the certificate's friendly name.\");\r\n }\r\n } else {\r\n // Clear out the existing store data, if any exists\r\n certificateStore.certificateData = undefined;\r\n certificateStore.keyData = undefined;\r\n }\r\n\r\n await FileSystem.deleteFileAsync(tempCertificatePath);\r\n }\r\n\r\n private _certificateHasSubjectAltName(): boolean {\r\n const certificateData: string | undefined = this._certificateStore.certificateData;\r\n if (!certificateData) {\r\n return false;\r\n }\r\n const certificate: pki.Certificate = forge.pki.certificateFromPem(certificateData);\r\n return !!certificate.getExtension('subjectAltName');\r\n }\r\n\r\n private _parseMacOsMatchingCertificateHash(findCertificateOuput: string): string | undefined {\r\n let shaHash: string | undefined = undefined;\r\n for (const line of findCertificateOuput.split(EOL)) {\r\n // Sets `shaHash` to the current certificate SHA-1 as we progress through the lines of certificate text.\r\n const shaHashMatch: string[] | null = line.match(/^SHA-1 hash: (.+)$/);\r\n if (shaHashMatch) {\r\n shaHash = shaHashMatch[1];\r\n }\r\n\r\n const snbrMatch: string[] | null = line.match(/^\\s*\"snbr\"<blob>=0x([^\\s]+).+$/);\r\n if (snbrMatch && (snbrMatch[1] || '').toLowerCase() === SERIAL_NUMBER) {\r\n return shaHash;\r\n }\r\n }\r\n }\r\n}\r\n"]}
@@ -3,6 +3,11 @@ export interface IRunResult {
3
3
  stderr: string[];
4
4
  code: number;
5
5
  }
6
+ export interface ISudoOptions {
7
+ cachePassword?: boolean;
8
+ prompt?: string;
9
+ spawnOptions?: object;
10
+ }
6
11
  export declare function runSudoAsync(command: string, params: string[]): Promise<IRunResult>;
7
12
  export declare function runAsync(command: string, params: string[]): Promise<IRunResult>;
8
- //# sourceMappingURL=exec.d.ts.map
13
+ //# sourceMappingURL=runCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runCommand.d.ts","sourceRoot":"","sources":["../src/runCommand.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAOzF;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAGrF"}
@@ -5,7 +5,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.runAsync = exports.runSudoAsync = void 0;
6
6
  const node_core_library_1 = require("@rushstack/node-core-library");
7
7
  async function runSudoAsync(command, params) {
8
- // eslint-disable-next-line
9
8
  const sudo = require('sudo');
10
9
  const result = sudo([command, ...params], {
11
10
  cachePassword: false,
@@ -35,4 +34,4 @@ async function _handleChildProcess(childProcess) {
35
34
  });
36
35
  });
37
36
  }
38
- //# sourceMappingURL=exec.js.map
37
+ //# sourceMappingURL=runCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runCommand.js","sourceRoot":"","sources":["../src/runCommand.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,oEAA0D;AAenD,KAAK,UAAU,YAAY,CAAC,OAAe,EAAE,MAAgB;IAClE,MAAM,IAAI,GAA0E,OAAO,CAAC,MAAM,CAAC,CAAC;IACpG,MAAM,MAAM,GAA+B,IAAI,CAAC,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,EAAE;QACpE,aAAa,EAAE,KAAK;QACpB,MAAM,EAAE,uBAAuB;KAChC,CAAC,CAAC;IACH,OAAO,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC3C,CAAC;AAPD,oCAOC;AAEM,KAAK,UAAU,QAAQ,CAAC,OAAe,EAAE,MAAgB;IAC9D,MAAM,MAAM,GAA+B,8BAAU,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7E,OAAO,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC3C,CAAC;AAHD,4BAGC;AAED,KAAK,UAAU,mBAAmB,CAAC,YAAwC;IACzE,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC,OAAqC,EAAE,EAAE;;QACjE,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAA,YAAY,CAAC,MAAM,0CAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YAC/C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAA,YAAY,CAAC,MAAM,0CAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YAC/C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAY,EAAE,EAAE;YACxC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\r\n// See LICENSE in the project root for license information.\r\n\r\nimport { Executable } from '@rushstack/node-core-library';\r\nimport * as child_process from 'child_process';\r\n\r\nexport interface IRunResult {\r\n stdout: string[];\r\n stderr: string[];\r\n code: number;\r\n}\r\n\r\nexport interface ISudoOptions {\r\n cachePassword?: boolean;\r\n prompt?: string;\r\n spawnOptions?: object;\r\n}\r\n\r\nexport async function runSudoAsync(command: string, params: string[]): Promise<IRunResult> {\r\n const sudo: (args: string[], options: ISudoOptions) => child_process.ChildProcess = require('sudo');\r\n const result: child_process.ChildProcess = sudo([command, ...params], {\r\n cachePassword: false,\r\n prompt: 'Enter your password: '\r\n });\r\n return await _handleChildProcess(result);\r\n}\r\n\r\nexport async function runAsync(command: string, params: string[]): Promise<IRunResult> {\r\n const result: child_process.ChildProcess = Executable.spawn(command, params);\r\n return await _handleChildProcess(result);\r\n}\r\n\r\nasync function _handleChildProcess(childProcess: child_process.ChildProcess): Promise<IRunResult> {\r\n return await new Promise((resolve: (result: IRunResult) => void) => {\r\n const stderr: string[] = [];\r\n childProcess.stderr?.on('data', (data: Buffer) => {\r\n stderr.push(data.toString());\r\n });\r\n\r\n const stdout: string[] = [];\r\n childProcess.stdout?.on('data', (data: Buffer) => {\r\n stdout.push(data.toString());\r\n });\r\n\r\n childProcess.on('close', (code: number) => {\r\n resolve({ code, stdout, stderr });\r\n });\r\n });\r\n}\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rushstack/debug-certificate-manager",
3
- "version": "1.1.11",
3
+ "version": "1.1.15",
4
4
  "description": "Cross-platform functionality to create debug ssl certificates.",
5
5
  "main": "lib/index.js",
6
6
  "typings": "dist/debug-certificate-manager.d.ts",
@@ -11,14 +11,14 @@
11
11
  "directory": "libraries/debug-certificate-manager"
12
12
  },
13
13
  "dependencies": {
14
- "@rushstack/node-core-library": "3.43.2",
14
+ "@rushstack/node-core-library": "3.44.0",
15
15
  "node-forge": "~0.10.0",
16
16
  "sudo": "~1.0.3"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@rushstack/eslint-config": "2.4.5",
20
- "@rushstack/heft": "0.42.2",
21
- "@rushstack/heft-node-rig": "1.2.30",
20
+ "@rushstack/heft": "0.42.4",
21
+ "@rushstack/heft-node-rig": "1.2.33",
22
22
  "@types/heft-jest": "1.0.1",
23
23
  "@types/node": "12.20.24",
24
24
  "@types/node-forge": "0.10.2"
package/lib/exec.d.ts.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../src/exec.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAQzF;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAGrF"}
package/lib/exec.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"exec.js","sourceRoot":"","sources":["../src/exec.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,oEAA0D;AASnD,KAAK,UAAU,YAAY,CAAC,OAAe,EAAE,MAAgB;IAClE,2BAA2B;IAC3B,MAAM,IAAI,GAAiE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3F,MAAM,MAAM,GAA+B,IAAI,CAAC,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,EAAE;QACpE,aAAa,EAAE,KAAK;QACpB,MAAM,EAAE,uBAAuB;KAChC,CAAC,CAAC;IACH,OAAO,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC3C,CAAC;AARD,oCAQC;AAEM,KAAK,UAAU,QAAQ,CAAC,OAAe,EAAE,MAAgB;IAC9D,MAAM,MAAM,GAA+B,8BAAU,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7E,OAAO,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC3C,CAAC;AAHD,4BAGC;AAED,KAAK,UAAU,mBAAmB,CAAC,YAAwC;IACzE,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC,OAAqC,EAAE,EAAE;;QACjE,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAA,YAAY,CAAC,MAAM,0CAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YAC/C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAA,YAAY,CAAC,MAAM,0CAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YAC/C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAY,EAAE,EAAE;YACxC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\r\n// See LICENSE in the project root for license information.\r\n\r\nimport { Executable } from '@rushstack/node-core-library';\r\nimport * as child_process from 'child_process';\r\n\r\nexport interface IRunResult {\r\n stdout: string[];\r\n stderr: string[];\r\n code: number;\r\n}\r\n\r\nexport async function runSudoAsync(command: string, params: string[]): Promise<IRunResult> {\r\n // eslint-disable-next-line\r\n const sudo: (args: string[], options: any) => child_process.ChildProcess = require('sudo');\r\n const result: child_process.ChildProcess = sudo([command, ...params], {\r\n cachePassword: false,\r\n prompt: 'Enter your password: '\r\n });\r\n return await _handleChildProcess(result);\r\n}\r\n\r\nexport async function runAsync(command: string, params: string[]): Promise<IRunResult> {\r\n const result: child_process.ChildProcess = Executable.spawn(command, params);\r\n return await _handleChildProcess(result);\r\n}\r\n\r\nasync function _handleChildProcess(childProcess: child_process.ChildProcess): Promise<IRunResult> {\r\n return await new Promise((resolve: (result: IRunResult) => void) => {\r\n const stderr: string[] = [];\r\n childProcess.stderr?.on('data', (data: Buffer) => {\r\n stderr.push(data.toString());\r\n });\r\n\r\n const stdout: string[] = [];\r\n childProcess.stdout?.on('data', (data: Buffer) => {\r\n stdout.push(data.toString());\r\n });\r\n\r\n childProcess.on('close', (code: number) => {\r\n resolve({ code, stdout, stderr });\r\n });\r\n });\r\n}\r\n"]}