@jsenv/https-local 3.0.0 → 3.0.2
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 +10 -7
- package/package.json +16 -16
- package/src/internal/browser_detection.js +7 -0
- package/src/internal/linux/chrome_linux.js +9 -17
- package/src/internal/linux/firefox_linux.js +16 -17
- package/src/internal/mac/firefox_mac.js +14 -18
- package/src/internal/nssdb_browser.js +20 -7
- package/src/main.js +4 -0
package/README.md
CHANGED
|
@@ -18,7 +18,8 @@ npm install --save-dev @jsenv/https-local
|
|
|
18
18
|
|
|
19
19
|
```js
|
|
20
20
|
/*
|
|
21
|
-
* This file needs to be executed once.
|
|
21
|
+
* This file needs to be executed once.
|
|
22
|
+
* After that the root certificate is valid for 20 years.
|
|
22
23
|
* Re-executing this file will log the current root certificate validity and trust status.
|
|
23
24
|
* Re-executing this file 20 years later would reinstall a root certificate and re-trust it.
|
|
24
25
|
*
|
|
@@ -42,7 +43,7 @@ await verifyHostsFile({
|
|
|
42
43
|
})
|
|
43
44
|
```
|
|
44
45
|
|
|
45
|
-
3 - Run
|
|
46
|
+
3 - Run with node
|
|
46
47
|
|
|
47
48
|
```console
|
|
48
49
|
node ./install_certificate_authority.mjs
|
|
@@ -88,14 +89,14 @@ server.listen(8080)
|
|
|
88
89
|
console.log(`Server listening at https://local.example:8080`)
|
|
89
90
|
```
|
|
90
91
|
|
|
91
|
-
5 -
|
|
92
|
+
5 - Start server with node
|
|
92
93
|
|
|
93
94
|
```console
|
|
94
95
|
node ./start_dev_server.mjs
|
|
95
96
|
```
|
|
96
97
|
|
|
97
|
-
At this stage
|
|
98
|
-
The rest of
|
|
98
|
+
At this stage you have a server running in https.
|
|
99
|
+
The rest of this documentation goes into more details.
|
|
99
100
|
|
|
100
101
|
# Certificate expiration
|
|
101
102
|
|
|
@@ -104,9 +105,11 @@ The rest of the documentation goes into details.
|
|
|
104
105
|
| server | 1 year | Re-run _requestCertificate_ |
|
|
105
106
|
| authority | 20 year | Re-run _installCertificateAuthority_ |
|
|
106
107
|
|
|
107
|
-
The **server
|
|
108
|
+
The **server certificate** expires after one year which is the maximum duration allowed by web browsers.
|
|
109
|
+
In the unlikely scenario where a local server is running for more than a year without interruption, restart it to re-run requestCertificate.
|
|
108
110
|
|
|
109
|
-
The **authority
|
|
111
|
+
The **authority root certificate** expires after 20 years which is close to the maximum allowed duration.
|
|
112
|
+
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.
|
|
110
113
|
|
|
111
114
|
# installCertificateAuthority
|
|
112
115
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/https-local",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "A programmatic way to generate locally trusted certificates",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -44,28 +44,28 @@
|
|
|
44
44
|
"verify-localhost-mappings": "node ./scripts/hosts/verify_localhost_mappings.mjs",
|
|
45
45
|
"ensure-localhost-mappings": "node ./scripts/hosts/ensure_localhost_mappings.mjs",
|
|
46
46
|
"prettier": "prettier --write .",
|
|
47
|
-
"playwright
|
|
47
|
+
"playwright:install": "npx playwright install-deps && npx playwright install"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@jsenv/filesystem": "4.1.
|
|
51
|
-
"@jsenv/log": "3.
|
|
52
|
-
"@jsenv/urls": "1.2.
|
|
50
|
+
"@jsenv/filesystem": "4.1.6",
|
|
51
|
+
"@jsenv/log": "3.3.2",
|
|
52
|
+
"@jsenv/urls": "1.2.8",
|
|
53
53
|
"command-exists": "1.2.9",
|
|
54
54
|
"node-forge": "1.3.1",
|
|
55
55
|
"sudo-prompt": "9.2.1",
|
|
56
|
-
"which": "
|
|
56
|
+
"which": "3.0.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@jsenv/assert": "2.
|
|
60
|
-
"@jsenv/core": "
|
|
61
|
-
"@jsenv/eslint-config": "16.2.
|
|
62
|
-
"@jsenv/eslint-import-resolver": "0.
|
|
63
|
-
"@jsenv/github-release-package": "1.5.
|
|
64
|
-
"@jsenv/package-publish": "1.10.
|
|
65
|
-
"@jsenv/performance-impact": "
|
|
66
|
-
"eslint": "8.
|
|
59
|
+
"@jsenv/assert": "2.8.0",
|
|
60
|
+
"@jsenv/core": "30.0.0",
|
|
61
|
+
"@jsenv/eslint-config": "16.2.9",
|
|
62
|
+
"@jsenv/eslint-import-resolver": "0.4.1",
|
|
63
|
+
"@jsenv/github-release-package": "1.5.1",
|
|
64
|
+
"@jsenv/package-publish": "1.10.1",
|
|
65
|
+
"@jsenv/performance-impact": "4.1.0",
|
|
66
|
+
"eslint": "8.30.0",
|
|
67
67
|
"eslint-plugin-import": "2.26.0",
|
|
68
|
-
"playwright": "1.
|
|
69
|
-
"prettier": "2.
|
|
68
|
+
"playwright": "1.29.1",
|
|
69
|
+
"prettier": "2.8.1"
|
|
70
70
|
}
|
|
71
71
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { existsSync } from "node:fs"
|
|
2
1
|
import { execSync } from "node:child_process"
|
|
3
2
|
import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem"
|
|
4
3
|
import { UNICODE } from "@jsenv/log"
|
|
@@ -35,22 +34,15 @@ export const executeTrustQueryOnChrome = ({
|
|
|
35
34
|
getCertutilBinPath,
|
|
36
35
|
|
|
37
36
|
browserName: "chrome",
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
logger.debug(`${UNICODE.INFO} Chrome not detected`)
|
|
48
|
-
return false
|
|
49
|
-
},
|
|
50
|
-
browserNSSDBDirectoryUrl: new URL(
|
|
51
|
-
".pki/nssdb",
|
|
52
|
-
assertAndNormalizeDirectoryUrl(process.env.HOME),
|
|
53
|
-
).href,
|
|
37
|
+
browserPaths: ["/usr/bin/google-chrome"],
|
|
38
|
+
browserNSSDBDirectoryUrls: [
|
|
39
|
+
new URL(".pki/nssdb", assertAndNormalizeDirectoryUrl(process.env.HOME)),
|
|
40
|
+
new URL(
|
|
41
|
+
"snap/chromium/current/.pki/nssdb",
|
|
42
|
+
assertAndNormalizeDirectoryUrl(process.env.HOME),
|
|
43
|
+
), // Snapcraft
|
|
44
|
+
"file:///etc/pki/nssdb", // CentOS 7
|
|
45
|
+
],
|
|
54
46
|
getBrowserClosedPromise: async () => {
|
|
55
47
|
if (!isChromeOpen()) {
|
|
56
48
|
return
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { existsSync } from "node:fs"
|
|
2
1
|
import { execSync } from "node:child_process"
|
|
3
2
|
import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem"
|
|
4
3
|
import { UNICODE } from "@jsenv/log"
|
|
@@ -35,22 +34,22 @@ export const executeTrustQueryOnFirefox = ({
|
|
|
35
34
|
getCertutilBinPath,
|
|
36
35
|
|
|
37
36
|
browserName: "firefox",
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
37
|
+
browserPaths: [
|
|
38
|
+
"/usr/bin/firefox",
|
|
39
|
+
"/usr/bin/firefox-nightly",
|
|
40
|
+
"/usr/bin/firefox-developer-edition",
|
|
41
|
+
"/snap/firefox",
|
|
42
|
+
],
|
|
43
|
+
browserNSSDBDirectoryUrls: [
|
|
44
|
+
new URL(
|
|
45
|
+
".mozilla/firefox/",
|
|
46
|
+
assertAndNormalizeDirectoryUrl(process.env.HOME),
|
|
47
|
+
),
|
|
48
|
+
new URL(
|
|
49
|
+
"/snap/firefox/common/.mozilla/firefox/",
|
|
50
|
+
assertAndNormalizeDirectoryUrl(process.env.HOME),
|
|
51
|
+
),
|
|
52
|
+
],
|
|
54
53
|
getBrowserClosedPromise: async () => {
|
|
55
54
|
if (!isFirefoxOpen()) {
|
|
56
55
|
return
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { existsSync } from "node:fs"
|
|
2
1
|
import { execSync } from "node:child_process"
|
|
3
2
|
import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem"
|
|
4
3
|
import { UNICODE, createTaskLog } from "@jsenv/log"
|
|
@@ -35,22 +34,18 @@ export const executeTrustQueryOnFirefox = ({
|
|
|
35
34
|
getCertutilBinPath,
|
|
36
35
|
|
|
37
36
|
browserName: "firefox",
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
browserNSSDBDirectoryUrl: new URL(
|
|
51
|
-
`./Library/Application Support/Firefox/Profiles/`,
|
|
52
|
-
assertAndNormalizeDirectoryUrl(process.env.HOME),
|
|
53
|
-
).href,
|
|
37
|
+
browserPaths: [
|
|
38
|
+
"/Applications/Firefox.app",
|
|
39
|
+
"/Applications/FirefoxDeveloperEdition.app",
|
|
40
|
+
"/Applications/Firefox Developer Edition.app",
|
|
41
|
+
"/Applications/Firefox Nightly.app",
|
|
42
|
+
],
|
|
43
|
+
browserNSSDBDirectoryUrls: [
|
|
44
|
+
new URL(
|
|
45
|
+
`./Library/Application Support/Firefox/Profiles/`,
|
|
46
|
+
assertAndNormalizeDirectoryUrl(process.env.HOME),
|
|
47
|
+
),
|
|
48
|
+
],
|
|
54
49
|
getBrowserClosedPromise: async () => {
|
|
55
50
|
if (!isFirefoxOpen()) {
|
|
56
51
|
return
|
|
@@ -78,5 +73,6 @@ export const executeTrustQueryOnFirefox = ({
|
|
|
78
73
|
}
|
|
79
74
|
|
|
80
75
|
const isFirefoxOpen = () => {
|
|
81
|
-
|
|
76
|
+
const psAux = execSync("ps aux")
|
|
77
|
+
return psAux.includes("Firefox.app")
|
|
82
78
|
}
|
|
@@ -9,6 +9,7 @@ import { urlToFilename } from "@jsenv/urls"
|
|
|
9
9
|
import { createDetailedMessage, UNICODE } from "@jsenv/log"
|
|
10
10
|
import { assertAndNormalizeDirectoryUrl, collectFiles } from "@jsenv/filesystem"
|
|
11
11
|
|
|
12
|
+
import { detectBrowser } from "./browser_detection.js"
|
|
12
13
|
import { exec } from "./exec.js"
|
|
13
14
|
import { searchCertificateInCommandOutput } from "./search_certificate_in_command_output.js"
|
|
14
15
|
import {
|
|
@@ -32,17 +33,21 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
32
33
|
getCertutilBinPath,
|
|
33
34
|
|
|
34
35
|
browserName,
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
browserPaths,
|
|
37
|
+
browserNSSDBDirectoryUrls,
|
|
37
38
|
getBrowserClosedPromise,
|
|
38
39
|
}) => {
|
|
39
|
-
|
|
40
|
+
logger.debug(`Detecting ${browserName}...`)
|
|
41
|
+
|
|
42
|
+
const browserDetected = detectBrowser(browserPaths)
|
|
40
43
|
if (!browserDetected) {
|
|
44
|
+
logger.debug(`${UNICODE.INFO} ${browserName} not detected`)
|
|
41
45
|
return {
|
|
42
46
|
status: "other",
|
|
43
47
|
reason: `${browserName} not detected`,
|
|
44
48
|
}
|
|
45
49
|
}
|
|
50
|
+
logger.debug(`${UNICODE.OK} ${browserName} detected`)
|
|
46
51
|
|
|
47
52
|
if (verb === VERB_CHECK_TRUST && certificateIsNew) {
|
|
48
53
|
logger.info(`${UNICODE.INFO} You should add certificate to ${browserName}`)
|
|
@@ -116,10 +121,17 @@ export const executeTrustQueryOnBrowserNSSDB = async ({
|
|
|
116
121
|
}
|
|
117
122
|
}
|
|
118
123
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
124
|
+
let NSSDBFiles
|
|
125
|
+
for (const browserNSSDBDirectoryUrl of browserNSSDBDirectoryUrls) {
|
|
126
|
+
NSSDBFiles = await findNSSDBFiles({
|
|
127
|
+
logger,
|
|
128
|
+
NSSDBDirectoryUrl: browserNSSDBDirectoryUrl,
|
|
129
|
+
})
|
|
130
|
+
if (NSSDBFiles.length > 0) {
|
|
131
|
+
break
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
123
135
|
const fileCount = NSSDBFiles.length
|
|
124
136
|
if (fileCount === 0) {
|
|
125
137
|
const reason = `could not find nss database file`
|
|
@@ -281,6 +293,7 @@ const isCertificateNotFoundError = (error) => {
|
|
|
281
293
|
|
|
282
294
|
const NSSDirectoryCache = {}
|
|
283
295
|
const findNSSDBFiles = async ({ logger, NSSDBDirectoryUrl }) => {
|
|
296
|
+
NSSDBDirectoryUrl = String(NSSDBDirectoryUrl)
|
|
284
297
|
const resultFromCache = NSSDirectoryCache[NSSDBDirectoryUrl]
|
|
285
298
|
if (resultFromCache) {
|
|
286
299
|
return resultFromCache
|
package/src/main.js
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* This file is the first file executed by code using the package
|
|
3
3
|
* Its responsability is to export what is documented
|
|
4
4
|
* Ideally this file should be kept simple to help discovering codebase progressively.
|
|
5
|
+
*
|
|
6
|
+
* see also
|
|
7
|
+
* - https://github.com/davewasmer/devcert
|
|
8
|
+
* - https://github.com/FiloSottile/mkcert
|
|
5
9
|
*/
|
|
6
10
|
|
|
7
11
|
export {
|