@jsenv/https-local 1.0.1 → 1.0.6

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/README.md CHANGED
@@ -30,7 +30,11 @@ npm install --save-dev @jsenv/https-local
30
30
  *
31
31
  * Read more in https://github.com/jsenv/https-local#installCertificateAuthority
32
32
  */
33
- import { installCertificateAuthority, verifyHostsFile } from "@jsenv/https-local"
33
+
34
+ import {
35
+ installCertificateAuthority,
36
+ verifyHostsFile,
37
+ } from "@jsenv/https-local"
34
38
 
35
39
  await installCertificateAuthority({
36
40
  tryToTrust: true,
@@ -38,13 +42,13 @@ await installCertificateAuthority({
38
42
  })
39
43
  await verifyHostsFile({
40
44
  ipMappings: {
41
- "127.0.0.1": ["localhost", "local.example.com"],
45
+ "127.0.0.1": ["localhost"],
42
46
  },
43
47
  tryToUpdatesHostsFile: true,
44
48
  })
45
49
  ```
46
50
 
47
- 3 - Install certificate authority
51
+ 3 - Run file to install certificate authority with node
48
52
 
49
53
  ```console
50
54
  node ./install_certificate_authority.mjs
@@ -55,7 +59,7 @@ node ./install_certificate_authority.mjs
55
59
  ```js
56
60
  /*
57
61
  * This file uses "@jsenv/https-local" to obtain a certificate used to start a server in https.
58
- * The certificate is valid for 396 days and is issued by a certificate authority trusted on this machine.
62
+ * The certificate is valid for 1 year (396 days) and is issued by a certificate authority trusted on this machine.
59
63
  * If the certificate authority was not installed before executing this file, an error is thrown
60
64
  * explaining that certificate authority must be installed first.
61
65
  *
@@ -65,12 +69,12 @@ node ./install_certificate_authority.mjs
65
69
  *
66
70
  * Read more in https://github.com/jsenv/https-local#requestCertificateForLocalhost
67
71
  */
72
+
68
73
  import { createServer } from "node:https"
69
74
  import { requestCertificateForLocalhost } from "@jsenv/https-local"
70
75
 
71
- const { serverCertificate, serverCertificatePrivateKey } = await requestCertificateForLocalhost({
72
- serverCertificateAltNames: ["localhost", "local.example"],
73
- })
76
+ const { serverCertificate, serverCertificatePrivateKey } =
77
+ await requestCertificateForLocalhost()
74
78
 
75
79
  const server = createServer(
76
80
  {
@@ -91,12 +95,15 @@ server.listen(8080)
91
95
  console.log(`Server listening at https://local.example:8080`)
92
96
  ```
93
97
 
94
- 5 - Start your server
98
+ 5 - Run file to start server with node
95
99
 
96
100
  ```console
97
101
  node ./start_dev_server.mjs
98
102
  ```
99
103
 
104
+ At this stage of the documentation you have a server running in https.
105
+ The rest of the documentation goes into details.
106
+
100
107
  # Certificate expiration
101
108
 
102
109
  The server certificate expires after one year which is the maximum duration allowed by web browsers.
@@ -105,7 +112,7 @@ In the unlikely scenario where your local server is running for more than a year
105
112
 
106
113
  The authority root certificate expires after 20 years which is close to the maximum allowed duration.
107
114
 
108
- In the very unlikely scenario where you are using the same machine for more than 20 years, re-execute [installCertificateAuthority](#installCertificateAuthority) to update certificate authority and restart your server.
115
+ In the very unlikely scenario where you are using the same machine for more than 20 years, re-execute [installCertificateAuthority](#installCertificateAuthority) to update certificate authority then restart your server.
109
116
 
110
117
  # installCertificateAuthority
111
118
 
@@ -118,6 +125,11 @@ import { installCertificateAuthority } from "@jsenv/https-local"
118
125
  await installCertificateAuthority()
119
126
  ```
120
127
 
128
+ By default, trusting authority root certificate is a manual process.
129
+ This manual process is documented in [BenMorel/dev-certificates#Import the CA in your browser](https://github.com/BenMorel/dev-certificates/tree/c10cd68945da772f31815b7a36721ddf848ff3a3#import-the-ca-in-your-browser).
130
+
131
+ Trusting the root certificate can also be done programmatically as explained in [Auto trust](#Auto-trust).
132
+
121
133
  Find below logs written in terminal when this function is executed.
122
134
 
123
135
  <details>
@@ -216,11 +228,6 @@ Check if certificate is trusted by firefox...
216
228
 
217
229
  </details>
218
230
 
219
- By default, trusting authority root certificate is a manual process.
220
- This manual process is documented in [BenMorel/dev-certificates#Import the CA in your browser](https://github.com/BenMorel/dev-certificates/tree/c10cd68945da772f31815b7a36721ddf848ff3a3#import-the-ca-in-your-browser).
221
-
222
- Trusting the root certificate can also be done programmatically as explained the next part.
223
-
224
231
  ## Auto trust
225
232
 
226
233
  It's possible to trust root certificate programmatically using _tryToTrust_
@@ -269,7 +276,7 @@ Check if certificate is in Firefox...
269
276
  </details>
270
277
 
271
278
  <details>
272
- <summary>windows</summary>
279
+ <summary>linux</summary>
273
280
 
274
281
  ```console
275
282
  > node ./install_certificate_authority.mjs
@@ -280,7 +287,7 @@ Checking certificate validity...
280
287
  Detect if certificate attributes have changed...
281
288
  ✔ certificate attributes are the same
282
289
  Check if certificate is in linux...
283
- ℹ certificate in linux is outdated
290
+ ℹ certificate not in linux
284
291
  Adding certificate to linux...
285
292
  ❯ sudo /bin/cp -f "/home/dmail/.config/https_local/https_local_root_certificate.crt" /usr/local/share/ca-certificates/https_local_root_certificate.crt
286
293
  [sudo] Password for dmail :
@@ -329,11 +336,11 @@ Detect if certificate attributes have changed...
329
336
  ✔ certificate attributes are the same
330
337
  Check if certificate is trusted by windows...
331
338
  ℹ certificate not trusted by windows
332
- Check if certificate is trusted by firefox...
333
- ℹ unable to detect if certificate is trusted by firefox (not implemented on windows)
334
339
  Adding certificate to windows...
335
340
  ❯ certutil -addstore -user root C:\Users\Dmail\AppData\Local\https_local\https_local_root_certificate.crt
336
341
  ✔ certificate added to windows
342
+ Check if certificate is trusted by firefox...
343
+ ℹ unable to detect if certificate is trusted by firefox (not implemented on windows)
337
344
  ```
338
345
 
339
346
  _second execution logs_
@@ -354,16 +361,33 @@ Check if certificate is trusted by firefox...
354
361
 
355
362
  </details>
356
363
 
364
+ # requestCertificateForLocalhost
365
+
366
+ _requestCertificateForLocalhost_ function returns a certificate and private key that can be used to start a server in HTTPS.
367
+
368
+ ```js
369
+ import { createServer } from "node:https"
370
+ import { requestCertificateForLocalhost } from "@jsenv/https-local"
371
+
372
+ const { serverCertificate, serverCertificatePrivateKey } =
373
+ await requestCertificateForLocalhost({
374
+ serverCertificateAltNames: ["localhost", "local.example"],
375
+ })
376
+ ```
377
+
378
+ [installCertificateAuthority](#installCertificateAuthority) must be called before this function.
379
+
357
380
  # verifyHostsFile
358
381
 
359
- _verifyHostsFile_ function check your hosts file content to see if ip mappings are present.
382
+ This function is not mandatory to obtain the https certificates.
383
+ But it is useful to programmatically verify ip mappings that are important for your local server are present in hosts file.
360
384
 
361
385
  ```js
362
386
  import { verifyHostsFile } from "@jsenv/https-local"
363
387
 
364
388
  await verifyHostsFile({
365
389
  ipMappings: {
366
- "127.0.0.1": ["localhost", "local.example.com"],
390
+ "127.0.0.1": ["localhost", "local.example"],
367
391
  },
368
392
  })
369
393
  ```
@@ -381,7 +405,7 @@ Check hosts file content...
381
405
  --- hosts file path ---
382
406
  /etc/hosts
383
407
  --- line(s) to add ---
384
- 127.0.0.1 localhost local.example.com
408
+ 127.0.0.1 localhost local.example
385
409
  ```
386
410
 
387
411
  </details>
@@ -397,7 +421,7 @@ Check hosts file content...
397
421
  --- hosts file path ---
398
422
  C:\\Windows\\System32\\Drivers\\etc\\hosts
399
423
  --- line(s) to add ---
400
- 127.0.0.1 localhost local.example.com
424
+ 127.0.0.1 localhost local.example
401
425
  ```
402
426
 
403
427
  </details>
@@ -411,7 +435,7 @@ import { verifyHostsFile } from "@jsenv/https-local"
411
435
 
412
436
  await verifyHostsFile({
413
437
  ipMappings: {
414
- "127.0.0.1": ["localhost", "local.example.com"],
438
+ "127.0.0.1": ["localhost", "local.example"],
415
439
  },
416
440
  tryToUpdateHostsFile: true,
417
441
  })
@@ -424,7 +448,7 @@ await verifyHostsFile({
424
448
  Check hosts file content...
425
449
  ℹ 1 mapping is missing in hosts file
426
450
  Adding 1 mapping(s) in hosts file...
427
- ❯ echo "127.0.0.1 local.example.com" | sudo tee /etc/hosts
451
+ ❯ echo "127.0.0.1 local.example" | sudo tee -a /etc/hosts
428
452
  Password:
429
453
  ✔ mappings added to hosts file
430
454
  ```
@@ -447,7 +471,7 @@ Check hosts file content...
447
471
  Check hosts file content...
448
472
  ℹ 1 mapping is missing in hosts file
449
473
  Adding 1 mapping(s) in hosts file...
450
- ❯ (echo 127.0.0.1 local.example.com) >> C:\\Windows\\System32\\Drivers\\etc\\hosts
474
+ ❯ (echo 127.0.0.1 local.example) >> C:\\Windows\\System32\\Drivers\\etc\\hosts
451
475
  Password:
452
476
  ✔ mappings added to hosts file
453
477
  ```
@@ -462,36 +486,3 @@ Check hosts file content...
462
486
  ```
463
487
 
464
488
  </details>
465
-
466
- # requestCertificateForLocalhost
467
-
468
- _requestCertificateForLocalhost_ function returns a certificate and private key that can be used to start a server in HTTPS.
469
-
470
- ```js
471
- import { createServer } from "node:https"
472
- import { requestCertificateForLocalhost } from "@jsenv/https-local"
473
-
474
- const { serverCertificate, serverCertificatePrivateKey } = await requestCertificateForLocalhost({
475
- serverCertificateAltNames: ["localhost", "local.example.com"],
476
- })
477
-
478
- const server = createServer(
479
- {
480
- cert: serverCertificate,
481
- key: serverCertificatePrivateKey,
482
- },
483
- (request, response) => {
484
- const body = "Hello world"
485
- response.writeHead(200, {
486
- "content-type": "text/plain",
487
- "content-length": Buffer.byteLength(body),
488
- })
489
- response.write(body)
490
- response.end()
491
- },
492
- )
493
- server.listen(8080)
494
- console.log(`Server listening at https://localhost:8080`)
495
- ```
496
-
497
- [installCertificateAuthority](#installCertificateAuthority) must be called before this function.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/https-local",
3
- "version": "1.0.1",
3
+ "version": "1.0.6",
4
4
  "description": "A programmatic way to generate locally trusted certificates",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -13,11 +13,10 @@
13
13
  "url": "https://github.com/jsenv/https-local"
14
14
  },
15
15
  "engines": {
16
- "node": ">=14.17.0"
16
+ "node": ">=16.13.0"
17
17
  },
18
18
  "publishConfig": {
19
- "access": "public",
20
- "registry": "https://registry.npmjs.org"
19
+ "access": "public"
21
20
  },
22
21
  "type": "module",
23
22
  "exports": {
@@ -26,14 +25,17 @@
26
25
  },
27
26
  "./*": "./*"
28
27
  },
28
+ "main": "./main.js",
29
29
  "files": [
30
30
  "/src/",
31
31
  "/main.js"
32
32
  ],
33
33
  "scripts": {
34
- "eslint-check": "node ./node_modules/eslint/bin/eslint.js .",
35
- "generate-importmap": "node ./script/importmap/generate_importmap.mjs",
36
- "measure-performances": "node ./script/performance/generate_performance_report.mjs --local",
34
+ "eslint": "node ./node_modules/eslint/bin/eslint.js . --ext=.js,.mjs",
35
+ "importmap": "node ./script/importmap/importmap.mjs",
36
+ "performances": "node --expose-gc ./script/performance/generate_performance_report.mjs --log",
37
+ "test": "node ./script/test/test.mjs",
38
+ "test-with-coverage": "npm run test -- --coverage",
37
39
  "start-node-server": "node ./script/certificate/start_node_server.mjs",
38
40
  "log-root-certificate-trust": "node ./script/certificate/log_root_certificate_trust.mjs",
39
41
  "trust-root-certificate": "node ./script/certificate/trust_root_certificate.mjs",
@@ -43,39 +45,31 @@
43
45
  "remove-localhost-mappings": "node ./script/hosts/remove_localhost_mappings.mjs",
44
46
  "verify-localhost-mappings": "node ./script/hosts/verify_localhost_mappings.mjs",
45
47
  "ensure-localhost-mappings": "node ./script/hosts/ensure_localhost_mappings.mjs",
46
- "test": "node ./script/test/test.mjs",
47
- "test-with-coverage": "npm run test -- --coverage",
48
- "prettier-format": "node ./script/prettier/prettier_format.mjs",
49
- "prettier-format-stage": "npm run prettier-format -- --staged",
50
- "prettier-check": "npm run prettier-format -- --dry-run",
51
- "install-playwright": "npx playwright install-deps && npx playwright install",
52
- "prepublishOnly": "node ./script/publish/remove_postinstall.mjs",
53
- "postpublish": "node ./script/publish/restore_postinstall.mjs"
48
+ "prettier": "prettier --write .",
49
+ "playwright-install": "npx playwright install-deps && npx playwright install"
54
50
  },
55
51
  "dependencies": {
56
- "@jsenv/filesystem": "2.1.1",
52
+ "@jsenv/filesystem": "2.7.1",
57
53
  "@jsenv/logger": "4.0.1",
58
54
  "command-exists": "1.2.9",
59
55
  "is-unicode-supported": "1.1.0",
60
- "node-forge": "0.10.0",
56
+ "node-forge": "1.2.1",
61
57
  "sudo-prompt": "9.2.1",
62
- "supports-color": "9.0.2",
58
+ "supports-color": "9.2.1",
63
59
  "which": "2.0.2"
64
60
  },
65
61
  "devDependencies": {
66
- "@jsenv/assert": "2.3.0",
67
- "@jsenv/codecov-upload": "3.5.0",
68
- "@jsenv/core": "19.6.2",
69
- "@jsenv/eslint-config": "15.0.2",
70
- "@jsenv/github-release-package": "1.2.3",
71
- "@jsenv/importmap-eslint-resolver": "5.1.0",
72
- "@jsenv/importmap-node-module": "1.0.1",
73
- "@jsenv/package-publish": "1.6.2",
74
- "@jsenv/performance-impact": "1.7.0",
75
- "@jsenv/prettier-check-project": "5.6.1",
76
- "eslint": "7.32.0",
77
- "eslint-plugin-import": "2.24.0",
78
- "playwright": "1.14.0",
79
- "prettier": "2.3.2"
62
+ "@jsenv/assert": "2.4.1",
63
+ "@jsenv/core": "25.3.0",
64
+ "@jsenv/eslint-config": "16.0.9",
65
+ "@jsenv/github-release-package": "1.3.3",
66
+ "@jsenv/importmap-eslint-resolver": "5.2.5",
67
+ "@jsenv/importmap-node-module": "5.1.3",
68
+ "@jsenv/package-publish": "1.7.2",
69
+ "@jsenv/performance-impact": "2.2.4",
70
+ "eslint": "8.7.0",
71
+ "eslint-plugin-import": "2.25.4",
72
+ "playwright": "1.18.0",
73
+ "prettier": "2.5.1"
80
74
  }
81
- }
75
+ }
@@ -1,12 +1,13 @@
1
- /* eslint-disable import/max-dependencies */
2
-
3
- import { createLogger, createDetailedMessage } from "@jsenv/logger"
4
1
  import { readFile, writeFile, removeFileSystemNode } from "@jsenv/filesystem"
2
+ import { createLogger, createDetailedMessage } from "@jsenv/logger"
5
3
 
6
4
  import { infoSign, okSign } from "./internal/logs.js"
7
5
  import { getAuthorityFileInfos } from "./internal/authority_file_infos.js"
8
6
  import { attributeDescriptionFromAttributeArray } from "./internal/certificate_data_converter.js"
9
- import { formatTimeDelta, formatDuration } from "./internal/validity_formatting.js"
7
+ import {
8
+ formatTimeDelta,
9
+ formatDuration,
10
+ } from "./internal/validity_formatting.js"
10
11
  import { importNodeForge } from "./internal/forge.js"
11
12
  import { createAuthorityRootCertificate } from "./internal/certificate_generator.js"
12
13
  import { importPlatformMethods } from "./internal/platform.js"
@@ -54,8 +55,11 @@ export const installCertificateAuthority = async ({
54
55
  )
55
56
  }
56
57
 
57
- const { authorityJsonFileInfo, rootCertificateFileInfo, rootCertificatePrivateKeyFileInfo } =
58
- getAuthorityFileInfos()
58
+ const {
59
+ authorityJsonFileInfo,
60
+ rootCertificateFileInfo,
61
+ rootCertificatePrivateKeyFileInfo,
62
+ } = getAuthorityFileInfos()
59
63
  const authorityJsonFileUrl = authorityJsonFileInfo.url
60
64
  const rootCertificateFileUrl = rootCertificateFileInfo.url
61
65
  const rootPrivateKeyFileUrl = rootCertificatePrivateKeyFileInfo.url
@@ -76,16 +80,23 @@ export const installCertificateAuthority = async ({
76
80
  })
77
81
 
78
82
  const { pki } = await importNodeForge()
79
- const rootCertificate = pemAsFileContent(pki.certificateToPem(rootCertificateForgeObject))
83
+ const rootCertificate = pemAsFileContent(
84
+ pki.certificateToPem(rootCertificateForgeObject),
85
+ )
80
86
  const rootCertificatePrivateKey = pemAsFileContent(
81
87
  pki.privateKeyToPem(rootCertificatePrivateKeyForgeObject),
82
88
  )
83
89
 
84
90
  await writeFile(rootCertificateFileUrl, rootCertificate)
85
91
  await writeFile(rootPrivateKeyFileUrl, rootCertificatePrivateKey)
86
- await writeFile(authorityJsonFileUrl, JSON.stringify({ serialNumber: 0 }, null, " "))
92
+ await writeFile(
93
+ authorityJsonFileUrl,
94
+ JSON.stringify({ serialNumber: 0 }, null, " "),
95
+ )
87
96
 
88
- logger.info(`${okSign} authority root certificate written at ${rootCertificateFileInfo.path}`)
97
+ logger.info(
98
+ `${okSign} authority root certificate written at ${rootCertificateFileInfo.path}`,
99
+ )
89
100
  return {
90
101
  rootCertificateForgeObject,
91
102
  rootCertificatePrivateKeyForgeObject,
@@ -140,14 +151,18 @@ export const installCertificateAuthority = async ({
140
151
  logger.debug(
141
152
  `Authority root certificate is not on filesystem at ${rootCertificateFileInfo.path}`,
142
153
  )
143
- logger.info(`${infoSign} authority root certificate not found in filesystem`)
154
+ logger.info(
155
+ `${infoSign} authority root certificate not found in filesystem`,
156
+ )
144
157
  return generate()
145
158
  }
146
159
  if (!rootCertificatePrivateKeyFileInfo.exists) {
147
160
  logger.debug(
148
161
  `Authority root certificate private key is not on filesystem at ${rootCertificatePrivateKeyFileInfo.path}`,
149
162
  )
150
- logger.info(`${infoSign} authority root certificate not found in filesystem`)
163
+ logger.info(
164
+ `${infoSign} authority root certificate not found in filesystem`,
165
+ )
151
166
  return generate()
152
167
  }
153
168
  logger.debug(
@@ -155,18 +170,23 @@ export const installCertificateAuthority = async ({
155
170
  )
156
171
  logger.info(`${okSign} authority root certificate found in filesystem`)
157
172
 
158
- const rootCertificate = await readFile(rootCertificateFileInfo.path, { as: "string" })
173
+ const rootCertificate = await readFile(rootCertificateFileInfo.path, {
174
+ as: "string",
175
+ })
159
176
  const { pki } = await importNodeForge()
160
177
  const rootCertificateForgeObject = pki.certificateFromPem(rootCertificate)
161
178
 
162
179
  logger.info(`Checking certificate validity...`)
163
- const rootCertificateValidityDurationInMs = getCertificateValidityDurationInMs(
180
+ const rootCertificateValidityDurationInMs =
181
+ getCertificateValidityDurationInMs(rootCertificateForgeObject)
182
+ const rootCertificateValidityRemainingMs = getCertificateRemainingMs(
164
183
  rootCertificateForgeObject,
165
184
  )
166
- const rootCertificateValidityRemainingMs = getCertificateRemainingMs(rootCertificateForgeObject)
167
185
  if (rootCertificateValidityRemainingMs < 0) {
168
186
  logger.info(
169
- `${infoSign} certificate expired ${formatTimeDelta(rootCertificateValidityRemainingMs)}`,
187
+ `${infoSign} certificate expired ${formatTimeDelta(
188
+ rootCertificateValidityRemainingMs,
189
+ )}`,
170
190
  )
171
191
  return regenerate()
172
192
  }
@@ -174,30 +194,44 @@ export const installCertificateAuthority = async ({
174
194
  rootCertificateValidityRemainingMs / rootCertificateValidityDurationInMs
175
195
  if (rootCertificateValidityRemainingRatio < aboutToExpireRatio) {
176
196
  logger.info(
177
- `${infoSign} certificate will expire ${formatTimeDelta(rootCertificateValidityRemainingMs)}`,
197
+ `${infoSign} certificate will expire ${formatTimeDelta(
198
+ rootCertificateValidityRemainingMs,
199
+ )}`,
178
200
  )
179
201
  return regenerate()
180
202
  }
181
203
  logger.info(
182
- `${okSign} certificate still valid for ${formatDuration(rootCertificateValidityRemainingMs)}`,
204
+ `${okSign} certificate still valid for ${formatDuration(
205
+ rootCertificateValidityRemainingMs,
206
+ )}`,
183
207
  )
184
208
 
185
209
  logger.info(`Detect if certificate attributes have changed...`)
186
- const rootCertificateDifferences = compareRootCertificateAttributes(rootCertificateForgeObject, {
187
- certificateCommonName,
188
- certificateValidityDurationInMs,
189
- })
210
+ const rootCertificateDifferences = compareRootCertificateAttributes(
211
+ rootCertificateForgeObject,
212
+ {
213
+ certificateCommonName,
214
+ certificateValidityDurationInMs,
215
+ },
216
+ )
190
217
  if (rootCertificateDifferences.length) {
191
218
  const paramNames = Object.keys(rootCertificateDifferences)
192
- logger.info(`${infoSign} certificate attributes are outdated: ${paramNames}`)
219
+ logger.info(
220
+ `${infoSign} certificate attributes are outdated: ${paramNames}`,
221
+ )
193
222
  return regenerate()
194
223
  }
195
224
  logger.info(`${okSign} certificate attributes are the same`)
196
225
 
197
- const rootCertificatePrivateKey = await readFile(rootCertificatePrivateKeyFileInfo.path, {
198
- as: "string",
199
- })
200
- const rootCertificatePrivateKeyForgeObject = pki.privateKeyFromPem(rootCertificatePrivateKey)
226
+ const rootCertificatePrivateKey = await readFile(
227
+ rootCertificatePrivateKeyFileInfo.path,
228
+ {
229
+ as: "string",
230
+ },
231
+ )
232
+ const rootCertificatePrivateKeyForgeObject = pki.privateKeyFromPem(
233
+ rootCertificatePrivateKey,
234
+ )
201
235
 
202
236
  const trustInfo = await platformMethods.executeTrustQuery({
203
237
  logger,
@@ -272,8 +306,11 @@ export const uninstallCertificateAuthority = async ({
272
306
  logger = createLogger({ logLevel }),
273
307
  tryToUntrust = false,
274
308
  } = {}) => {
275
- const { authorityJsonFileInfo, rootCertificateFileInfo, rootCertificatePrivateKeyFileInfo } =
276
- getAuthorityFileInfos()
309
+ const {
310
+ authorityJsonFileInfo,
311
+ rootCertificateFileInfo,
312
+ rootCertificatePrivateKeyFileInfo,
313
+ } = getAuthorityFileInfos()
277
314
 
278
315
  const filesToRemove = []
279
316
 
@@ -283,7 +320,9 @@ export const uninstallCertificateAuthority = async ({
283
320
  if (rootCertificateFileInfo.exists) {
284
321
  // first untrust the root cert file
285
322
  if (tryToUntrust) {
286
- const rootCertificate = await readFile(rootCertificateFileInfo.url, { as: "string" })
323
+ const rootCertificate = await readFile(rootCertificateFileInfo.url, {
324
+ as: "string",
325
+ })
287
326
  const { pki } = await importNodeForge()
288
327
  const rootCertificateForgeObject = pki.certificateFromPem(rootCertificate)
289
328
  const rootCertificateCommonName = attributeDescriptionFromAttributeArray(
@@ -15,7 +15,7 @@ export const requestCertificateForLocalhost = async ({
15
15
  logLevel,
16
16
  logger = createLogger({ logLevel }), // to be able to catch logs during unit tests
17
17
 
18
- serverCertificateAltNames = [],
18
+ serverCertificateAltNames = ["localhost"],
19
19
  serverCertificateCommonName = "https local server certificate",
20
20
  serverCertificateValidityDurationInMs = createValidityDurationOfXDays(396),
21
21
  } = {}) => {
@@ -41,8 +41,11 @@ export const requestCertificateForLocalhost = async ({
41
41
  )
42
42
  }
43
43
 
44
- const { authorityJsonFileInfo, rootCertificateFileInfo, rootCertificatePrivateKeyFileInfo } =
45
- getAuthorityFileInfos()
44
+ const {
45
+ authorityJsonFileInfo,
46
+ rootCertificateFileInfo,
47
+ rootCertificatePrivateKeyFileInfo,
48
+ } = getAuthorityFileInfos()
46
49
  if (!rootCertificateFileInfo.exists) {
47
50
  throw new Error(
48
51
  `Certificate authority not found, "installCertificateAuthority" must be called before "requestCertificateForLocalhost"`,
@@ -57,16 +60,26 @@ export const requestCertificateForLocalhost = async ({
57
60
 
58
61
  logger.debug(`Restoring certificate authority from filesystem...`)
59
62
  const { pki } = await importNodeForge()
60
- const rootCertificate = await readFile(rootCertificateFileInfo.url, { as: "string" })
61
- const rootCertificatePrivateKey = await readFile(rootCertificatePrivateKeyFileInfo.url, {
63
+ const rootCertificate = await readFile(rootCertificateFileInfo.url, {
62
64
  as: "string",
63
65
  })
64
- const certificateAuthorityData = await readFile(authorityJsonFileInfo.url, { as: "json" })
66
+ const rootCertificatePrivateKey = await readFile(
67
+ rootCertificatePrivateKeyFileInfo.url,
68
+ {
69
+ as: "string",
70
+ },
71
+ )
72
+ const certificateAuthorityData = await readFile(authorityJsonFileInfo.url, {
73
+ as: "json",
74
+ })
65
75
  const rootCertificateForgeObject = pki.certificateFromPem(rootCertificate)
66
- const rootCertificatePrivateKeyForgeObject = pki.privateKeyFromPem(rootCertificatePrivateKey)
76
+ const rootCertificatePrivateKeyForgeObject = pki.privateKeyFromPem(
77
+ rootCertificatePrivateKey,
78
+ )
67
79
  logger.debug(`${okSign} certificate authority restored from filesystem`)
68
80
 
69
- const serverCertificateSerialNumber = certificateAuthorityData.serialNumber + 1
81
+ const serverCertificateSerialNumber =
82
+ certificateAuthorityData.serialNumber + 1
70
83
  await writeFile(
71
84
  authorityJsonFileInfo.url,
72
85
  JSON.stringify({ serialNumber: serverCertificateSerialNumber }, null, " "),
@@ -81,14 +94,17 @@ export const requestCertificateForLocalhost = async ({
81
94
  await requestCertificateFromAuthority({
82
95
  logger,
83
96
  authorityCertificateForgeObject: rootCertificateForgeObject,
84
- auhtorityCertificatePrivateKeyForgeObject: rootCertificatePrivateKeyForgeObject,
97
+ auhtorityCertificatePrivateKeyForgeObject:
98
+ rootCertificatePrivateKeyForgeObject,
85
99
  serialNumber: serverCertificateSerialNumber,
86
100
  altNames: serverCertificateAltNames,
87
101
  commonName: serverCertificateCommonName,
88
102
  validityDurationInMs: serverCertificateValidityDurationInMs,
89
103
  })
90
104
  const serverCertificate = pki.certificateToPem(certificateForgeObject)
91
- const serverCertificatePrivateKey = pki.privateKeyToPem(certificatePrivateKeyForgeObject)
105
+ const serverCertificatePrivateKey = pki.privateKeyToPem(
106
+ certificatePrivateKeyForgeObject,
107
+ )
92
108
  logger.debug(
93
109
  `${okSign} server certificate generated, it will be valid for ${formatDuration(
94
110
  serverCertificateValidityDurationInMs,
@@ -24,7 +24,9 @@ export const verifyHostsFile = async ({
24
24
  Object.keys(ipMappings).forEach((ip) => {
25
25
  const ipHostnames = ipMappings[ip]
26
26
  if (!Array.isArray(ipHostnames)) {
27
- throw new TypeError(`ipMappings values must be an array, found ${ipHostnames} for ${ip}`)
27
+ throw new TypeError(
28
+ `ipMappings values must be an array, found ${ipHostnames} for ${ip}`,
29
+ )
28
30
  }
29
31
  const existingMappings = hostnames.getIpHostnames(ip)
30
32
  const missingHostnames = normalizeHostnames(ipHostnames).filter(
@@ -47,15 +49,20 @@ export const verifyHostsFile = async ({
47
49
  .map(({ ip, missingHostnames }) => `${ip} ${missingHostnames.join(" ")}`)
48
50
  .join(EOL)
49
51
  logger.warn(
50
- createDetailedMessage(`${warningSign} ${formatXMappingMissingMessage(missingMappingCount)}`, {
51
- "hosts file path": hostsFilePath,
52
- "line(s) to add": linesToAdd,
53
- }),
52
+ createDetailedMessage(
53
+ `${warningSign} ${formatXMappingMissingMessage(missingMappingCount)}`,
54
+ {
55
+ "hosts file path": hostsFilePath,
56
+ "line(s) to add": linesToAdd,
57
+ },
58
+ ),
54
59
  )
55
60
  return
56
61
  }
57
62
 
58
- logger.info(`${infoSign} ${formatXMappingMissingMessage(missingMappingCount)}`)
63
+ logger.info(
64
+ `${infoSign} ${formatXMappingMissingMessage(missingMappingCount)}`,
65
+ )
59
66
  await missingMappings.reduce(async (previous, { ip, missingHostnames }) => {
60
67
  await previous
61
68
  const mapping = `${ip} ${missingHostnames.join(" ")}`
@@ -11,14 +11,20 @@ export const getAuthorityFileInfos = () => {
11
11
  rootCertificatePrivateKeyFileUrl,
12
12
  } = getCertificateAuthorityFileUrls()
13
13
 
14
- const authorityJsonFilePath = urlToFileSystemPath(certificateAuthorityJsonFileUrl)
14
+ const authorityJsonFilePath = urlToFileSystemPath(
15
+ certificateAuthorityJsonFileUrl,
16
+ )
15
17
  const authorityJsonFileDetected = existsSync(authorityJsonFilePath)
16
18
 
17
19
  const rootCertificateFilePath = urlToFileSystemPath(rootCertificateFileUrl)
18
20
  const rootCertificateFileDetected = existsSync(rootCertificateFilePath)
19
21
 
20
- const rootCertificatePrivateKeyFilePath = urlToFileSystemPath(rootCertificatePrivateKeyFileUrl)
21
- const rootCertificatePrivateKeyFileDetected = existsSync(rootCertificatePrivateKeyFilePath)
22
+ const rootCertificatePrivateKeyFilePath = urlToFileSystemPath(
23
+ rootCertificatePrivateKeyFileUrl,
24
+ )
25
+ const rootCertificatePrivateKeyFileDetected = existsSync(
26
+ rootCertificatePrivateKeyFilePath,
27
+ )
22
28
 
23
29
  return {
24
30
  authorityJsonFileInfo: {