@jsenv/https-local 3.3.0 → 3.5.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/README.md CHANGED
@@ -1,77 +1,82 @@
1
- # https local [![npm package](https://img.shields.io/npm/v/@jsenv/https-local.svg?logo=npm&label=package)](https://www.npmjs.com/package/@jsenv/https-local)
2
-
3
- MOVED TO https://github.com/jsenv/core/tree/main/packages/independent/https-local
4
-
5
- A programmatic way to generate locally trusted certificates.
6
-
7
- Generate certificate(s) trusted by your operating system and browsers.
8
- This certificate can be used to start your development server in HTTPS.
9
- Works on mac, linux and windows.
10
-
11
- # How to use
12
-
13
- 1 - Install _@jsenv/https-local_
1
+ # HTTPS Local [![npm package](https://img.shields.io/npm/v/@jsenv/https-local.svg?logo=npm&label=package)](https://www.npmjs.com/package/@jsenv/https-local)
2
+
3
+ A programmatic way to generate locally trusted certificates for HTTPS development.
4
+
5
+ 🔒 Generate certificates trusted by your operating system and browsers
6
+ 🌐 Perfect for local HTTPS development
7
+ 🖥️ Works on macOS, Linux, and Windows
8
+ ⚡ Simple API for certificate management
9
+
10
+ ## Table of Contents
11
+
12
+ - [HTTPS Local ](#https-local-)
13
+ - [Table of Contents](#table-of-contents)
14
+ - [Quick Start](#quick-start)
15
+ - [How to Use](#how-to-use)
16
+ - [1. Install the Root Certificate](#1-install-the-root-certificate)
17
+ - [2. Request Certificate for Your Server](#2-request-certificate-for-your-server)
18
+ - [3. Start the Server](#3-start-the-server)
19
+ - [Certificate Expiration](#certificate-expiration)
20
+ - [JavaScript API](#javascript-api)
21
+ - [requestCertificate](#requestcertificate)
22
+ - [verifyHostsFile](#verifyhostsfile)
23
+ - [Auto Update Hosts](#auto-update-hosts)
24
+ - [installCertificateAuthority](#installcertificateauthority)
25
+ - [Auto Trust](#auto-trust)
26
+
27
+ ## Quick Start
14
28
 
15
29
  ```console
16
- npm install --save-dev @jsenv/https-local
17
- ```
30
+ # Install the package
31
+ npm install @jsenv/https-local
18
32
 
19
- 2 - Create _install_certificate_authority.mjs_
33
+ # Install and trust the root certificate
34
+ npx @jsenv/https-local install --trust
35
+ ```
20
36
 
21
37
  ```js
22
- /*
23
- * This file needs to be executed once.
24
- * After that the root certificate is valid for 20 years.
25
- * Re-executing this file will log the current root certificate validity and trust status.
26
- * Re-executing this file 20 years later would reinstall a root certificate and re-trust it.
27
- *
28
- * Read more in https://github.com/jsenv/https-local#installCertificateAuthority
29
- */
30
-
31
- import {
32
- installCertificateAuthority,
33
- verifyHostsFile,
34
- } from "@jsenv/https-local";
38
+ // In your server file
39
+ import { createServer } from "node:https";
40
+ import { requestCertificate } from "@jsenv/https-local";
35
41
 
36
- await installCertificateAuthority({
37
- tryToTrust: true,
38
- NSSDynamicInstall: true,
39
- });
40
- await verifyHostsFile({
41
- ipMappings: {
42
- "127.0.0.1": ["localhost"],
42
+ const { certificate, privateKey } = requestCertificate();
43
+ const server = createServer(
44
+ {
45
+ cert: certificate,
46
+ key: privateKey,
47
+ },
48
+ (request, response) => {
49
+ response.end("Hello HTTPS world!");
43
50
  },
44
- tryToUpdatesHostsFile: true,
51
+ ).listen(8443, () => {
52
+ console.log("HTTPS server running at https://localhost:8443");
45
53
  });
46
54
  ```
47
55
 
48
- 3 - Run with node
56
+ ## How to Use
57
+
58
+ The following steps can be taken to start a local server in HTTPS:
59
+
60
+ ### 1. Install the Root Certificate
49
61
 
50
62
  ```console
51
- node ./install_certificate_authority.mjs
63
+ npx @jsenv/https-local install --trust
52
64
  ```
53
65
 
54
- 4 - Create _start_dev_server.mjs_
66
+ This will install a root certificate valid for 20 years.
55
67
 
56
- ```js
57
- /*
58
- * This file uses "@jsenv/https-local" to obtain a certificate used to start a server in https.
59
- * The certificate is valid for 1 year (396 days) and is issued by a certificate authority trusted on this machine.
60
- * If the certificate authority was not installed before executing this file, an error is thrown
61
- * explaining that certificate authority must be installed first.
62
- *
63
- * To install the certificate authority, you can use the following command
64
- *
65
- * > node ./install_certificate_authority.mjs
66
- *
67
- * Read more in https://github.com/jsenv/https-local#requestCertificate
68
- */
68
+ - Re-executing this command will log the current root certificate validity and trust status
69
+ - Re-executing this command 20 years later would reinstall a root certificate and re-trust it
70
+
71
+ ### 2. Request Certificate for Your Server
69
72
 
73
+ _start_dev_server.mjs_
74
+
75
+ ```js
70
76
  import { createServer } from "node:https";
71
77
  import { requestCertificate } from "@jsenv/https-local";
72
78
 
73
79
  const { certificate, privateKey } = requestCertificate();
74
-
75
80
  const server = createServer(
76
81
  {
77
82
  cert: certificate,
@@ -91,31 +96,156 @@ server.listen(8080);
91
96
  console.log(`Server listening at https://local.example:8080`);
92
97
  ```
93
98
 
94
- 5 - Start server with node
99
+ ### 3. Start the Server
95
100
 
96
101
  ```console
97
102
  node ./start_dev_server.mjs
98
103
  ```
99
104
 
100
- At this stage you have a server running in https.
101
- The rest of this documentation goes into more details.
105
+ At this stage you have a server running in HTTPS.
102
106
 
103
- # Certificate expiration
107
+ ## Certificate Expiration
104
108
 
105
109
  | Certificate | Expires after | How to renew? |
106
110
  | ----------- | ------------- | ------------------------------------ |
107
111
  | server | 1 year | Re-run _requestCertificate_ |
108
- | authority | 20 year | Re-run _installCertificateAuthority_ |
112
+ | authority | 20 years | Re-run _installCertificateAuthority_ |
109
113
 
110
- The **server certificate** expires after one year which is the maximum duration allowed by web browsers.
114
+ The **server certificate** expires after one year, which is the maximum duration allowed by web browsers.
111
115
  In the unlikely scenario where a local server is running for more than a year without interruption, restart it to re-run requestCertificate.
112
116
 
113
- The **authority root certificate** expires after 20 years which is close to the maximum allowed duration.
114
- 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.
117
+ The **authority root certificate** expires after 20 years, which is close to the maximum allowed duration.
118
+ 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.
119
+
120
+ ## JavaScript API
121
+
122
+ ### requestCertificate
123
+
124
+ The `requestCertificate` function returns a certificate and private key that can be used to start a server in HTTPS.
125
+
126
+ ```js
127
+ import { createServer } from "node:https";
128
+ import { requestCertificate } from "@jsenv/https-local";
129
+
130
+ const { certificate, privateKey } = requestCertificate({
131
+ altNames: ["localhost", "local.example"],
132
+ });
133
+ ```
134
+
135
+ [installCertificateAuthority](#installcertificateauthority) must be called before this function.
136
+
137
+ ### verifyHostsFile
138
+
139
+ This function is not mandatory to obtain the HTTPS certificates, but it is useful to programmatically verify IP mappings that are important for your local server are present in hosts file.
140
+
141
+ ```js
142
+ import { verifyHostsFile } from "@jsenv/https-local";
143
+
144
+ await verifyHostsFile({
145
+ ipMappings: {
146
+ "127.0.0.1": ["localhost", "local.example"],
147
+ },
148
+ });
149
+ ```
150
+
151
+ Find below logs written in terminal when this function is executed:
152
+
153
+ <details>
154
+ <summary>Mac and Linux output</summary>
155
+
156
+ ```console
157
+ > node ./verify_hosts.mjs
158
+
159
+ Check hosts file content...
160
+ ⚠ 1 mapping is missing in hosts file
161
+ --- hosts file path ---
162
+ /etc/hosts
163
+ --- line(s) to add ---
164
+ 127.0.0.1 localhost local.example
165
+ ```
166
+
167
+ </details>
168
+
169
+ <details>
170
+ <summary>Windows output</summary>
171
+
172
+ ```console
173
+ > node ./verify_hosts.mjs
174
+
175
+ Check hosts file content...
176
+ ⚠ 1 mapping is missing in hosts file
177
+ --- hosts file path ---
178
+ C:\\Windows\\System32\\Drivers\\etc\\hosts
179
+ --- line(s) to add ---
180
+ 127.0.0.1 localhost local.example
181
+ ```
182
+
183
+ </details>
184
+
185
+ #### Auto Update Hosts
186
+
187
+ It's possible to update hosts file programmatically using `tryToUpdateHostsFile`:
188
+
189
+ ```js
190
+ import { verifyHostsFile } from "@jsenv/https-local";
191
+
192
+ await verifyHostsFile({
193
+ ipMappings: {
194
+ "127.0.0.1": ["localhost", "local.example"],
195
+ },
196
+ tryToUpdateHostsFile: true,
197
+ });
198
+ ```
199
+
200
+ <details>
201
+ <summary>Mac and Linux output</summary>
202
+
203
+ ```console
204
+ Check hosts file content...
205
+ ℹ 1 mapping is missing in hosts file
206
+ Adding 1 mapping(s) in hosts file...
207
+ ❯ echo "127.0.0.1 local.example" | sudo tee -a /etc/hosts
208
+ Password:
209
+ ✔ mappings added to hosts file
210
+ ```
211
+
212
+ _Second execution logs_
213
+
214
+ ```console
215
+ > node ./verify_hosts.mjs
216
+
217
+ Check hosts file content...
218
+ ✔ all ip mappings found in hosts file
219
+ ```
220
+
221
+ </details>
222
+
223
+ <details>
224
+ <summary>Windows output</summary>
225
+
226
+ ```console
227
+ Check hosts file content...
228
+ ℹ 1 mapping is missing in hosts file
229
+ Adding 1 mapping(s) in hosts file...
230
+ ❯ (echo 127.0.0.1 local.example) >> C:\\Windows\\System32\\Drivers\\etc\\hosts
231
+ Password:
232
+ ✔ mappings added to hosts file
233
+ ```
234
+
235
+ _Second execution logs_
115
236
 
116
- # installCertificateAuthority
237
+ ```console
238
+ > node ./verify_hosts.mjs
117
239
 
118
- _installCertificateAuthority_ function generates a certificate authority valid for 20 years.
240
+ Check hosts file content...
241
+ ✔ all ip mappings found in hosts file
242
+ ```
243
+
244
+ </details>
245
+
246
+ ### installCertificateAuthority
247
+
248
+ The `installCertificateAuthority` function generates a certificate authority valid for 20 years.
119
249
  This certificate authority is needed to generate local certificates that will be trusted by the operating system and web browsers.
120
250
 
121
251
  ```js
@@ -124,12 +254,10 @@ import { installCertificateAuthority } from "@jsenv/https-local";
124
254
  await installCertificateAuthority();
125
255
  ```
126
256
 
127
- By default, trusting authority root certificate is a manual process. 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). This process can be done programmatically as explained in [Auto trust](#Auto-trust).
128
-
129
- Find below logs written in terminal when this function is executed.
257
+ By default, trusting authority root certificate is a manual process. 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). This process can be done programmatically as explained in [Auto Trust](#auto-trust).
130
258
 
131
259
  <details>
132
- <summary>mac</summary>
260
+ <summary>macOS output</summary>
133
261
 
134
262
  ```console
135
263
  > node ./install_certificate_authority.mjs
@@ -141,7 +269,7 @@ Generating authority root certificate with a validity of 20 years...
141
269
  ℹ You should add root certificate to firefox
142
270
  ```
143
271
 
144
- _second execution logs_
272
+ _Second execution logs_
145
273
 
146
274
  ```console
147
275
  > node ./install_certificate_authority.mjs
@@ -160,7 +288,7 @@ Check if certificate is in firefox...
160
288
  </details>
161
289
 
162
290
  <details>
163
- <summary>linux</summary>
291
+ <summary>Linux output</summary>
164
292
 
165
293
  ```console
166
294
  > node ./install_certificate_authority.mjs
@@ -173,7 +301,7 @@ Generating authority root certificate with a validity of 20 years...
173
301
  ℹ You should add certificate to firefox
174
302
  ```
175
303
 
176
- _second execution logs_
304
+ _Second execution logs_
177
305
 
178
306
  ```console
179
307
  > node ./install_certificate_authority.mjs
@@ -194,7 +322,7 @@ Check if certificate is in firefox...
194
322
  </details>
195
323
 
196
324
  <details>
197
- <summary>windows</summary>
325
+ <summary>Windows output</summary>
198
326
 
199
327
  ```console
200
328
  > node ./install_certificate_authority.mjs
@@ -206,7 +334,7 @@ Generating authority root certificate with a validity of 20 years...
206
334
  ℹ You should add certificate to firefox
207
335
  ```
208
336
 
209
- _second execution logs_
337
+ _Second execution logs_
210
338
 
211
339
  ```console
212
340
  > node ./install_certificate_authority.mjs
@@ -224,9 +352,9 @@ Check if certificate is trusted by firefox...
224
352
 
225
353
  </details>
226
354
 
227
- ## Auto trust
355
+ #### Auto Trust
228
356
 
229
- It's possible to trust root certificate programmatically using _tryToTrust_
357
+ It's possible to trust root certificate programmatically using `tryToTrust`:
230
358
 
231
359
  ```js
232
360
  import { installCertificateAuthority } from "@jsenv/https-local";
@@ -237,7 +365,7 @@ await installCertificateAuthority({
237
365
  ```
238
366
 
239
367
  <details>
240
- <summary>mac</summary>
368
+ <summary>macOS output</summary>
241
369
 
242
370
  ```console
243
371
  > node ./install_certificate_authority.mjs
@@ -253,7 +381,7 @@ Adding certificate to firefox...
253
381
  ✔ certificate added to Firefox
254
382
  ```
255
383
 
256
- _second execution logs_
384
+ _Second execution logs_
257
385
 
258
386
  ```console
259
387
  > node ./install_certificate_authority.mjs
@@ -272,7 +400,7 @@ Check if certificate is in Firefox...
272
400
  </details>
273
401
 
274
402
  <details>
275
- <summary>linux</summary>
403
+ <summary>Linux output</summary>
276
404
 
277
405
  ```console
278
406
  > node ./install_certificate_authority.mjs
@@ -299,7 +427,7 @@ Adding certificate to firefox...
299
427
  ✔ certificate added to firefox
300
428
  ```
301
429
 
302
- _second execution logs_
430
+ _Second execution logs_
303
431
 
304
432
  ```console
305
433
  > node ./install_certificate_authority.mjs
@@ -320,7 +448,7 @@ Check if certificate is in firefox...
320
448
  </details>
321
449
 
322
450
  <details>
323
- <summary>windows</summary>
451
+ <summary>Windows output</summary>
324
452
 
325
453
  ```console
326
454
  > node ./install_certificate_authority.mjs
@@ -339,7 +467,7 @@ Check if certificate is trusted by firefox...
339
467
  ℹ unable to detect if certificate is trusted by firefox (not implemented on windows)
340
468
  ```
341
469
 
342
- _second execution logs_
470
+ _Second execution logs_
343
471
 
344
472
  ```console
345
473
  > node ./install_certificate_authority.mjs
@@ -356,128 +484,3 @@ Check if certificate is trusted by firefox...
356
484
  ```
357
485
 
358
486
  </details>
359
-
360
- # requestCertificate
361
-
362
- _requestCertificate_ function returns a certificate and private key that can be used to start a server in HTTPS.
363
-
364
- ```js
365
- import { createServer } from "node:https";
366
- import { requestCertificate } from "@jsenv/https-local";
367
-
368
- const { certificate, privateKey } = requestCertificate({
369
- altNames: ["localhost", "local.example"],
370
- });
371
- ```
372
-
373
- [installCertificateAuthority](#installCertificateAuthority) must be called before this function.
374
-
375
- # verifyHostsFile
376
-
377
- This function is not mandatory to obtain the https certificates.
378
- But it is useful to programmatically verify ip mappings that are important for your local server are present in hosts file.
379
-
380
- ```js
381
- import { verifyHostsFile } from "@jsenv/https-local";
382
-
383
- await verifyHostsFile({
384
- ipMappings: {
385
- "127.0.0.1": ["localhost", "local.example"],
386
- },
387
- });
388
- ```
389
-
390
- Find below logs written in terminal when this function is executed.
391
-
392
- <details>
393
- <summary>mac and linux</summary>
394
-
395
- ```console
396
- > node ./verify_hosts.mjs
397
-
398
- Check hosts file content...
399
- ⚠ 1 mapping is missing in hosts file
400
- --- hosts file path ---
401
- /etc/hosts
402
- --- line(s) to add ---
403
- 127.0.0.1 localhost local.example
404
- ```
405
-
406
- </details>
407
-
408
- <details>
409
- <summary>windows</summary>
410
-
411
- ```console
412
- > node ./verify_hosts.mjs
413
-
414
- Check hosts file content...
415
- ⚠ 1 mapping is missing in hosts file
416
- --- hosts file path ---
417
- C:\\Windows\\System32\\Drivers\\etc\\hosts
418
- --- line(s) to add ---
419
- 127.0.0.1 localhost local.example
420
- ```
421
-
422
- </details>
423
-
424
- ## Auto update hosts
425
-
426
- It's possible to update hosts file programmatically using _tryToUpdateHostsFile_.
427
-
428
- ```js
429
- import { verifyHostsFile } from "@jsenv/https-local";
430
-
431
- await verifyHostsFile({
432
- ipMappings: {
433
- "127.0.0.1": ["localhost", "local.example"],
434
- },
435
- tryToUpdateHostsFile: true,
436
- });
437
- ```
438
-
439
- <details>
440
- <summary>mac and linux</summary>
441
-
442
- ```console
443
- Check hosts file content...
444
- ℹ 1 mapping is missing in hosts file
445
- Adding 1 mapping(s) in hosts file...
446
- ❯ echo "127.0.0.1 local.example" | sudo tee -a /etc/hosts
447
- Password:
448
- ✔ mappings added to hosts file
449
- ```
450
-
451
- _Second execution logs_
452
-
453
- ```console
454
- > node ./verify_hosts.mjs
455
-
456
- Check hosts file content...
457
- ✔ all ip mappings found in hosts file
458
- ```
459
-
460
- </details>
461
-
462
- <details>
463
- <summary>windows</summary>
464
-
465
- ```console
466
- Check hosts file content...
467
- ℹ 1 mapping is missing in hosts file
468
- Adding 1 mapping(s) in hosts file...
469
- ❯ (echo 127.0.0.1 local.example) >> C:\\Windows\\System32\\Drivers\\etc\\hosts
470
- Password:
471
- ✔ mappings added to hosts file
472
- ```
473
-
474
- _Second execution logs_
475
-
476
- ```console
477
- > node ./verify_hosts.mjs
478
-
479
- Check hosts file content...
480
- ✔ all ip mappings found in hosts file
481
- ```
482
-
483
- </details>
package/package.json CHANGED
@@ -1,20 +1,18 @@
1
1
  {
2
2
  "name": "@jsenv/https-local",
3
- "version": "3.3.0",
3
+ "version": "3.5.0",
4
4
  "type": "module",
5
5
  "description": "A programmatic way to generate locally trusted certificates",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "https://github.com/jsenv/https-local"
9
- },
10
- "author": {
11
- "name": "dmail",
12
- "email": "dmaillard06@gmail.com"
8
+ "url": "https://github.com/jsenv/core",
9
+ "directory": "packages/tooling/https-local"
13
10
  },
14
11
  "license": "MIT",
15
12
  "engines": {
16
- "node": ">=25.0.0"
13
+ "node": ">=20.0.0"
17
14
  },
15
+ "bin": "./src/https_local_cli.mjs",
18
16
  "main": "./src/main.js",
19
17
  "exports": {
20
18
  ".": {
@@ -26,25 +24,21 @@
26
24
  "/src/"
27
25
  ],
28
26
  "scripts": {
29
- "eslint": "npx eslint . --ext=.js,.mjs,.cjs",
30
- "test": "node ./scripts/test/test.mjs",
31
- "performance": "node --expose-gc ./scripts/performance/performance.mjs --local --log",
32
- "test:start-node-server": "node ./scripts/certificate/start_node_server.mjs",
33
27
  "ca:install": "node ./scripts/certificate/install_ca.mjs",
34
28
  "ca:log-trust": "node ./scripts/certificate/log_root_certificate_trust.mjs",
35
29
  "ca:trust": "node ./scripts/certificate/trust_root_certificate.mjs",
36
- "ca:untrust": "node ./scripts/certificate/untrust_root_certificate.mjs",
37
30
  "ca:uninstall": "node ./scripts/certificate/uninstall_certificate_authority.mjs",
31
+ "ca:untrust": "node ./scripts/certificate/untrust_root_certificate.mjs",
38
32
  "hosts:add-localhost-mappings": "node ./scripts/hosts/add_localhost_mappings.mjs",
33
+ "hosts:ensure-localhost-mappings": "node ./scripts/hosts/ensure_localhost_mappings.mjs",
39
34
  "hosts:remove-localhost-mappings": "node ./scripts/hosts/remove_localhost_mappings.mjs",
40
35
  "hosts:verify-localhost-mappings": "node ./scripts/hosts/verify_localhost_mappings.mjs",
41
- "hosts:ensure-localhost-mappings": "node ./scripts/hosts/ensure_localhost_mappings.mjs",
42
- "prettier": "prettier --write .",
43
- "playwright:install": "npx playwright install-deps && npx playwright install"
36
+ "performance": "node --expose-gc ./scripts/performance/performance.mjs --local --log",
37
+ "test:start-node-server": "node ./scripts/certificate/start_node_server.mjs"
44
38
  },
45
39
  "dependencies": {
46
40
  "@jsenv/filesystem": "4.15.15",
47
- "@jsenv/log": "3.5.2",
41
+ "@jsenv/humanize": "1.7.6",
48
42
  "@jsenv/urls": "2.9.8",
49
43
  "command-exists": "1.2.9",
50
44
  "node-forge": "1.4.0",
@@ -52,24 +46,13 @@
52
46
  "which": "6.0.1"
53
47
  },
54
48
  "devDependencies": {
55
- "@jsenv/assert": "4.5.6",
56
- "@jsenv/eslint-config-relax": "1.8.5",
57
- "@jsenv/github-release-package": "1.6.42",
58
- "@jsenv/package-publish": "1.11.44",
59
- "@jsenv/performance-impact": "4.4.42",
60
- "@jsenv/test": "3.7.21",
61
- "eslint": "9.39.2",
62
- "playwright": "1.59.1",
63
- "prettier": "3.8.3",
64
- "prettier-plugin-embed": "0.5.1",
65
- "prettier-plugin-organize-imports": "4.3.0",
66
- "prettier-plugin-pkg": "0.22.1"
49
+ "@jsenv/assert": "../assert",
50
+ "@jsenv/https-local": "./",
51
+ "@jsenv/performance-impact": "../performance-impact",
52
+ "@jsenv/test": "../../related/test",
53
+ "playwright": "1.59.1"
67
54
  },
68
55
  "publishConfig": {
69
56
  "access": "public"
70
- },
71
- "volta": {
72
- "node": "25.8.1",
73
- "npm": "11.6.2"
74
57
  }
75
58
  }
@@ -1,6 +1,5 @@
1
1
  import { readFile, removeEntry, writeFile } from "@jsenv/filesystem";
2
- import { UNICODE, createDetailedMessage, createLogger } from "@jsenv/log";
3
-
2
+ import { UNICODE, createDetailedMessage, createLogger } from "@jsenv/humanize";
4
3
  import { getAuthorityFileInfos } from "./internal/authority_file_infos.js";
5
4
  import { attributeDescriptionFromAttributeArray } from "./internal/certificate_data_converter.js";
6
5
  import { createAuthorityRootCertificate } from "./internal/certificate_generator.js";
@@ -213,7 +212,7 @@ export const installCertificateAuthority = async ({
213
212
  certificateValidityDurationInMs,
214
213
  },
215
214
  );
216
- if (Object.keys(rootCertificateDifferences).length) {
215
+ if (rootCertificateDifferences.length) {
217
216
  const paramNames = Object.keys(rootCertificateDifferences);
218
217
  logger.info(
219
218
  `${UNICODE.INFO} certificate attributes are outdated: ${paramNames}`,
@@ -327,13 +326,13 @@ export const uninstallCertificateAuthority = async ({
327
326
  const rootCertificateCommonName = attributeDescriptionFromAttributeArray(
328
327
  rootCertificateForgeObject.subject.attributes,
329
328
  ).commonName;
330
- const { removeCertificateFromTrustStores } =
331
- await importPlatformMethods();
332
- await removeCertificateFromTrustStores({
329
+ const platformMethods = await importPlatformMethods();
330
+ await platformMethods.executeTrustQuery({
333
331
  logger,
334
- certificate: rootCertificate,
335
- certificateFileUrl: rootCertificateFileInfo.url,
336
332
  certificateCommonName: rootCertificateCommonName,
333
+ certificateFileUrl: rootCertificateFileInfo.url,
334
+ certificate: rootCertificate,
335
+ verb: "REMOVE_TRUST",
337
336
  });
338
337
  }
339
338
  filesToRemove.push(rootCertificateFileInfo.url);
@@ -1,7 +1,6 @@
1
1
  import { writeFileSync } from "@jsenv/filesystem";
2
- import { UNICODE, createDetailedMessage, createLogger } from "@jsenv/log";
2
+ import { UNICODE, createDetailedMessage, createLogger } from "@jsenv/humanize";
3
3
  import { readFileSync } from "node:fs";
4
-
5
4
  import { getAuthorityFileInfos } from "./internal/authority_file_infos.js";
6
5
  import { requestCertificateFromAuthority } from "./internal/certificate_generator.js";
7
6
  import { forge } from "./internal/forge.js";
@@ -47,7 +46,9 @@ export const requestCertificate = ({
47
46
  } = getAuthorityFileInfos();
48
47
  if (!rootCertificateFileInfo.exists) {
49
48
  throw new Error(
50
- `Certificate authority not found, "installCertificateAuthority" must be called before "requestServerCertificate"`,
49
+ `Certificate authority not found, "installCertificateAuthority" must be called before "requestServerCertificate".
50
+ --- Suggested command to run ---
51
+ npx @jsenv/https-local install --trust`,
51
52
  );
52
53
  }
53
54
  if (!rootCertificatePrivateKeyFileInfo.exists) {
@@ -84,7 +85,6 @@ export const requestCertificate = ({
84
85
  logger.debug(`Generating server certificate...`);
85
86
  const { certificateForgeObject, certificatePrivateKeyForgeObject } =
86
87
  requestCertificateFromAuthority({
87
- logger,
88
88
  authorityCertificateForgeObject: rootCertificateForgeObject,
89
89
  auhtorityCertificatePrivateKeyForgeObject:
90
90
  rootCertificatePrivateKeyForgeObject,
@@ -1,5 +1,4 @@
1
- import { createDetailedMessage, createLogger, UNICODE } from "@jsenv/log";
2
-
1
+ import { createDetailedMessage, createLogger, UNICODE } from "@jsenv/humanize";
3
2
  import {
4
3
  HOSTS_FILE_PATH,
5
4
  parseHosts,
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {
4
+ installCertificateAuthority,
5
+ requestCertificate,
6
+ uninstallCertificateAuthority,
7
+ verifyHostsFile,
8
+ } from "@jsenv/https-local";
9
+ import { writeFileSync } from "node:fs";
10
+ import { parseArgs } from "node:util";
11
+
12
+ const options = {
13
+ "help": {
14
+ type: "boolean",
15
+ },
16
+ "trust": {
17
+ type: "boolean",
18
+ },
19
+ "certificate": {
20
+ type: "string",
21
+ },
22
+ "private-key": {
23
+ type: "string",
24
+ },
25
+ "hostnames": {
26
+ type: "string",
27
+ },
28
+ };
29
+ const { values, positionals } = parseArgs({
30
+ options,
31
+ allowPositionals: true,
32
+ });
33
+
34
+ if (values.help || positionals.length === 0) {
35
+ console.log(`https-local: Generate https certificates to use on your machine.
36
+
37
+ Usage:
38
+
39
+ npx @jsenv/https-local setup
40
+ Install root certificate, try to trust it and ensure localhost is mapped to 127.0.0.1
41
+
42
+ npx @jsenv/https-local install --trust
43
+ Install root certificate on the filesystem
44
+ - trust: Try to add root certificate to os and browser trusted stores.
45
+
46
+ npx @jsenv/https-local uninstall
47
+ Uninstall root certificate from the filesystem
48
+
49
+ npx @jsenv/https-local localhost-mapping
50
+ Ensure localhost mapping to 127.0.0.1 is set on the filesystem
51
+
52
+ npx @jsenv/https-local generate
53
+ Generate a server certificate and write it to files
54
+ - certificate: Path where to write the certificate file (default: certificate.pem)
55
+ - private-key: Path where to write the private key file (default: private_key.pem)
56
+ - hostnames: Comma-separated list of hostnames (default: localhost)
57
+
58
+ https://github.com/jsenv/core/tree/main/packages/tooling/https-local
59
+
60
+ `);
61
+
62
+ process.exit(0);
63
+ }
64
+
65
+ const commandHandlers = {
66
+ setup: async () => {
67
+ await installCertificateAuthority({
68
+ tryToTrust: true,
69
+ NSSDynamicInstall: true,
70
+ });
71
+ await verifyHostsFile({
72
+ ipMappings: {
73
+ "127.0.0.1": ["localhost"],
74
+ },
75
+ tryToUpdateHostsFile: true,
76
+ });
77
+ },
78
+ install: async ({ trust }) => {
79
+ await installCertificateAuthority({
80
+ tryToTrust: trust,
81
+ NSSDynamicInstall: trust,
82
+ });
83
+ },
84
+ uninstall: async () => {
85
+ await uninstallCertificateAuthority({
86
+ tryToUntrust: true,
87
+ });
88
+ },
89
+ ["localhost-mapping"]: async () => {
90
+ await verifyHostsFile({
91
+ ipMappings: {
92
+ "127.0.0.1": ["localhost"],
93
+ },
94
+ tryToUpdateHostsFile: true,
95
+ });
96
+ },
97
+ generate: async ({ certificate, "private-key": privateKey, hostnames }) => {
98
+ const certificateFilePath = certificate || "certificate.pem";
99
+ const privateKeyFilePath = privateKey || "private_key.pem";
100
+ const altNames = hostnames ? hostnames.split(",") : ["localhost"];
101
+ const result = requestCertificate({ altNames });
102
+ writeFileSync(certificateFilePath, result.certificate);
103
+ writeFileSync(privateKeyFilePath, result.privateKey);
104
+ console.log(`certificate written to ${certificateFilePath}`);
105
+ console.log(`private key written to ${privateKeyFilePath}`);
106
+ },
107
+ };
108
+
109
+ const [command] = positionals;
110
+ const commandHandler = commandHandlers[command];
111
+ if (!commandHandler) {
112
+ console.error(`Error: unknown command ${command}.`);
113
+ process.exit(1);
114
+ }
115
+
116
+ await commandHandler(values);
@@ -1,6 +1,5 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { fileURLToPath } from "node:url";
3
-
4
3
  import { getCertificateAuthorityFileUrls } from "./certificate_authority_file_urls.js";
5
4
 
6
5
  export const getAuthorityFileInfos = () => {
@@ -8,9 +8,8 @@ export const parseHosts = (
8
8
  const lines = [];
9
9
  hosts.split(/\r?\n/).forEach((line) => {
10
10
  const lineWithoutComments = line.replace(/#.*/, "");
11
- const matches = /^\s*(\S+)\s+(\S+(?:\s+\S+)*)\s*$/.exec(
12
- lineWithoutComments,
13
- );
11
+ // eslint-disable-next-line regexp/no-super-linear-backtracking
12
+ const matches = /^\s*?(.+?)\s+(.+?)\s*$/.exec(lineWithoutComments);
14
13
  if (matches && matches.length === 3) {
15
14
  const [, ip, host] = matches;
16
15
  const hostnames = host.split(" ");
@@ -1,5 +1,4 @@
1
1
  import { readFile } from "@jsenv/filesystem";
2
-
3
2
  import { HOSTS_FILE_PATH } from "./hosts_utils.js";
4
3
 
5
4
  export const readHostsFile = async (hostsFilePath = HOSTS_FILE_PATH) => {
@@ -1,7 +1,5 @@
1
1
  import { createRequire } from "node:module";
2
-
3
2
  import { exec } from "../exec.js";
4
-
5
3
  import { HOSTS_FILE_PATH } from "./hosts_utils.js";
6
4
 
7
5
  export const writeHostsFile = async (
@@ -1,8 +1,6 @@
1
1
  import { readFile } from "@jsenv/filesystem";
2
2
  import { createRequire } from "node:module";
3
-
4
3
  import { exec } from "../exec.js";
5
-
6
4
  import { HOSTS_FILE_PATH } from "./hosts_utils.js";
7
5
 
8
6
  export const writeLineInHostsFile = async (
@@ -1,7 +1,6 @@
1
1
  import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem";
2
- import { UNICODE } from "@jsenv/log";
2
+ import { UNICODE } from "@jsenv/humanize";
3
3
  import { execSync } from "node:child_process";
4
-
5
4
  import { executeTrustQueryOnBrowserNSSDB } from "../nssdb_browser.js";
6
5
  import {
7
6
  detectIfNSSIsInstalled,
@@ -1,7 +1,6 @@
1
1
  import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem";
2
- import { UNICODE } from "@jsenv/log";
2
+ import { UNICODE } from "@jsenv/humanize";
3
3
  import { execSync } from "node:child_process";
4
-
5
4
  import { executeTrustQueryOnBrowserNSSDB } from "../nssdb_browser.js";
6
5
  import {
7
6
  detectIfNSSIsInstalled,
@@ -13,7 +13,6 @@ export const executeTrustQuery = async ({
13
13
  }) => {
14
14
  const linuxTrustInfo = await executeTrustQueryOnLinux({
15
15
  logger,
16
- certificateCommonName,
17
16
  certificateFileUrl,
18
17
  certificateIsNew,
19
18
  certificate,
@@ -3,10 +3,9 @@
3
3
  */
4
4
 
5
5
  import { readFile } from "@jsenv/filesystem";
6
- import { createDetailedMessage, UNICODE } from "@jsenv/log";
6
+ import { createDetailedMessage, UNICODE } from "@jsenv/humanize";
7
7
  import { existsSync } from "node:fs";
8
8
  import { fileURLToPath } from "node:url";
9
-
10
9
  import { exec } from "../exec.js";
11
10
  import {
12
11
  VERB_ADD_TRUST,
@@ -1,7 +1,6 @@
1
1
  // https://github.com/FiloSottile/mkcert/issues/447
2
2
 
3
- import { UNICODE } from "@jsenv/log";
4
-
3
+ import { UNICODE } from "@jsenv/humanize";
5
4
  import { exec } from "../exec.js";
6
5
  import { memoize } from "../memoize.js";
7
6
 
@@ -1,6 +1,5 @@
1
- import { UNICODE } from "@jsenv/log";
1
+ import { UNICODE } from "@jsenv/humanize";
2
2
  import { existsSync } from "node:fs";
3
-
4
3
  import { memoize } from "../memoize.js";
5
4
 
6
5
  const REASON_CHROME_NOT_DETECTED = `Chrome not detected`;
@@ -1,7 +1,6 @@
1
1
  import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem";
2
- import { UNICODE, createTaskLog } from "@jsenv/log";
2
+ import { UNICODE, createTaskLog } from "@jsenv/humanize";
3
3
  import { execSync } from "node:child_process";
4
-
5
4
  import { executeTrustQueryOnBrowserNSSDB } from "../nssdb_browser.js";
6
5
  import {
7
6
  detectIfNSSIsInstalled,
@@ -44,7 +44,6 @@ export const executeTrustQuery = async ({
44
44
  });
45
45
 
46
46
  const safariTrustInfo = await executeTrustQueryOnSafari({
47
- logger,
48
47
  // safari needs macTrustInfo because it uses OS trust store
49
48
  macTrustInfo,
50
49
  });
@@ -1,8 +1,7 @@
1
1
  // https://ss64.com/osx/security.html
2
2
 
3
- import { createDetailedMessage, UNICODE } from "@jsenv/log";
3
+ import { createDetailedMessage, UNICODE } from "@jsenv/humanize";
4
4
  import { fileURLToPath } from "node:url";
5
-
6
5
  import { exec } from "../exec.js";
7
6
  import { searchCertificateInCommandOutput } from "../search_certificate_in_command_output.js";
8
7
  import {
@@ -1,7 +1,6 @@
1
1
  import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem";
2
- import { UNICODE } from "@jsenv/log";
2
+ import { UNICODE } from "@jsenv/humanize";
3
3
  import { fileURLToPath } from "node:url";
4
-
5
4
  import { commandExists } from "../command.js";
6
5
  import { exec } from "../exec.js";
7
6
  import { memoize } from "../memoize.js";
@@ -7,11 +7,10 @@ import {
7
7
  assertAndNormalizeDirectoryUrl,
8
8
  collectFiles,
9
9
  } from "@jsenv/filesystem";
10
- import { createDetailedMessage, UNICODE } from "@jsenv/log";
10
+ import { createDetailedMessage, UNICODE } from "@jsenv/humanize";
11
11
  import { urlToFilename } from "@jsenv/urls";
12
12
  import { existsSync } from "node:fs";
13
13
  import { fileURLToPath } from "node:url";
14
-
15
14
  import { detectBrowser } from "./browser_detection.js";
16
15
  import { exec } from "./exec.js";
17
16
  import { searchCertificateInCommandOutput } from "./search_certificate_in_command_output.js";
@@ -1,4 +1,4 @@
1
- import { UNICODE } from "@jsenv/log";
1
+ import { UNICODE } from "@jsenv/humanize";
2
2
 
3
3
  const platformTrustInfo = {
4
4
  status: "unknown",
@@ -1,7 +1,6 @@
1
- import { UNICODE } from "@jsenv/log";
1
+ import { UNICODE } from "@jsenv/humanize";
2
2
  import { existsSync } from "node:fs";
3
3
  import { createRequire } from "node:module";
4
-
5
4
  import { memoize } from "../memoize.js";
6
5
 
7
6
  const require = createRequire(import.meta.url);
@@ -3,10 +3,9 @@
3
3
  * - A way to install and use NSS command on windows to update firefox NSS dabatase file
4
4
  */
5
5
 
6
- import { UNICODE } from "@jsenv/log";
6
+ import { UNICODE } from "@jsenv/humanize";
7
7
  import { existsSync } from "node:fs";
8
8
  import { createRequire } from "node:module";
9
-
10
9
  import { memoize } from "../memoize.js";
11
10
 
12
11
  const require = createRequire(import.meta.url);
@@ -14,7 +14,6 @@ export const executeTrustQuery = async ({
14
14
  certificateCommonName,
15
15
  certificateFileUrl,
16
16
  certificateIsNew,
17
- certificate,
18
17
  verb,
19
18
  }) => {
20
19
  const windowsTrustInfo = await executeTrustQueryOnWindows({
@@ -22,7 +21,6 @@ export const executeTrustQuery = async ({
22
21
  certificateCommonName,
23
22
  certificateFileUrl,
24
23
  certificateIsNew,
25
- certificate,
26
24
  verb,
27
25
  });
28
26
 
@@ -3,9 +3,8 @@
3
3
  * https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/certutil
4
4
  */
5
5
 
6
- import { createDetailedMessage, UNICODE } from "@jsenv/log";
6
+ import { createDetailedMessage, UNICODE } from "@jsenv/humanize";
7
7
  import { fileURLToPath } from "node:url";
8
-
9
8
  import { exec } from "../exec.js";
10
9
  import {
11
10
  VERB_ADD_TRUST,
package/src/main.js CHANGED
@@ -12,12 +12,9 @@ export {
12
12
  installCertificateAuthority,
13
13
  uninstallCertificateAuthority,
14
14
  } from "./certificate_authority.js";
15
-
15
+ export { requestCertificate } from "./certificate_request.js";
16
+ export { verifyHostsFile } from "./hosts_file_verif.js";
16
17
  export {
17
18
  createValidityDurationOfXDays,
18
19
  createValidityDurationOfXYears,
19
20
  } from "./validity_duration.js";
20
-
21
- export { verifyHostsFile } from "./hosts_file_verif.js";
22
-
23
- export { requestCertificate } from "./certificate_request.js";